Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"parameter" fields in derived types

44 views
Skip to first unread message

m

unread,
Jan 20, 2011, 8:04:56 AM1/20/11
to
Hi,
I would like to define a derived type with a constant field,
ideally something like

type a_t
integer, parameter :: i = 10
! other fields
end type a_t

however I see this is not allowed in this form. Is there a way to
obtain something similar?

Two options I know of - but I'm not very happy with - are

1) simply eliminate the parameter attribute:

type a_t
integer :: i = 10
end type a_t

Problems: 1) the value of i can be changed and 2) if I have a large
array of type a_t the field i can waste memory

2) use a type bound procedure:

type a_t
contains
procedure, nopass :: i => i_p
end type a_t

function i_p() result(i)
integer :: i
i = 10
end function i_p

Problems: 1) can not be used in statements like
type(a_t) :: a
integer :: vec(a%i())
and 2) seems a little unnatural.

Thank you!
Marco

m_b_metcalf

unread,
Jan 20, 2011, 8:36:55 AM1/20/11
to

A simple approach is to declare the type in a module and then to
specify i as private. That affords a lot of protection.

Regards,

Mike Metcalf

m

unread,
Jan 20, 2011, 8:47:57 AM1/20/11
to

Mike, thank you. Do you mean

module m
type a_t
  integer, private :: i = 10
end type a_t
end module m

However, this would actually be too much protection, since then i
would not be visible at all from outside the module. My goal is to
make i available to every scope using the derived type a_t, but
without the possibility of changing it.

Marco


Wolfgang Kilian

unread,
Jan 20, 2011, 8:53:30 AM1/20/11
to

If you want i to be visible but protected, Solution 2) is reasonable,
just a bit clumsy.

The declaration

integer :: vec(a%i())

while invalid in F2003, may actually be valid in F2008. The function
i_p must be declared PURE to be permissible as a specification function.
(Refer to 7.1.11 "Specification expression". I'm not sure whether a
specification function referenced as a type-bound procedure invocation
a%i() is still a specification function. If yes, is it necessary for a
to be constant?)

-- Wolfgang

--
E-mail: firstnameini...@domain.de
Domain: yahoo

m_b_metcalf

unread,
Jan 20, 2011, 9:05:59 AM1/20/11
to
> Marco- Hide quoted text -
>
> - Show quoted text -

Yes, that's what I meant. You didn't specify what you actually wanted
to do, so, yes, that's overprotetion. The only way to access i outside
the module would be by via a little function that returns the value,
rather pointless given your requirement. All rather clumsy.

Regards,

Mike Metcalf

m_b_metcalf

unread,
Jan 20, 2011, 9:35:24 AM1/20/11
to
> Mike Metcalf- Hide quoted text -

>
> - Show quoted text -

P.S. Of course, Fortran 2003 provides the protected attribute which
allows access but no modification.

M.

Ron Shepard

unread,
Jan 20, 2011, 11:30:27 AM1/20/11
to
In article <ih9bto$eco$1...@news.eternal-september.org>,
m <mres...@gmail.com> wrote:

> Hi,
> I would like to define a derived type with a constant field,
> ideally something like
>
> type a_t
> integer, parameter :: i = 10
> ! other fields
> end type a_t
>
> however I see this is not allowed in this form. Is there a way to
> obtain something similar?
>
> Two options I know of - but I'm not very happy with - are
>
> 1) simply eliminate the parameter attribute:
>
> type a_t
> integer :: i = 10
> end type a_t
>
> Problems: 1) the value of i can be changed and 2) if I have a large
> array of type a_t the field i can waste memory

I think this is why parameters are not allowed in derived types in
the first place. An array of that derived type would indeed waste
memory by storing that parameter in every array element. Or
multiple scalar variables of that type would also waste memory for
the same reason.

The workaround that I usually use is to put the list of parameters
outside of the derived type, but to define the parameters and the
derived type in the same module.

module define
integer, parameter :: a_t_i = 10
type a_t
! other fields
x =
y =
end type a_t
end module define

Now, when you USE DEFINE, you get the integer parameters and you
also get the derived type definition to declare you own scalars and
arrays.

