-
Notifications
You must be signed in to change notification settings - Fork 3
Note: Function Pointer Types
There are four types of function pointers in Flect:
- Bare function pointers.
- External function pointers.
- Closure function pointers.
- By-reference function pointers.
Bare function pointers are like plain old C function pointers. They are of the form:
fn(ty1, ... tyN) -> retTy
(As with functions, all function pointers can also have the !
return type, indicating divergence.)
External function pointers are described in Note: External Functions.
Closure function pointers are those that have access to their surrounding lexical environment. They are of the form:
fn@(ty1, ... tyN) -> retTy
By-reference function pointers are basically closure function pointers (the type syntax is the same) but are treated specially by the compiler. For instance:
pub fn transform[T, U](val : T, ref fun : fn@(T) -> U) -> U {
fun(val);
}
The thing to notice here is the ref
. Since ref
allows safe references to on-stack values, it means we can say:
let fourty_two = transform(21, fn@(val) { val * 2; });
Normally, the second argument would result in a GC heap allocation of the closure. In this case, however, the compiler knows that transform
cannot leak the fun
argument in an unsafe way. Thus, it allocates the closure directly on the stack, resulting in an obvious performance gain. This also makes it practical to work with closures in a freestanding environment.
A function pointer type can be implicitly converted to another function pointer type provided that:
- The source function pointer kind is compatible with the target function pointer kind.
- The source and target function pointer types are of the same arity.
- All types in the source parameter list are compatible with those in the target parameter list (in the same position).
- The source return type is compatible with the target return type.
Only one kind conversion is currently allowed: Bare function pointer to closure function pointer.
A source parameter type Tn
is compatible with a target parameter type Un
if either:
-
Tn
andTu
are the same type. -
Tn
is an@
or*
pointer andTu
is an&
pointer (both pointing to the same type). -
Tn
andTu
are structural types, contain pointer types that are implicitly convertible to each other following the previous rule (in the same positions), and all other types are equal.
The same rules are applied to return types except that the *T
to &T
conversion is illegal.
To make this a bit clearer:
let f : fn(int, f32) -> i8 = ...;
let f2 : fn(int, f32) -> i8 = f; // Legal; same types.
let f : fn() -> unit = ...;
let f2 : fn@() -> unit = f; // Legal; creates empty (null) closure environment.
let f : fn@() -> unit = ...;
let f2 : fn() -> unit = f; // Illegal; cannot drop closure environment.
let f : fn(@int) -> unit = ...;
let f2 : fn(&int) -> unit = f; // Legal; @int is convertible to &int.
let f : fn(*int) -> unit = ...;
let f2 : fn(&int) -> unit = f; // Legal; *int is convertible to &int.
let f : fn() -> *int = ...;
let f2 : fn() -> &int = f; // Illegal; cannot null-check return value.
let f : fn((@int, f32), f64) -> uint = ...;
let f2 : fn((&int, f32), f64) -> uint = f; // Legal; (@int, f32) is convertible to (&int, f32).
- Home
- Introduction
- Motivation
- Features
- Tutorial
- Library
- FAQ
- General
- Interoperability
- Syntax
- Type System
- Macros and CTE
- Specification
- Introduction
- Lexical
- Common Grammar Elements
- Modules and Bundles
- Type System
- Declarations
- Expressions
- Macros
- Compile-Time Evaluation
- Memory Management
- Application Binary Interface
- Foreign Function Interface
- Unit Testing
- Documentation Comments
- Style
- Indentation
- Braces
- Spacing
- Naming