Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Derived Type

Blane_J_
New Contributor I
1,116 Views

Hi to all. Is there any approach to define a derived type parameter whose components are decorated with PRIVATE attribute ? Like:

module test
    implicit none

    type :: my
        private
        integer :: a
    contains
        ...........some type-bound procedures.......
    end type my

    type(my), parameter :: const_my = my(a=100)      !!! This is wrong here !!!

end module test

If not, any suggestions that I could accomplish things like this, Thanks for reply.

0 Kudos
21 Replies
Arjen_Markus
Honored Contributor I
986 Views

If there is nothing in the contains section (or there is no contains section at all), the compiler does not complain. Can you show us the error messages?

0 Kudos
jimdempseyatthecove
Honored Contributor III
986 Views

So you want a parameter with procedures... that could potentially modify the parameter?

Jim Dempsey

0 Kudos
Blane_J_
New Contributor I
986 Views

Arjen Markus wrote:

If there is nothing in the contains section (or there is no contains section at all), the compiler does not complain. Can you show us the error messages?

It seems that I have made a little mistake here. when the error occurs, the defination of the parameter is within the program scope but not the module scope, and it generates the error of "error #6053: Structure constructor may not have fields with the PRIVATE attribute".

0 Kudos
Blane_J_
New Contributor I
986 Views

jimdempseyatthecove wrote:

So you want a parameter with procedures... that could potentially modify the parameter?

Jim Dempsey

It's not like that, Jim. What I mean to do is to accomplish things just like a C# class constant.

0 Kudos
Steven_L_Intel1
Employee
986 Views

You can't have a structure constructor that has values associated with components that aren't accessible. The whole point of private components is that, outside of the definition scope, those components are not visible.

0 Kudos
FortranFan
Honored Contributor II
986 Views

Blane J. wrote:

.. What I mean to do is to accomplish things just like a C# class constant.

I presume the interest is in a feature like so:

class Greeter
{
   ..
   const string Greeting = "Hello World!"
   ..
}

If that's the case, then it is not supported as such by Fortran.

What is your use case?  If you can explain it here, perhaps someone might be able to offer workarounds you have not thought of and which you might like.  You may also have your friends at Intel contemplate such a capability in a future Fortran standard revision.

 

0 Kudos
Blane_J_
New Contributor I
986 Views

Steve Lionel (Intel) wrote:

You can't have a structure constructor that has values associated with components that aren't accessible. The whole point of private components is that, outside of the definition scope, those components are not visible.

Thanks, Steve. So here at the moment the whole module is the defination scope.

0 Kudos
Blane_J_
New Contributor I
986 Views

FortranFan wrote:

What is your use case?  If you can explain it here, perhaps someone might be able to offer workarounds you have not thought of and which you might like.  You may also have your friends at Intel contemplate such a capability in a future Fortran standard revision.

 

What I exactly want is to define a derived type parameter and the derived type have all private components. Such as:

type :: Time
    private
    integer(8) :: ticks
contains
    ! Some procedures to process the calculation.
end type Time

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

Accroding to what we discuessed above, the parameter defination should be within the module scope, and any scope else will return an comiple time, Thanks FortranFan.

0 Kudos
Steven_L_Intel1
Employee
986 Views

This works fine as long as the reference to the private component is in the module. If the type is made available by use association, you can't reference the private component.

The following compiles without errors:

module timemod

type :: Time
    private
    integer(8) :: ticks
!contains
    ! Some procedures to process the calculation.
end type Time

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

end module timemod
program foo
use timemod

type(time) :: t
t = MaxValue
end

 

0 Kudos
Blane_J_
New Contributor I
986 Views

Steve Lionel (Intel) wrote:

This works fine as long as the reference to the private component is in the module. If the type is made available by use association, you can't reference the private component.

The following compiles without errors:

module timemod

type :: Time
    private
    integer(8) :: ticks
!contains
    ! Some procedures to process the calculation.
end type Time

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

end module timemod
program foo
use timemod

type(time) :: t
t = MaxValue
end

 

And till now I had the clear view on it. Thanks Steve.

0 Kudos
jimdempseyatthecove
Honored Contributor III
986 Views

Steve,

In your example, where MaxValue is declared as parameter, are type contained procedures still callable? And if so, what about a contained procedure that modifies ticks?

IOW while

MaxValue = newValue

will be prohibited by the compiler, how about:

result = MaxValue%AddToTicksFunction(deltaTicks)

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
986 Views

Perfectly fine to call a type-bound procedure that is accessible, no matter what it does. Private accessibility means that you can't touch that component directly. You can always call into a module procedure to do whatever it wants. Basically, any context where you could name the component, even where the name is optional, is not permitted.