There is another similar usage that is also necessary sometimes.
This is an example of when you do want the integer value within the
derived type. You want it to be set once in the program, say from
some input values, and then you want it to remain fixed from then
on. This is what the PROTECTED attribute is for. However, I forget
if this is in f2003 or f2008, but it is not yet supported by all
compilers.

$.02 -Ron Shepard

Richard Maine

unread,
Jan 20, 2011, 11:54:45 AM1/20/11
to
m_b_metcalf <michael...@compuserve.com> wrote:

> On Jan 20, 3:05 pm, m_b_metcalf <michaelmetc...@compuserve.com> wrote:
> > On Jan 20, 2:47 pm, m <mreste...@gmail.com> wrote:
> > > Il Thu, 20 Jan 2011 05:36:55 -0800, m_b_metcalf ha scritto:
> > > > On Jan 20, 2:04 pm, m <mreste...@gmail.com> wrote:
> > > >> I would like to define a derived type with a constant field,

...


> > > >> Two options I know of - but I'm not very happy with - are
> > > >> 1) simply eliminate the parameter attribute:

...


> > > >> Problems: 1) the value of i can be changed and 2) if I have a large
> > > >> array of type a_t the field i can waste memory

I'm slightly confused about the comment on wasting memory. Mostly, that
makes me unsure what you are trying to achieve. If each object of the
type can have a different value for the component, then that value is
going to have to be stored somewhere. If each object of the type can't
have a different value for the component, then I wonder why it needs to
be a component at all; why isn't it just a parameter outside of the
type?

> > > >> 2) use a type bound procedure:

...


> > > >> and 2) seems a little unnatural.

I'd probably agree with that, but I suppose it comes back to
understanding what the objective is.

> P.S. Of course, Fortran 2003 provides the protected attribute which
> allows access but no modification.

but cannot be done for an individual component.

I'll mention one possible approach to the OP's problem, but let me
preface it by saying that I don't actually recommend it. I'm mentioining
it more for what one might call academic purposes than as a
recommendation. This is a notion that occurred to me when f2003 was
being developed.

A derived type LEN parameter in f2003 acts an awful lot like a constant
component. You specify its value in the declaration of the object (or
during object creation if the declaration specifies that the value is
deferred). You can then access the value with a syntax that looks just
like a component reference, but you can't change the value for an
existing object.

I'm not entirely sure whether this will achieve the OP's objectives (as
I am still unsure precisely what those objectives are), but it strikes
me that it has at least a chance.

A major argument against this approach, however, is that parameterized
derived types are clearly among the last of the f2003 features to be
implemented by compilers. You are likely to have a had time finding a
compiler that implements them - much less being sure that any other user
of your code would also have such a compiler.

A related problem is that I'd strongly suspect any implementations you
do find are likely to be pretty buggy. This suspicion is based not on
any particular experience, but rather on the observation that a major
reason compilers don't implement pdts yet is that implementation is
difficult. (Another reason is that customer demand appears to be
relatively low). If they are that difficult to implement, it seems
likely that early implementations will be buggy.

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

m

unread,
Jan 20, 2011, 12:27:33 PM1/20/11
to
Il Thu, 20 Jan 2011 08:54:45 -0800, Richard Maine ha scritto:

> m_b_metcalf <michael...@compuserve.com> wrote:
>
>> On Jan 20, 3:05 pm, m_b_metcalf <michaelmetc...@compuserve.com> wrote:
>> > On Jan 20, 2:47 pm, m <mreste...@gmail.com> wrote:
>> > > Il Thu, 20 Jan 2011 05:36:55 -0800, m_b_metcalf ha scritto:
>> > > > On Jan 20, 2:04 pm, m <mreste...@gmail.com> wrote:
>> > > >> I would like to define a derived type with a constant field,
> ...
>> > > >> Two options I know of - but I'm not very happy with - are 1)
>> > > >> simply eliminate the parameter attribute:
> ...
>> > > >> Problems: 1) the value of i can be changed and 2) if I have a
>> > > >> large array of type a_t the field i can waste memory
>
> I'm slightly confused about the comment on wasting memory. Mostly, that
> makes me unsure what you are trying to achieve. If each object of the
> type can have a different value for the component, then that value is
> going to have to be stored somewhere. If each object of the type can't
> have a different value for the component, then I wonder why it needs to
> be a component at all; why isn't it just a parameter outside of the
> type?

