Like many other subsystems in Monte, guards can be made from any ordinary object which implements the correct methods.
The main method for a guard is
coerce/2, which takes an object to examine,
called the specimen, and an ejector. If the specimen conforms to the
guard, then the guard returns the conformed value; otherwise, the ejector is
used to abort the computation.
object Any: to coerce(specimen, _): return specimen object Void: to coerce(_, _): return null
Here are two example guards,
Any passes all
specimens through as-is, and
Void ignores the specimen entirely, always
Here’s an actual test. The
Empty guard checks its specimen, which is a
container, for emptiness and ejects on failure:
object Empty: to coerce(specimen, ej): if (specimen.size() != 0): throw.eject(ej, `$specimen was not empty`)
The ejector does not need to have a meaningful object (nor even a string) as its payload, but the payload may be used for diagnostic purposes by the runtime. For example, a debugger might display them to a developer, or a debugging feature of the runtime might record them to a log.
Informally, an unretractable guard cannot be fooled by impostor objects that only pretend to be guarded, and it also will not change its mind about an object on two different coercions.
Formally, an unretractable guard Un is a guard such that for all Monte objects o, if o is successfully coerced by Un, then it will always be successfully coerced by Un, regardless of the internal state of Un or o.