0 Kudos
jimdempseyatthecove
Honored Contributor III
986 Views

That is not what I asked. Let me rephrase the question. The example given had:

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

Where parameter implies to the compiler that the value is a compile time constant (literal). In the code section

MaxValue = newValue

will be prohibited by the compiler, how about:

result = MaxValue%AddToTicksFunction(deltaTicks)

Then to complete the question, because MaxValue was declared to the compiler as parameter, then what is the value of

result = MaxValue%getTicks()

when issued after the result = MaxValue%AddToTicksFunction(deltaTicks)?

Is it the compile time parameter value, or the runtime resultant value?

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
986 Views

result = MaxValue%AddToTicksFunction(deltaTicks) is fine. The ticks component is not referenced.

result = MaxValue%getTicks() is also legal - and in fact a reasonable way of doing information hiding with get/set procedures.

Don't get hung up on MaxValue being a PARAMETER - in these contexts it is simply a way to reference the derived type, though it will become the "passed object" dummy argument.

0 Kudos
IanH
Honored Contributor II
986 Views

jimdempseyatthecove wrote:

That is not what I asked. Let me rephrase the question. The example given had:

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

Where parameter implies to the compiler that the value is a compile time constant (literal). In the code section

MaxValue = newValue

will be prohibited by the compiler, how about:

result = MaxValue%AddToTicksFunction(deltaTicks)

Then to complete the question, because MaxValue was declared to the compiler as parameter, then what is the value of

result = MaxValue%getTicks()

when issued after the result = MaxValue%AddToTicksFunction(deltaTicks)?

Is it the compile time parameter value, or the runtime resultant value?

Jim Dempsey

It hasn't been specified whether the function referenced by the AddToTicksFunction binding modifies the passed argument.  If it doesn't modify the argument (say the dummy argument corresponding to the passed argument is INTENT(IN)) then the call with a named constant as an actual argument corresponding to the passed argument is fine.  If it does modify the passed argument then a call with a named constant as the actual argument corresponding to the passed argument is not - if the relevant dummy argument corresponding to the passed argument is INTENT(xxOUT) then the compiler should complain.

It is the same situation as passing the literal constant `1` as an actual argument to a function.  If the function doesn't modify the associated dummy argument, all good.  If it does modify it, the universe ends, and the compiler might also complain about it.

(Adding something to a "maximum value" will probably have other issues.)

0 Kudos
jimdempseyatthecove
Honored Contributor III
986 Views

Ian, Steve,

I though my choice of name of function was self explanatory.

MaxValue%AddToTicksFunction(deltaTicks)

Adds the (to be) dummy argument deltaTicks to the type embodied (and hidden) variable ticks, same as would a setTicks setter function. In this case the (hidden/protected) ticks is modified at runtime. PARAMETERS are (IMHO), well, parameters: immutable compile time "constants". Therefor, the compiler could conceivably use the compile time value of the parameter in lieu of the runtime value of a "variable".

IVF Documentation>>An entity with the PARAMETER attribute must not be a variable, a coarray, or a procedure.

Jim Dempsey

0 Kudos
Steven_L_Intel1
Employee
986 Views

I was commenting only on the legality of the reference, not what such a procedure might do. Ian took that up. Yes, a PARAMETER is not writable, so if the procedure tried updating the passed-object dummy it would fail. That has nothing to do with private components.

As for the restriction you mention, the PARAMETER is not a variable or a procedure. It is a named constant of a derived type that has type-bound procedures associated with it. Nothing wrong with that.

0 Kudos
IanH
Honored Contributor II
986 Views

jimdempseyatthecove wrote:

I though my choice of name of function was self explanatory.

MaxValue%AddToTicksFunction(deltaTicks)

Adds the (to be) dummy argument deltaTicks to the type embodied (and hidden) variable ticks, same as would a setTicks setter function. In this case the (hidden/protected) ticks is modified at runtime.

This is perhaps more a question of style, but I don't write functions with dummy arguments that do not have the INTENT(IN) or VALUE attribute [unless I am interfacing with something that otherwise requires it (WinMain, C api's)].  The equivalent of `setTicks` is always a subroutine, if the add operation was going to mutate its argument, it would also be a subroutine.  I know of many others that follow a similar style.  The motivation for this style is the specific semantics of function references and the restrictions on statements more generally that are set out in the standard. 

Consequently, when I saw AddToTicksFunction, as a function reference, my initial assumption was that you were not modifying the actual argument.

~~~

Overloaded structure constructors (a generic function that has the same name as the type) can be useful in situations where you have private components.

