docs/syntax/function-parameters.md
One of the biggest usability innovations of Enso is the set of parameter types that it supports. The combination of named and defaulted parameters with a curried language creates a tool in which it is very clear to express even complex APIs.
<!-- MarkdownTOC levels="2,3" autolink="true" -->Much like most programming languages, functions in Enso can be called with their parameters provided positionally. This is the simple case that everybody is familiar with.
All parameters in Enso are defined with a name. Like all programming languages, this is necessary for that parameter to be used. However, what Enso allows is for users to then call those parameters by name.
(name = value) (or one may
also take advantage of the operator precedence to write name=value).foo and then try to later apply to it
by name, this will fail due to currying of functions.a + b cannot apply arguments by name. However,
when calling the operator as a method (a.+ b), the call-by-name syntax may
indeed be used (a.+ (that = b)).This is a great usability boon as in complex APIs it can often be difficult to remember the order or parameters.
Enso also allows users to define their functions with defaults for the function's parameters. This is very useful for complex APIs as it allows users to experiment and iterate quickly by only providing the parameters that they want to customise.
(name = default_val),
which, as above, accounts for precedence rules.... operator which suspends application of the default
parameters for the purposes of currying.[!WARNING] Not implemented.
There are certain cases where the type information for an parameter may be able
to be inferred by the compiler. This is best explained by example. Consider the
implementation of a read function that reads text and outputs a value of a
particular type.
read : Text -> t -> t
read text this = t.fromText text
You can use this function by explicitly providing the type information in either of the following ways:
val1 = read '5' Int
val2 = Int.read '5'
This, however, is often tedious, especially in contexts where this information
could be inferred by the compiler. We can re-write read as follows:
read : Text -> (t=t) -> t
read text (this=this) = t.fromText text
This allows users both to provide the parameter explicitly or leave it out. In the case where it is not provided, the compiler will attempt to infer it from usage. If this is impossible, an error would be raised.
Enso provides a syntactic sugar for the t=t syntax. The above code can be
written instead using ?.
read : Text -> t? -> t
read text this? = t.fromText text
[!WARNING] Not implemented.
Enso provides users with the ability to define variadic functions, or splats functions in our terminology. These are very useful for defining expressive APIs and flexible code.
name..., where name is an arbitrary
parameter name.The actionables for this section are:
- Work out how (and if) this can interact with currying.
- Do we even want this?
[!WARNING] Not implemented.
There are sometimes cases where the user wants to explicitly refine the type of an parameter at the call site of a function. This can be useful for debugging, and for writing ad-hoc code. Much like the named-parameters in applications above, Enso also provides a syntax for refining types at the application site.
:=
operator (e.g. arg_name := T).T must be a valid
subtype for the type inferred for (or defined for) the function being called.Enso provides the _ parameter as a quick way to create a lambda from a
function call. It obeys the following rules.
_ will create a lambda that accepts an
parameter and passes it in the place of the underscore. All other function
parameters are applied as normal._ parameters, they are desugared left
to right as the parameters would be applied to the function definition,
creating nested lambdas.