So, my idea was to:
1) have a unique value shared by all the objects of type a_t
2) have that value somehow bundled with the type definition, so that
one doesn't have to use two things and recall they have to be used
together (which is in fact how I tend to think about derived types
in general).

>
>> > > >> 2) use a type bound procedure:
> ...
>> > > >> and 2) seems a little unnatural.
>
> I'd probably agree with that, but I suppose it comes back to
> understanding what the objective is.
>
>> P.S. Of course, Fortran 2003 provides the protected attribute which
>> allows access but no modification.
>
> but cannot be done for an individual component.

Yes. Just out of curiosity, why is it allowed to specify private
and public for individual components, but not protected? To me
they look very similar concepts...

>
> I'll mention one possible approach to the OP's problem, but let me
> preface it by saying that I don't actually recommend it.

[discussion about LEN parameters]

OK, this is one idea, but it provides a shared copy at the array
level, while I was thinking more at the type level (nevertheless,
I find that being able to share a parameter for a whole array
is also a useful thing).

Thank you,
Marco

m

unread,
Jan 20, 2011, 12:29:57 PM1/20/11
to

Wolfgang, Ron, thank you. Nice notice about F2008 possibly allowing the
use of the function in specification expression, since in fact in this
case making the function PURE is not a problem.

Marco

Richard Maine

unread,
Jan 20, 2011, 1:30:11 PM1/20/11
to
m <mres...@gmail.com> wrote:
...

> >> > > >> I would like to define a derived type with a constant field,
...
> So, my idea was to:
> 1) have a unique value shared by all the objects of type a_t
> 2) have that value somehow bundled with the type definition, so that
> one doesn't have to use two things and recall they have to be used
> together (which is in fact how I tend to think about derived types
> in general).

I'd probably go with the approach that Ron mentioned of having the type
and the parameter as separate entities, but in the same module. The
"same module" part provides the link of using them together.

While you might be able to use any of several other approaches, my
personal judgement is that they are all a lot of complication relative
to the desired end. Think not only of writing the code, but also of
someone else reading it and trying to figure out what is going on with
the type-bound procedure, type parameter, or whatever. I'm guessing that
most readers would be confused and think that something deeper must be
going on. Just my personal judgement there; others may differ.

> Yes. Just out of curiosity, why is it allowed to specify private
> and public for individual components, but not protected? To me
> they look very similar concepts...

A perceptive question. It is a bit subtle in that private/public are
more fundamentally different from protected than you are probably
thinking. I'm guessing that you are thinking that private protects you
from both reading and writing, while protected protects you from only
writing, so that private is stronger. But that isn't the whole story. In
some ways protected is stronger.

In particular, the private attribute is fundamentally about the
visibility of the name. Declaring a variable private to a module doesn't
mean that you can't access that variable outside of the module; it just
means that the particular name is not "known" outside of the module.
There might be other ways to access the variable outside of the module;
nothing wrong with them. (An "obvious" other way is to give the variable
the target attribute and point a pointer at it). I like to explain that
in some sense public/private are not really attributes of the object,
but of the object's name.

The protected attribute, in contrast, attaches to the object. It doesn't
matter what roundabout tricks you might use to access the object, it is
illegal to modify the value of a protected object outside of its module.
(There are some cases where a compiler probably can't catch the error,
but it is still illegal).

I'm trying to think about the issue of something that attaches to the
object like that being specified in the type declaration, which applies
to all objects of the type instead of just a particular object. A little
bit of stream-of-consciousness writing here; I haven't though this
through. I guess its probably ok; I'd have to think on it more to be
sure.

So I guess I'm going to waffle and say that I don't know for sure any
reason why it couldn't be done. Might well be for reasons that I haven't
thought through, though.

James Van Buskirk

unread,
Jan 20, 2011, 2:16:30 PM1/20/11
to
"m" <mres...@gmail.com> wrote in message
news:ih9rel$ml2$2...@news.eternal-september.org...

> Wolfgang, Ron, thank you. Nice notice about F2008 possibly allowing the
> use of the function in specification expression, since in fact in this
> case making the function PURE is not a problem.

It seems to me that you are gravitating towards something like:

C:\gfortran\clf\type_param>type type_param.f90
module mytypes
implicit none
private

