- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I played around with OOP and got confused by a mis-leading error message (PSXE 2017u2, x64). Assume the following code:
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type, public :: my_type
!real(rk), private :: x_ ! compile time error occurs here, if implicit type casting is happening in the constructor
!real(rk), private :: y_ !
real(rk) :: x_ ! this works with implicit type casting!!
real(rk) :: y_
!contains
! some procedures
end type my_type
interface my_type
module procedure my_type_constructor
end interface
contains
function my_type_constructor(x,y)
implicit none
!real(rk), intent (in) :: x ! real should be used
!real(rk), intent (in) :: y
integer, intent (in) :: x ! ERROR: this is not intended to be integer, but a coding error
integer, intent (in) :: y !
type(my_type) :: my_type_constructor
my_type_constructor%x_ = x
my_type_constructor%y_ = y
end function my_type_constructor
end module my_mod_type_short
program OO_test_01
use my_mod_type_short
implicit none
! Variables
type(my_type) :: twoD_data
real(rk) :: my_x, my_y
my_x = 5.0_rk
my_y =10.0_rk
twoD_data = my_type(my_x, my_y)
end program OO_test_01
This runs fine, but contains a not intended implicit type casting in the constructor (my_type_constructor), where I accidently used integer instead of real. If I add the private attribute to x_ and y_ (line 09/10 instead of 11/12), I get this error message:
1>------ Build started: Project: OO_test_01, Configuration: Debug x64 ------ 1>Compiling with Intel(R) Visual Fortran Compiler 17.0.2.187 [Intel(R) 64]... 1>my_mod_type_short.f90 1>D:\02_Fortran\99_test\OO_test_01\my_mod_type_short.f90(48): error #6053: Structure constructor may not have fields with the PRIVATE attribute [MY_X] 1>D:\02_Fortran\99_test\OO_test_01\my_mod_type_short.f90(48): error #6053: Structure constructor may not have fields with the PRIVATE attribute [MY_Y] 1>compilation aborted for D:\02_Fortran\99_test\OO_test_01\my_mod_type_short.f90 (code 1) 1> 1>Build log written to "file://D:\02_Fortran\99_test\OO_test_01\x64\Debug\BuildLog.htm" 1>OO_test_01 - 3 error(s), 0 warning(s) ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
This message is not a help here and it took me some time to figure out, what is wrong. Makes the error message sense at all?
Switching in the constructor to real, everything works fine.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Johannes wrote:
.. At the end, the error message I get, if I falsely use integer in the explicit constructor, is misleading, because it not mention the wrong data type, but complains about the private attribute. I assume that in case of non-matching interfaces, the implicit constructor is expected, which not works with private components. One can test this with commenting out the explicit constructor and its interface. With private components of my_type, I get the same error message like if the explicit contains wrong non-mating interface.
Or am I wrong? ..
When a GENERIC INTERFACE with the same name as a derived type is made PUBLIC, a specific procedure that is part of the interface will get invoked if the method signature matches with that employed with the "construction" statement in the caller. If there is no match, the compiler will attempt the default structure constructor approach which can result in errors when PRIVATE components of the derived type are being assigned values.
First try this code:
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type :: my_type
private
real(rk) :: x_
real(rk) :: y_
contains
private
procedure, pass(this), public :: x => get_x
procedure, pass(this), public :: y => get_y
end type my_type
interface my_type
module procedure my_type_constructor
module procedure int_constructor
end interface
public :: my_type
contains
function my_type_constructor( xy ) result( mt )
real(rk), intent (in) :: xy
! Function result
type(my_type) :: mt
print *, "enter my_type_constructor"
mt%x_ = xy
mt%y_ = xy
return
end function my_type_constructor
function int_constructor(x,y) result( mt )
integer, intent (in) :: x
integer, intent (in) :: y
! Function result
type(my_type) :: mt
print *, "enter int_constructor"
mt%x_ = x
mt%y_ = y
return
end function int_constructor
function get_x( this ) result( x )
class(my_type), intent (in) :: this
! Function result
real(rk) :: x
x = this%x_
return
end function get_x
function get_y( this ) result( y )
class(my_type), intent (in) :: this
! Function result
real(rk) :: y
y = this%y_
return
end function get_y
end module my_mod_type_short
program OO_test_01 use my_mod_type_short, only : rk, my_type implicit none ! Variables type(my_type) :: mt1 type(my_type) :: mt2 type(my_type) :: mt3 mt1 = my_type( xy=5.0_rk ) print *, "mt1%x = ", mt1%x() print *, "mt1%y = ", mt1%y() mt2 = my_type( x=5, y=10 ) print *, "mt2%x = ", mt2%x() print *, "mt3%y = ", mt2%y() !mt3 = my_type( 5.0_rk, 10.0_rk ) stop end program OO_test_01
Then try uncommenting the code on line #20 and retry to see what happens.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Seems like the root of your problem is the INTERFACE my_tape is not made public, only the derived type is.
Remove the ", public" attribute on the derived type definition for my_type and then add "public :: my_type" statement following the INTERFACE definition.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi FortranFan,
I've tested your suggestion (removing public from line 8, adding public::mytype in line 22), but I receive now a different error:
error #6404: This name does not have a type, and must have an explicit type. [MYTYPE]
Since the original code works, if the constructor contains the correct data type (real, line 27/28 instead of 29/30). I've a gut feeling, that I do something non-standard conforming or there might be a compiler bug.
What I'm wondering still, how the explicit constructor is found although I defined everything private (line 5) for the case, no error is thrown?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
twoD_data = my_type(my_x, my_y) is standard fortran syntax you do not need a constructor routine for this to work and indeed maybe that is the cause of the problems.....
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi all,
the implicit standard constructor works fine as long the components of my_type are public. I wanted to hide them. If that is the case, I have to provide an explicit constructor as far as I understood. This works fine, if the correct data types (real) are written in the constructor (in debug, I can set a break point in the explicit constructor, where the code pauses, the code below works). At the end, the error message I get, if I falsely use integer in the explicit constructor, is misleading, because it not mention the wrong data type, but complains about the private attribute. I assume that in case of non-matching interfaces, the implicit constructor is expected, which not works with private components. One can test this with commenting out the explicit constructor and its interface. With private components of my_type, I get the same error message like if the explicit contains wrong non-mating interface.
Or am I wrong?
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type, public :: my_type
!type :: my_type
real(rk), private :: x_ !
real(rk), private :: y_ !
!contains
! some procedures
end type my_type
interface my_type
module procedure my_type_constructor
end interface
contains
function my_type_constructor(x,y)
implicit none
real(rk), intent (in) :: x ! real should be used
real(rk), intent (in) :: y
type(my_type) :: my_type_constructor
my_type_constructor%x_ = x
my_type_constructor%y_ = y
end function my_type_constructor
end module my_mod_type_short
program OO_test_01
use my_mod_type_short
implicit none
! Variables
type(my_type) :: twoD_data
real(rk) :: my_x, my_y
my_x = 5.0_rk
my_y =10.0_rk
twoD_data = my_type(my_x, my_y)
end program OO_test_01
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Johannes wrote:
.. I've tested your suggestion (removing public from line 8, adding public::mytype in line 22), but I receive now a different error:
error #6404: This name does not have a type, and must have an explicit type. [MYTYPE]..
It looks like you had a typo this time where you used "MYTYPE" in one place and "MY_TYPE" in another,
Anyways, try this:
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type :: my_type
private
real(rk) :: x_
real(rk) :: y_
contains
private
procedure, pass(this), public :: x => get_x
procedure, pass(this), public :: y => get_y
end type my_type
interface my_type
module procedure my_type_constructor
end interface
public :: my_type
contains
function my_type_constructor(x,y) result( mt )
real(rk), intent (in) :: x
real(rk), intent (in) :: y
! Function result
type(my_type) :: mt
mt%x_ = x
mt%y_ = y
return
end function my_type_constructor
function get_x( this ) result( x )
class(my_type), intent (in) :: this
! Function result
real(rk) :: x
x = this%x_
return
end function get_x
function get_y( this ) result( y )
class(my_type), intent (in) :: this
! Function result
real(rk) :: y
y = this%y_
return
end function get_y
end module my_mod_type_short
program OO_test_01 use my_mod_type_short, only : rk, my_type implicit none ! Variables type(my_type) :: twoD_data twoD_data = my_type( x=5.0_rk, y=10.0_rk ) print *, "twoD_data%x = ", twoD_data%x() print *, "twoD_data%y = ", twoD_data%y() stop end program OO_test_01
You should get no compilation warnings or errors and upon compilation, you should see the following:
twoD_data%x = 5.00000000000000 twoD_data%y = 10.0000000000000
So notice in this revised code the "data" for the class (derived type in Fortran) are PRIVATE, then using the facility introduced in Fortran 2003 that allows a GENERIC INTERFACE (that has PUBLIC attribute) to have the same name as the derived type a "constructor" option is introduced, and "setter" accessor methods (get_x, get_y) are added to the class to dispatch the requested "data" from the class to the caller.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Johannes wrote:
.. At the end, the error message I get, if I falsely use integer in the explicit constructor, is misleading, because it not mention the wrong data type, but complains about the private attribute. I assume that in case of non-matching interfaces, the implicit constructor is expected, which not works with private components. One can test this with commenting out the explicit constructor and its interface. With private components of my_type, I get the same error message like if the explicit contains wrong non-mating interface.
Or am I wrong? ..
When a GENERIC INTERFACE with the same name as a derived type is made PUBLIC, a specific procedure that is part of the interface will get invoked if the method signature matches with that employed with the "construction" statement in the caller. If there is no match, the compiler will attempt the default structure constructor approach which can result in errors when PRIVATE components of the derived type are being assigned values.
First try this code:
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type :: my_type
private
real(rk) :: x_
real(rk) :: y_
contains
private
procedure, pass(this), public :: x => get_x
procedure, pass(this), public :: y => get_y
end type my_type
interface my_type
module procedure my_type_constructor
module procedure int_constructor
end interface
public :: my_type
contains
function my_type_constructor( xy ) result( mt )
real(rk), intent (in) :: xy
! Function result
type(my_type) :: mt
print *, "enter my_type_constructor"
mt%x_ = xy
mt%y_ = xy
return
end function my_type_constructor
function int_constructor(x,y) result( mt )
integer, intent (in) :: x
integer, intent (in) :: y
! Function result
type(my_type) :: mt
print *, "enter int_constructor"
mt%x_ = x
mt%y_ = y
return
end function int_constructor
function get_x( this ) result( x )
class(my_type), intent (in) :: this
! Function result
real(rk) :: x
x = this%x_
return
end function get_x
function get_y( this ) result( y )
class(my_type), intent (in) :: this
! Function result
real(rk) :: y
y = this%y_
return
end function get_y
end module my_mod_type_short
program OO_test_01 use my_mod_type_short, only : rk, my_type implicit none ! Variables type(my_type) :: mt1 type(my_type) :: mt2 type(my_type) :: mt3 mt1 = my_type( xy=5.0_rk ) print *, "mt1%x = ", mt1%x() print *, "mt1%y = ", mt1%y() mt2 = my_type( x=5, y=10 ) print *, "mt2%x = ", mt2%x() print *, "mt3%y = ", mt2%y() !mt3 = my_type( 5.0_rk, 10.0_rk ) stop end program OO_test_01
Then try uncommenting the code on line #20 and retry to see what happens.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi FortranFan,
many thanks for your help! Eureka.
So, if no matching procedure is found in the generic interface, the known error message occurs. It's the same for non OO generic interfaces. The only point, I miss from the user perspective is a meaningful error message, which is different to non OO generic interfaces.
The OO message is:
error #6053: Structure constructor may not have fields with the PRIVATE attribute
The non OO non-matching generic interface is:
error #6284: There is no matching specific function for this generic function reference. [DUMMY]
It would be nice to have a better error message for non-matching generic function references for the OO case, if it is possible. The working solution is shown below.
module my_mod_type_short
use, intrinsic :: ISO_FORTRAN_ENV, only : rk => real64
implicit none
private
public :: rk
type :: my_type
private
real(rk) :: x_
real(rk) :: y_
contains
private
procedure, pass(this), public :: x => get_x
procedure, pass(this), public :: y => get_y
end type my_type
interface my_type
module procedure my_type_constructor
module procedure my_type_constructor_xy
module procedure int_constructor
end interface
public :: my_type
interface dummy
module procedure dummy_int
module procedure dummy_real
end interface dummy
public :: dummy
contains
function my_type_constructor( x, y ) result( mt )
real(rk), intent (in) :: x
real(rk), intent (in) :: y
! Function result
type(my_type) :: mt
print *, "enter my_type_constructor"
mt%x_ = x
mt%y_ = y
return
end function my_type_constructor
function my_type_constructor_xy( xy ) result( mt )
real(rk), intent (in) :: xy
! Function result
type(my_type) :: mt
print *, "enter my_type_constructor_xy"
mt%x_ = xy
mt%y_ = xy
return
end function my_type_constructor_xy
function int_constructor(x,y) result( mt )
integer, intent (in) :: x
integer, intent (in) :: y
! Function result
type(my_type) :: mt
print *, "enter int_constructor"
mt%x_ = x
mt%y_ = y
return
end function int_constructor
function get_x( this ) result( x )
class(my_type), intent (in) :: this
! Function result
real(rk) :: x
x = this%x_
return
end function get_x
function get_y( this ) result( y )
class(my_type), intent (in) :: this
! Function result
real(rk) :: y
y = this%y_
return
end function get_y
function dummy_int ( input )
implicit none
integer, intent(in) :: input
integer :: dummy_int
write(*,'(i8)') input
dummy_int = input * 2
return
end function dummy_int
function dummy_real ( input )
implicit none
real(rk), intent(in) :: input
real(rk) :: dummy_real
write(*,'(f8.2)') input
dummy_real = input * 2.0_rk
return
end function dummy_real
end module my_mod_type_short
program OO_test_01 use my_mod_type_short, only : rk, my_type, dummy implicit none ! Variables type(my_type) :: mt1 type(my_type) :: mt2 type(my_type) :: mt3 integer :: i_value real(rk) :: r_value mt1 = my_type( xy=5.0_rk ) print *, "mt1%x = ", mt1%x() print *, "mt1%y = ", mt1%y() mt2 = my_type( x=5, y=10 ) print *, "mt2%x = ", mt2%x() print *, "mt3%y = ", mt2%y() mt3 = my_type( 5.0_rk, 10.0_rk ) i_value = dummy( input = 1 ) r_value = dummy( input = 1.0_rk ) stop end program OO_test_01
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page