MODULE m
  IMPLICIT NONE
  
  ! Just so things don't get accidentally exposed.
  PRIVATE
  
  TYPE, PUBLIC :: t
    INTEGER, PRIVATE :: component
  CONTAINS
    PROCEDURE :: set
    PROCEDURE :: get
    PROCEDURE :: add
  END TYPE t
  
  ! Programmers can overload or hide the compiler provided structure 
  ! constructor.  This can be useful when you have private components.
  INTERFACE t
    MODULE PROCEDURE t_constructor
  END INTERFACE t
  
  TYPE(t), PARAMETER, PUBLIC :: apple = t(1)
CONTAINS
  SUBROUTINE set(object, value)
    CLASS(t), INTENT(INOUT) :: object
    INTEGER, INTENT(IN) :: value
    
    object%component = value
  END SUBROUTINE set
  
  FUNCTION get(object)
    CLASS(t), INTENT(IN) :: object
    INTEGER :: get
    
    get = object%component
  END FUNCTION get
  
  FUNCTION add(left_hand_side, right_hand_side)
    CLASS(t), INTENT(IN) :: left_hand_side
    INTEGER, INTENT(IN) :: right_hand_side
    TYPE(t) :: add
    
    add = t(left_hand_side%component + right_hand_side)
  END FUNCTION add
  
  ! Two arguments, just to make it distinguishable from the structure 
  ! constructor.
  !
  ! If this had the exact same signature as the structure constructor, 
  ! then it would effectively hide the structure constructor.  For the 
  ! sake of the example I don't want to do this.
  FUNCTION t_constructor(a, b)
    INTEGER, INTENT(IN) :: a
    INTEGER, INTENT(IN) :: b
    TYPE(t) :: t_constructor
    
    t_constructor%component = a + b
  END FUNCTION t_constructor
END MODULE m

PROGRAM p
  USE m
  IMPLICIT NONE
  
  ! Cannot do this - the t in the initializer resolves to the 
  ! structure constructor, and the relevant component is private.
  !
  ! (ifort's error is a bit misleading.)
!  TYPE(t), PARAMETER :: a = t(2)
  
  ! Cannot do this - the t in the initializer resolves to the 
  ! overload of the structure constructor, and that isn't 
  ! valid in a constant expression.
!  TYPE(t), PARAMETER :: b = t(3, 4)
  
  ! Can do this - the value of the named constant in this scope 
  ! is the value of the named constant from the module.
  TYPE(t), PARAMETER :: named_constant = apple
  
  TYPE(t) :: variable
  
  ! Can do this - the t in the expression resolves to the 
  ! overloaded structure constructor.
  variable = t(5, 6)
  
  ! Can not do this - trying to change a named constant.
!  CALL named_constant%set(7)
  
  ! Can do this.
  CALL variable%set(8)
  
  ! Can do this - the add function does not change its argument, 
  ! and the left hand side of the assignment is a variable.
  variable = named_constant%add(9)
  
  ! Likewise, both of these are fine.
  PRINT *, named_constant%get(), variable%get()
END PROGRAM p

 

0 Kudos
jimdempseyatthecove
Honored Contributor III
986 Views

>>variable = named_constant%add(9)

Not quite what I'd postulated. Consider (untested)

module timemod

type :: Time
    private
    integer(8) :: ticks
contains
    ! add value to ticks and return the result
    procedure :: AddToTicksFunction
end type Time

type(Time), parameter :: MaxValue = Time(HUGE(0_8))

contains
    ! add value to ticks and return the result
    function AddToTicksFunction(this, deltaTicks)
      class(Time), intent(in) :: this
      integer(8), intent(in):: deltaTicks
      integer(8) :: AddToTicksFunction
      this%ticks = this%ticks + deltaTicks
      AddToTicksFunction = this%ticks
    end function AddToTicksFunction
end module timemod
program foo
use timemod

type(time) :: t
t = MaxValue
print *,MaxValue%AddToTicksFunction(-1)
print *,MaxValue%AddToTicksFunction(-1)
end

Note, the code is not modifying the dummy argument. Rather, the object (part of the object called ticks) of which the object (MaxValue) is a parameter, is instructed to be modified. IIF ticks is modifiable, then MaxValue cannot be by definition a PARAMETER. Where was the grammar police when the committee would permit a variable parameter???

Jim Dempsey

0 Kudos
jimdempseyatthecove
Honored Contributor III
841 Views

Oh...

I think I see the error in my interpretation. Presumably the intent(in) would prohibit this%ticks =...

Change class(Time), intent(in) :: this to class(Time), intent(inout) :: this

Presumably, the compiler could (would) catch the inout applied to a parameter(ized) type.

Jim Dempsey

0 Kudos
Reply