integer,private,save :: i_priv = 13
type,public :: mytype
integer key
! ...
contains
procedure,NOPASS :: i => get_i_priv
end type mytype
contains
pure function get_i_priv()
integer get_i_priv
get_i_priv = i_priv
end function get_i_priv
end module mytypes

program test
use mytypes
implicit none
type(mytype) a, b

a%key = 7
b%key = 11
write(*,'(2(a,i0))') 'a%key = ',a%key,', a%i() = ',a%i()
write(*,'(2(a,i0))') 'b%key = ',b%key,', b%i() = ',b%i()
end program test

C:\gfortran\clf\type_param>gfortran type_param.f90 -otype_param

C:\gfortran\clf\type_param>type_param
a%key = 7, a%i() = 13
b%key = 11, b%i() = 13

One thing I wanted to add is that allowing PURE functions in
specification expressions goes way back to f95, so you can expect it
to work in any compiler nowadays. Do note that there is a difference
between specification expressions and initialization expressions,
however. Loosely speaking, an initialization expression is what you
need if the program can't be compiled without knowing the value of
the expression in advance, for example the compiler couldn't do much
with

real(kind=nint(sin(x)*17)) y

if it couldn't compute the value of nint(sin(x)*17) during
compilation because it wouldn't know whether to treat y as a
single- or double-precision variable.

Having said that, even f2008 doesn't allow you to write your own
initialization functions, only specification functions.

--
write(*,*) transfer((/17.392111325966148d0,6.5794487871554595D-85, &
6.0134700243160014d-154/),(/'x'/)); end


Wolfgang Kilian

unread,
Jan 21, 2011, 7:49:19 AM1/21/11
to
On 01/20/2011 08:16 PM, James Van Buskirk wrote:
> "m" <mres...@gmail.com> wrote in message
> news:ih9rel$ml2$2...@news.eternal-september.org...
>
>> Wolfgang, Ron, thank you. Nice notice about F2008 possibly allowing the
>> use of the function in specification expression, since in fact in this
>> case making the function PURE is not a problem.
>
> It seems to me that you are gravitating towards something like:
> [...]

> One thing I wanted to add is that allowing PURE functions in
> specification expressions goes way back to f95, so you can expect it
> to work in any compiler nowadays.

I guess you're right, and a possible advice to the OP would be to use
pure type-bound procedures, if the extra typing is worthwhile. The
F2008 standard is just more explicit:

F2003:
A restricted expression is an expression in which each operation is
intrinsic and [...]

F2008:
A restricted expression is an expression in which each operation is
intrinsic or defined by a specifiation function and [...]

Unfortunately, compilers have problems with this. A variant of your
sample code:

module mytypes
implicit none
private

public :: mytype, get_i

integer, save :: i_priv = 13

type :: mytype
integer :: dummy
contains
procedure, nopass :: i => get_i
end type mytype

contains

pure function get_i () result (i)
integer :: i
i = i_priv
end function get_i

end module mytypes


program test
use mytypes
implicit none

type(mytype) :: a
type(mytype), parameter :: a_const = mytype (0)

! integer, dimension (get_i()) :: x ! #1
! integer, dimension (a%i()) :: x ! #2
! integer, dimension (a_const%i()) :: x ! #3

print *, size (x)

end program test


The result depends on whether I activate line #1, #2 or #3.
gfortran-4.6 (fresh build) on 64bit Linux:

#1
> gfortran my_types.f90 -o my_types && ./my_types
13

That's ok...

#2
> fortran my_types.f90 -o my_types && ./my_types
13

So the object need not be constant ...

#3
> gfortran my_types.f90 -o my_types && ./my_typesmy_types.f90:19:0: internal compiler error: in gfc_match_varspec, at fortran/primary.c:1846
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.

That was unexpected.


Try nagfor on 64bit Linux:
#1
> nagfor -f2003 my_types.f90 -o my_types && ./my_types
NAG Fortran Compiler Release 5.2(756)
Warning: my_types.f90, line 37: Unused local variable A
detected at TEST@<end-of-statement>
Error: my_types.f90, line 31: Reference to non-intrinsic function GET_I
in initialisation expression
Errors in declarations, no further processing for TEST
[NAG Fortran Compiler error termination, 1 error, 1 warning]

So NAG thinks this is an initialization expression. Well ...

