Panther Search Documentation Tutorials Devlogs Downloads Source Code

Documentation > Panther Documentation > Functions

Functions

Panther
Documentation


  Functions are a set of statements that are executable. They can take a number of inputs (known as parameters), and outputs (known as return/error parameters). By default, functions are able to run at compile-time (known as constexpr).

Syntax

1: func {IDENTIFIER|OPERATOR} = {TEMPLATE_PARAMETER_PACK?} ( {PARAMETERS*} ) {ATTRIBUTES*} -> {TYPE} { {STATEMENTS*} }
2: func {IDENTIFIER|OPERATOR} = {TEMPLATE_PARAMETER_PACK?} ( {PARAMETERS*} ) {ATTRIBUTES*} -> ( {RETURN_PARAMETERS+} ) { {STATEMENTS*} }
3: func {IDENTIFIER|OPERATOR} = {TEMPLATE_PARAMETER_PACK?} ( {PARAMETERS*} ) {ATTRIBUTES*} -> {TYPE} < {TYPE} > { {STATEMENTS*} }
4: func {IDENTIFIER|OPERATOR} = {TEMPLATE_PARAMETER_PACK?} ( {PARAMETERS*} ) {ATTRIBUTES*} -> ( {RETURN_PARAMETERS+} ) < {ERROR_PARAMETERS*} > { {STATEMENTS*} }

  Syntaxes 1, and 3 create a function that has a single return value. A return type of Void means that the function doesn't return anything. Syntaxes 2 and 4 have explicit return parameters, which allows returning of multiple values. Syntaxes 3 and 4 are for functions that may error.

  The list of parameters, return parameters, and error parameters are delimited by a comma (,). A comma may also go at the end of a parameter even if there is no following parameter(s).

  To return a value from a function, the return statement is used. Likewise, to error a function, the error statement is used (although this may only happen if the declaration defines that the function errors).

  Function overloading is allowed. This means that two functions may have the same name if they have a different set of template parameters and parameters.

Function Parameters

Syntax

1: {IDENTIFIER}: {TYPE} {ATTRIBUTES*}
2: {IDENTIFIER}: {TYPE} {read|mut|in} {ATTRIBUTES*}
3: this
4: this {read|mut}

  Parameters are references values. The value the parameter references may not be changed.

  All parameters have a qualifier. If a parameter does not have an explicit qualifier (syntaxes 1 and 3), then they are defaulted to the read qualifier.

Read Parameter Qualifier

  The read parameter qualifier means that the parameter is read-only. They have a value category of concrete-const. If the parameter type trivially-sized, trivially-copyable, and trivially-destroyable, the ABI guarantees that the parameter passing will be by copy (instead of by pointer).

Mut Parameter Qualifier

  The mut parameter qualifier means that the parameter is mutable. If the parameter is not a this parameter, it can only accept concrete values. They have a value category of concrete-mutable.

In Parameter Qualifier

  The in parameter qualifier means that the parameter is mutable. They can only accept ephemeral values. They have a value category of concrete-forwardable.

ABI note:

  In general, in parameters is passed by pointer. This means that if the argument given is a copy or a move, the copy or move is not actually done at the call-site, rather it is done at a operator forward assignment. This allows for what is known as perfect forwarding - a pointer can be passed through from function to function through operator forward and the copy or move operation is only made once actually necessary. If the value is trivially-copyable or trivially-moveable for a copy or move respectively, and it is trivially-sized, the copy or move is made at the site of any forward.

Explicit Function Return/Error Parameters

Syntax

1: {IDENTIFIER}: {TYPE}

  Explicit return/error parameters are pointers to the target, which means that using them guarantees Return-Value-Optimization (RVO).

  If a function explicit return parameters, a return statement in that function must be "return...;". Likewise, if a function has explicit error parameters, an error statement in that function must be "error...;". The "..." is a separate token which means there may be white-space in-between it and the respective keyword, although this goes against the Panther style guide.

  Explicit return/error parameters begin as uninitialized. If the function returns, all return parameters must be initialized, and all initialized error parameters will automatically have their operator delete called on them. This works similarly for if the function errors.

Erroring Functions

  If a function errors, it must be called through a try expression or statement.

ABI note:

  Erroring functions signal if the error or not through returning boolean value. If the function has a single return value, that value becomes an "out" parameter. The error return values themselves are in a packed struct stored right on the stack. This allows for a single pointer to be passed to the function as a parameter in the ABI for all the error values needed so as to lower the performance affect on the normal return path as much as possible.

Function Templates

  (TODO)

Operator Overloading

  (TODO)

Example

Panther
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
def std = @import("std"); // Create a function called "sum" which adds together "lhs" and "rhs" and returns that sum func sum = (lhs: Int, rhs: Int) -> Int { return lhs + rhs; } // Running sum at compile-time def SUM_OF_1_AND_2: Int = sum(1, 2); // Create a function called "divide" that divides "lhs" and "rhs" and returns that result // If an error occurs, print out a message. This function must be runtime (#rt) as std.println is runtime // If "rhs" is 0, error with no error return value func divide = (lhs: Int, rhs: Int) #rt -> Int <Void> { if(rhs == 0){ std.println("Cannot divide by 0"); error; } return lhs / rhs; } // Call the divide function // Use an explicit return parameter for the return func divide_handled = (lhs: Int, rhs: Int) #rt -> (output: Int) { output = try divide(lhs, rhs) else 0; return...; } // template version of the "sum" function func sum = <{T: Type}> (lhs: T, rhs: T) -> T { return lhs + rhs; }