Purity
Levels of purity
Every type in crow has a purity. The purpose is to control what can be shared between different contexts that may be running in parallel. The precise details will be explained in Fibers.
There are 3 levels or purity:
data |
Immutable values only. |
shared |
All data , plus values that are mutable in a thread-safe way.
|
mut |
Allows all types, including ordinary mutable values. |
data
is stricter than "read-only";
it only allows values that are guaranteed to never change.
You can't cast mutable data to immutable data, but you can usually call to
.
Declaring purity
Types are assumed data
by default.
If not, they must be marked shared
or
mut
at the declaration.
Benefits of purity
Purity is deep: If a record has a mut
field,
it must be mut
itself.
To put it in reverse, if a record is data
,
then everything it references, and everything they reference, is data
too.
Two other Crow features also enforce kinds of purity:
- Global state is considered unsafe. (It may be used, but code should behave as if there is no global state.)
-
For non-
summon
functions, the ability to do I/O must come from a parameter. This will be explained in I/O.
With these combine, purity creates a "jail" that a (non-summon
)
function can't escape from.
Its parameters are the roots of the graph of all data it can access.
If those parameters are data
, then the entire graph of objects accessible
to that function is data
.
It can't modify any state visible to the outside, or do any I/O.
It's limited to reading data and producing a return value.
The only thing that matters about such a function is its return value.
It can still create mutable objects of its own, but this is fine since they won't affect anything elsewhere.
Even if some parameter is shared
or mut
,
the function can only access whatever state or side effects are exposed through that parameter.