Functions
C3 has both regular functions and member functions. Member functions are functions namespaced using type names, and allows invocations using the dot syntax.
Regular functions
Regular functions are the same as C aside from the keyword fn
, which is followed by the conventional C declaration of <return type> <name>(<parameter list>)
.
Function arguments
C3 allows use of default arguments as well as named arguments. Note that any unnamed arguments must appear before any named arguments.
Named arguments
Named arguments with defaults:
Varargs
There are four types of varargs:
- single typed
- explicitly typed any: pass non-any arguments as references
- implicitly typed any: arguments are implicitly converted to references (use with care)
- untyped C-style
Examples:
For typed varargs, we can pass a slice instead of the individual arguments, by using the splat ...
operator for example:
Splat
- Splat
...
unknown size slice ONLY in a typed vaarg slot.
- Splat
...
any array anywhere
- Splat
...
known size slices anywhere
Named arguments and varargs
Usually, a parameter after varargs would never be assigned to:
However, named arguments can be used to set this value:
Functions and Optional returns
Function return values may be Optionals – denoted by <type>!
indicating that this
function might either return an Optional with a result, or an Optional with an Excuse.
For example this function might return an Excuse of type SomeError
or OtherResult
.
A function call which is passed one or more Optional arguments will only execute if all Optional values contain a result, otherwise the first Excuse found is returned.
This allows us to chain functions:
Methods
Methods look exactly like functions, but are prefixed with the type name and is (usually) invoked using dot syntax:
The target object may be passed by value or by pointer:
Implicit first parameters
Because the type of the first argument is known, it may be left out. To indicate a pointer &
is used.
It is customary to use self
as the name of the first parameter, but it is not required.
Restrictions on methods
- Methods on a struct/union may not have the same name as a member.
- Methods only works on distinct, struct, union and enum types.
- When taking a function pointer of a method, use the full name.
- Using subtypes, overlapping function names will be shadowed.
Contracts
C3’s error handling is not intended to use errors to signal invalid data or to check invariants and post conditions. Instead C3’s approach is to add annotations to the function, that conditionally will be compiled into asserts.
As an example, the following code:
Will in debug builds be compiled into something like this:
The compiler is allowed to use the contracts for optimizations. For example this:
May be optimized to:
In this case the compiler can look at the post condition of result > 0
to determine that testFoo(foo) == 0
must always be false.
Looking closely at this code, we not that nothing guarantees that bar
is not violating the preconditions. In Safe builds this will usually be checked in runtime, but a sufficiently smart compiler will warn about the lack of checks on bar
. Execution of code violating pre and post conditions has unspecified behaviour.
Short function declaration syntax
For very short functions, C3 offers a “short declaration” syntax using =>
:
Lambdas
It’s possible to create anonymous functions using the regular fn
syntax. Anonymous
functions are identical to regular functions and do not capture variables from the
surrounding scope:
Static initializer and finalizers
It is sometimes useful to run code at startup and shutdown. Static initializers and finalizers
are regular functions annotated with @init
and @finalizer
that are run at startup and shutdown respectively:
Note that invoking @finalizer
is a best effort attempt by the OS and may not
be called during abnormal shutdown.
Changing priority of static initializers and finalizers
It is possible to provide an argument to the attributes to set the actual priority. It is recommended that programs use a priority of 1024 or higher. The higher the value, the later it will be called. The lowest priority is 65535.