I/O
"Summon" functions
In most programming languages, all functions can do I/O.
(Meaning, nothing about the function signature tells you whether it does I/O.)
In crow, ordinary functions can't initiate I/O.
Functions that do so must be marked summon
.
print
is a summon
function.
It can only be directly called by another summon
function,
which is why we marked main
.
A function not marked summon
can still call lambdas
which do come from a summon
function.
In the above example, times
is an ordinary function.
Yet, running it causes I/O to happen due to calling f
.
Still, times
is considered ordinary because its I/O
is fully controlled by its caller.
It's called summon
because
it allows a function to "summon" new I/O capabilities ex nihilo,
as opposed to receiving them as lambdas through parameters.
If an ordinary function can't reach any lambdas through its parameters,
it can't perform any I/O (except log
).
Interfaces
Crow has no "interface" keyword, but it does have a pattern that accomplishes that.
In case passing a separate lambda for each possible I/O action is excessive,
they can be joined together in a record.
In the above example, connection
is the "interface":
a record full of far
lambdas.
It allows use-connection
to be written without
summon
.
Ideally, a small amount of code should be summon
and the rest should use interfaces.
Observe that in this example we're using a map to fake most of the I/O.
Since normal functions can only do I/O through their parameters,
you can make them into pure functions by passing parameters that do nothing (or fake I/O).
This is useful for tests.
Overriding 'log'
Logging is always allowed, but you can temporarily change the log handler when calling a function.
Currently this can only be done for native code, as JS logging always uses the JS console.
For details, see log.