Plasma uses resources to manage effects, They provide an annotation on functions that say what the function may do or may observe to have been done, this allows Plasma to be a purely declarative language and still communicate with the outside world. A function declares what resources it may use or observe with a uses or observes keyword and list of resources:

func print_item(i : Item) uses IO { ... }

This function writes an item to standard output. (Of course it’d be better style to specify a specific file stream.) When you call a function that uses or observes a resource you need to add a ! symbol:

print_item!(my_item)

Of course Plasma knows one or more resources are involved, and which ones, the ! simply ensures that anyone reading code gets a heads up to draw their attention to this code, that some state is involved. The Plasma compiler will enforce this.

There are a few rules for using resources:

To call a function that uses a resource, the caller must declare that it also uses the resource.

To call a function that observes a resource, the caller must declare that it uses or observes the resource.

Every resource using or observing call must have a ! after the function name.

No two calls with bangs (!) can be made in the same statement (does not apply to compound statements like if-then-else blocks).

So why separate uses and observes? For parallelisation! It is perfectly safe to run any number of resource-observing or pure computations in parallel, or to run a single resource-using and any number of pure computations in parallel. But not to run two or more resource-using computations, or a single resource-using and any number of resource-observing computations in parallel. So by making observes a separate concept, it’ll be easer to leverage more parallelism from Plasma programs.

And why resources rather than monads or linear types? They’re easier to use and compose (linear types also compose, but monads don’t).