- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
I understand the following is not legal:
module foo
type :: bar
integer :: a=53
end type
type, extends(bar) :: rab
integer :: a=-33333 !!! Redefine default initialization
end type
end module
I think this would be quite practical. The only workaround is implementing clumsy constructor wrappers...
Any thoughts?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I prefer not to use default initialization; I use constructors instead. And the Fortran 2003 feature of being able to name an interface block the same as the type name gives me options to apply generics on constructors that are sufficient and flexible enough for my needs.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I also tend to use constructors, but in this very particular case, the default constructors suit me perfectly. There are no additional components that I need to initialize by hand, etc. But sure, the initializer (using the interface to use the same name as the type as you said) is the one I had to implement so far...
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
What you propose looks like a duplicate component name declaration. I understand what you want to accomplish, but that's just not how the language tends to work. As you found, it is easy to write your own constructors.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Steve,
But why would it be a problem? As long as the type of the component is identical to the parent one, redefining the default initialization should not break anything.
Along these lines, I have another question. What is the correct way to set inherited private components? Let's suppose I have the following types:
module foo
type, abstract :: Dad
private
integer :: i
end type
type, extends(Dad) :: Son
end type
end module
program main
use foo
type(Son) :: guy
guy=Son(i=3) ! i is private
guy%dad=Dad(i=3) ! Dad cannot be "instantiated", it's abstract
end program
...
What is the correct way to set the component i of something variable? Are getters/accessors the only possibilities?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Extended derived types (i.e., children class) have access to parent members, so you can add a "setter" method to your child class: say you create SUBROUTINE called SetI which takes an argument ValueOfI. Your program can then invoke this as CALL Son%SetI(ValueOfI=3).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Well, this is not 100% true. Dad's private component is accessible if Son is defined in the same module. The following code does not compile:
module foo
implicit none
public :: Dad
private
type, abstract :: Dad
private
integer :: i
end type
end module
module foo2
use foo
implicit none
public :: Son
private
type, extends(Dad) :: Son
contains
procedure :: set_i
end type
interface Son
module procedure :: Son_init
end interface
contains
subroutine set_i(self,i)
class(Son), intent(inout) :: self
integer :: i
self%i=i
end subroutine
function Son_init(i) result(new)
integer, intent(in) :: i
type(Son) :: new
new%i=i
end function
end module
program main
use foo2
implicit none
type(Son) :: guy
guy=Son(i=3)
end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yep, that's one of the limitations of the current Fortran standard, including 2008. So you have to either apply PUBLIC attribute to component i in the ABSTRACT type or include both the parent and child in the same module.
I end up picking one of these options depending on my needs. I usually create a concrete base type off the abstract in the parent module with "getter" and "setter" methods; child modules then extend the concrete type instead of the abstract.
In one case, I ended up with several concrete types (analogy: abstract shape class; concrete bases for 2-D and 3-D; children: triangle, circle, etc. for 2-D and sphere, cylinder, pyramid, etc. for 3-D), abstract and concretes all in one (parent) module, but the children were in their own individual modules.
And yes, this won't satisfy OOP-purists but one is constrained by the language features.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I think the constructor method is definitely the way to go here; a little bit more typing, but the client code can remain unchanged, so you don't have to repeat yourself:
module foo
implicit none
private
public :: bar ,rab
type :: bar
private
integer :: a=53
end type
type, extends(bar) :: rab
end type
interface rab
procedure :: constructor
end interface
contains
function constructor(a) result(res)
integer ,optional ,intent(in) :: a
type(rab) :: res
res%a = -33333
if ( present(a) ) res%a = a
end function
end module
If you want to allow the child and the parent to be contained in separate modules, you could create a type bound setter method for the abstract type (you could even make the input argument optional, and use a default if the input argument is omitted) then call the setter method from the constructor. One downside here, however, is that the setter method will now be publically exposed.
module foo
implicit none
private
public :: bar
type :: bar
private
integer :: a=53
contains
procedure :: a_setter
end type
contains
subroutine a_setter(this,a)
class(bar) ,intent(out) :: this
integer ,optional ,intent(in) :: a
res%a = 53
if ( present(a) ) this%a = a
end subroutine
end module
module oof
use foo
implicit none
private
public :: rab
type, extends(bar) :: rab
end type
interface rab
procedure :: constructor
end interface
contains
function constructor(a) result(res)
integer ,optional ,intent(in) :: a
type(rab) :: res
call res%a_setter(-33333)
if ( present(a) ) call res%a_setter(a)
end function
end module
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Yep, Zaak, this is pretty much exactly the only solution I had figured so far.
Thanks!
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page