I previously asked Can I mimic multiple passed-object dummy arguments in Fortran?
I over-simplified my problem for that question, and a better example of the code I would like to write is
module m_Parent
type, abstract :: Parent
contains
procedure(f_Parent), deferred :: f
end type
abstract interface
subroutine f_Parent(foo,bar)
import Parent
implicit none
class(Parent), intent(in) :: foo
class(Parent), intent(in) :: bar
end subroutine
end interface
end module
module m_Child
use m_Parent
type, extends(Parent) :: Child
contains
procedure, public :: f => f_Child
end type
contains
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Child), intent(in) :: bar
end subroutine
end module
with the constraint that m_Parent may not have dependencies on m_Child, to avoid circular dependencies and to allow for many Child classes without having to update m_Parent with the details of each.
As before:
the code presented here is forbidden by the Fortran standard.
the select type construct is too slow.
Can I mimic the behaviour that the above code would produce if multiple passed-object dummy arguments were allowed by the Fortran standard?
The standard forbids multiple passed-object dummy arguments, along with passed-object dummy arguments which are arrays or pointers. The standard does not forbid passed-object dummy arguments which are classes containing arrays or pointers.
This can be implemented as
module m_Parent
type, abstract :: Parent
end type
type, abstract :: ParentPair
contains
procedure(f_ParentPair), deferred :: f
end type
abstract interface
subroutine f_ParentPair(foobar)
import ParentPair
implicit none
class(ParentPair), intent(in) :: foobar
end subroutine
end interface
end module
module m_Child
use m_Parent
type, extends(Parent) :: Child
contains
procedure, public :: f => f_Child
end type
type, extends(ParentPair) :: ChildPair
type(Child) :: foo
type(Child) :: bar
contains
procedure, public :: f => f_ChildPair
end type
contains
subroutine f_ChildPair(foobar)
implicit none
class(ChildPair), intent(in) :: foobar
call foobar%foo%f(foobar%bar)
end subroutine
subroutine f_Child(foo,bar)
implicit none
class(Child), intent(in) :: foo
class(Child), intent(in) :: bar
end subroutine
end module
This is not the most elegant solution, and it requires the creation and maintenance of an entire ChildPair class for every implementation of Child.
According to operf, in ifort 19.1 this has a negligible overhead compared to a select type statement.
Related
I have a library with fortran functions that is compiled in single and double precision, but I cannot alter anything in the source code of this library. Ideally, I would define the external function as
template<typename TF> extern "C" void fortran_function(TF*)
And call the function (with both calls in the same scope) as
double a[3] = { 2, 3, 4 };
fortran_function<double>(a);
float b[3] = { 2, 3, 4 };
fortran_function<float>(b);
However, this is not allowed. How do I solve this problem in an elegant way?
There is a very strong problems with this requirement. C++ does allow overloading for native C++ functions, but not for "C"language linkages. Linkage specifications [dcl.link] ยง6 says:
At most one function with a particular name can have C language linkage.
And your templating attempt is equivalent to declaring explicitely:
extern "C" void fortran_function(double *);
extern "C" void fortran_function(float *);
This would declare 2 different function with C language linkage and the same name => explicitely forbidden by C++ standard.
The rationale behind that is that common implementation use name mangling to build a function identifier containing the argument types for the linker to be able to identify them. The C language linkage precisely avoid that name mangling to allow interfacing with C language functions. That immediately defeats any overloading possibility.
Anyway, you will not be able to define 2 C or Fortran functions with the same name and using different parameters. The best I can imagine is to do manual mangling:
extern "C" void fortran_function_double(double *);
extern "C" void fortran_function_float(float *);
Maybe you could use macros to ease multiple declarations, but I am really not proficient enough in macro meta-programming...
You may have to use the C preprocessor to perform name mangling on the C++ side, but on the Fortran end there is no need to use non-Fortran tools to achieve the necessary mangling. Consider
! mangle.i90
subroutine mangle(x) bind(C,name='fortran_function_'// &
trim(merge('float ','double',mykind==C_FLOAT)))
real(mykind) x(3)
x([2,3,1]) = x
end subroutine mangle
and
! mangle.f90
module floatmod
use ISO_C_BINDING
implicit none
integer, parameter :: mykind = C_FLOAT
contains
include 'mangle.i90'
end module floatmod
module doublemod
use ISO_C_BINDING
implicit none
integer, parameter :: mykind = C_DOUBLE
contains
include 'mangle.i90'
end module doublemod
When compiled via gfortran -c mangle.f90 you get a mangle.o file with subroutines fortran_function_float and fortran_function_double.
Can I specialize a type in a signature using types before that type and in the signature? Here is an example:
signature A = sig
type t
type s
end
Can I specialize A by the following?
signature B = A where type s = t list
Both SML/NJ and Mlton complain that t is unbound.
No, that indeed cannot be done directly. The reasons are rather technical, it is not easy to ascribe a well-behaved semantics to such an operation in the general case.
The closest you can get is by introducing another auxiliary type:
signature B =
sig
type t'
include A with type t = t' with type s = t' list
end
This is about type definition in OCaml, I find the following syntax puzzling:
type 'a t
What does it mean in plain English?
Since OP has an experience in C++ language, I think the following explanation might be useful. A type declaration of the form:
type 'a t
is close to the C++
template <typename a> class t;
For example, 'a list is a generic list, and 'a is a type of an element. For concise, we use a single ', instead of template <typename _> construct. In the OCaml parlance, we use term "parametric polymorphism", instead of "generic programming". And instead of a word template, we say a type constructor. The latter has an interesting consequence. Like in C++ a template instantiation creates a new instances of types, in OCaml concertizing a type variable of a polymorphic type creates a new type, e.g., int list, float list (c.f., list<int>, float<list>). So, one can view type constructor 'a list as an unary function on a type level, it accepts a type, and creates a type. It is possible to have nary type constructors, e.g., type ('key, 'value) hashtbl is a binary type constructor, that creates a type for a given key and value pair. Moreover, we can see a non parametric types as a nullary type constructors, so int constructs the type int.
P.S. F# language, a descendant of OCaml, allows to write in both forms: int t and t<int>
P.P.S. To prevent a possible confusion, I would like to state, that although templates and parametric types are trying to solve the same problems, they still have a few differences. Templates are typed after the instantiation, parametric types before. So parametric type 'a t is defined for all 'a. If you want to create a type where a type variable is not universally quantified, you can use another mechanism - functors. They are also very close to templates, but they accept a type plus type requirements, a concept in C++ parlance. The concepts are reified in module types in OCaml, and thus a functor is actually a function on a module level, as it accepts a module and produces a module.
This a parametric type declaration.
A type declaration allows you to declare a new datatype:
type my_type = int * string
let x : my_type = (42,"Sorry for the inconvenience")
Sometimes however, you want a type to be parametric, meaning it takes another type as argument:
type 'a container = 'a * string * 'a
let x : int container = (0, "hello", 1)
let y : string container = ("stack", "over", "flow")
Now in that case, there is no equal after your type declaration. The meaning of that depends whether if it is in a module's structure (like, on top of a .ml file) or in a signature (e.g. in a .mli)
If it is in a structure, it declares a type with no value inside. Which is as useful as an empty set (sometimes it is, but not much). However, if it is in a signature, it means "there exists a parametric definition somewhere, but it is not visible from here".
Suppose there are those two files a.ml and a.mli:
(* a.ml *)
type 'a t = Nil | Cons of 'a * 'a t
let empty = Nil
let add x l = Cons (x,l)
(* and so on... *)
(* a.mli *)
type 'a t
val empty : 'a t
val add : 'a -> 'a t -> 'at
(* and so on... *)
If in the rest of your program you want to manipulate the A.t type, you'll be able to do so only through the empty and add and other defined functions, but not through directly using Nil and Cons.
I'm a bit confused by the fact that (apparently) functor's signature in OCaml can be defined in two (seemingly) completely different ways. E.g. in the .mli file I can write:
module type A = sig
type a
end
module type SigA = sig
type t
end
module Make (MA : SigA) :
A with type a := MA.t
module type Make2 = functor (MA : SigA) -> A with type a := MA.t
As far as I understand, in the example above Make and Make2 are entirely identical signature, yet the syntax looks quite radically different.
Am I missing something? Is there any difference?
So is there a reason for two separate syntactic constructs? Historical reasons? IMO it is a bad practice to have two separate syntactic constructs serving the same purpose.
This is syntactic sugar, similar to that for functions (ie, let f x y = ... is shorthand for let f = fun x -> fun y -> ...). The motivation is presumably that in the long form multiple argument functors become quite hard to read:
module type A = sig end
module type B = sig end
module type C = sig end
module Foo (A:A) (B:B) (C:C) = struct
end
module Foo2 = functor (A:A) -> functor (B:B) -> functor (C:C) -> struct
end
I'm trying to accomplish the following:
module type S = sig
type 'a t
end
module A = struct
type 'a t = 'a list
end
module B = struct
type ('a,'b) t = ('a * 'b) list
end
module Make (P : S) = struct
type 'a t = 'a P.t
end
module Single = struct
include Make (A)
end
module Tuple = struct
include Make (B)
end
Basically, I want to reuse the make functor, except for in Tuple, force the type to be a tuple. Is this possible?
I think the module type S is messing it up, which is giving me the error: They have different arities. Maybe it is possible to get this working using first class modules?
Thanks!
What are you trying to accomplish? If you forget about functors for a second you will see that your module B cannot satisfy the signature S. For example:
module B1 = (B : S)
Will give you the same error. The problem here is that your type t in your singature S only accepts 1 type variable. You cannot apply this signature to a module with type t with 2 type variables.