#2
> nagfor -f2003 my_types.f90 -o my_types && ./my_types
NAG Fortran Compiler Release 5.2(756)
Segmentation violation
Internal error - please report this bug

(...oops again)

#3
> nagfor -f2003 my_types.f90 -o my_types && ./my_types
NAG Fortran Compiler Release 5.2(756)
Warning: my_types.f90, line 37: Unused local variable A
detected at TEST@<end-of-statement>
Error: my_types.f90, line 33: Reference to non-intrinsic function GET_I
in initialisation expression
Errors in declarations, no further processing for TEST
[NAG Fortran Compiler error termination, 1 error, 1 warning]

(same as #1.)


Conclusion: in any case, some bug reports are in order ...

James Van Buskirk

unread,
Jan 21, 2011, 9:34:52 AM1/21/11
to
"Wolfgang Kilian" <see...@domain.invalid> wrote in message
news:ihbvcf$aqb$1...@news.eternal-september.org...

> contains

> end module mytypes

> print *, size (x)

> end program test

> Try nagfor on 64bit Linux:


> #1
>> nagfor -f2003 my_types.f90 -o my_types && ./my_types
> NAG Fortran Compiler Release 5.2(756)
> Warning: my_types.f90, line 37: Unused local variable A
> detected at TEST@<end-of-statement>
> Error: my_types.f90, line 31: Reference to non-intrinsic function GET_I
> in initialisation expression
> Errors in declarations, no further processing for TEST
> [NAG Fortran Compiler error termination, 1 error, 1 warning]

> So NAG thinks this is an initialization expression. Well ...

Amusing that named constants can have member functions that can be
used to access variables... I pretty much ICE on that concept myself.

But this issue came up a while back and I seem to recall coming to
the conclusion that while f95 explicitly calls out automatic data
objects as being forbidden in the specification part of a main
program: ISO/IEC 1539-1:1997(E), section 11.1:

"Constraint: An automatic data object shall not appear in the
specification part of a main program."

and f08 doesn't have this restriction spelled out, nevertheless
one may conclude that the same restriction is still there because
everything in the main program gets the SAVE attribute and
automatic data objects can't have the SAVE attribute. Surely there
is some documentation out there about why this constraint was
dropped, whether it was intended to allow automatic data objects in
a main program after all or if it was simply considered redundant
because other language already told you it was forbidden.

But if you want to dodge that issue, you could rewrite as:

program prog
call test
end program prog

subroutine test
! body of program test
end subroutine test

and see how things go from that point.

Wolfgang Kilian

unread,
Jan 21, 2011, 10:19:43 AM1/21/11
to

Actually, these two compilers don't care whether the returned data is
variable. I get the same results if i_priv is declared as

integer, parameter :: i_priv = 13

> But this issue came up a while back and I seem to recall coming to
> the conclusion that while f95 explicitly calls out automatic data
> objects as being forbidden in the specification part of a main
> program: ISO/IEC 1539-1:1997(E), section 11.1:
>
> "Constraint: An automatic data object shall not appear in the
> specification part of a main program."
>
> and f08 doesn't have this restriction spelled out, nevertheless
> one may conclude that the same restriction is still there because
> everything in the main program gets the SAVE attribute and
> automatic data objects can't have the SAVE attribute. Surely there
> is some documentation out there about why this constraint was
> dropped, whether it was intended to allow automatic data objects in
> a main program after all or if it was simply considered redundant
> because other language already told you it was forbidden.
>
> But if you want to dodge that issue, you could rewrite as:

Thanks for reminding me of the special semantics inside a main program
... so NAG was right to complain, although the error message could have
been more helpful.

> program prog
> call test
> end program prog
>
> subroutine test
> ! body of program test
> end subroutine test
>
> and see how things go from that point.

gfortran: no difference
NAG: accepts #1 and #3 and prints out '13'. #2 still gives an ICE.

m

unread,
Jan 21, 2011, 12:56:54 PM1/21/11
to
Il Thu, 20 Jan 2011 10:30:11 -0800, Richard Maine ha scritto:

> m <mres...@gmail.com> wrote:
> ...
>> >> > > >> I would like to define a derived type with a constant
>> >> > > >> field,
> ...

Interesting!

Marco

0 new messages