Language`*Mutation*
First seen here, implemented by Taliesin Beynon
What do they do?
The only functions I really know about in this bunch are the ?Language`*Mutation*
functions.
This is an interface that allows you to build things that work like CloudExpression
. For example, I can make a CloudExpression
and use AppendTo
on it:
ce = CreateCloudExpression[<||>]
(* ==> CloudExpression[...]*)
AppendTo[ce, 1 -> 2]
(* ==> CloudExpression[...] *)
This is really implemented at the UpValues
level, but for many things the expression itself might be too deep to use via UpValues
, e.g.:
ce[[1]] = 4
(* ==> 4*)
For this they use Language`SetMutationHandler
to handle what would otherwise have been a failed assignment:
obj["uuid"][[1]] = 2
(* > Set::setps: obj[uuid] in the part assignment is not a symbol. *)
(* ==> 2*)
And there are a bunch of symbols these days that use this:
ToExpression[
Names["*`*"]
, StandardForm
, Function[Null, If[Language`HasMutationHandlerQ[#], #, Nothing], HoldFirst]
]
(*{Audio`AudioGraph, AudioStream, CloudExpression, EntityStore,
InitializationValue, PersistentObject, PersistentValue}*)
Language`SetMutationHandler
This is the heart of the interface. We call it like:
Language`SetMutationHandler[type, handler]
which registers a mutation handler for type
. CloudExpression
for instance has the handler CloudExpression`PackageScope`CloudExpressionMutate
.
Here's a concrete example of this in action:
oop`mut~SetAttributes~HoldAllComplete
oop`mut[Set[f_[oop`ob[s_], p___], v_]] := Set[f[s, p], v]
sym = {1, 2};
oop`ob[sym][[1]] = 2
sym
(*Set::setps: oop`ob[sym] in the part assignment is not a symbol.*)
(* ==> 2 *)
(* ==> {1, 2} *)
Language`SetMutationHandler[oop`ob, oop`mut]
oop`ob[sym][[1]] = 2
sym
(* ==> 2 *)
(* ==> {2, 2} *)
Language`HasMutationHandlerQ
Pretty clear from the previous section
Language`HandleMutation
This is how the MutationHandler
system does its dirty work. For example:
Language`HandleMutation[oop`ob[sym][[1]] = 2]
(* Set::noval: Symbol sym in part assignment does not have an immediate value. *)
(* ==> HoldComplete[1] *)
One thing to note, if the Handler
doesn't do anything, the system will keep trying to mutate it until it bottoms out:
Language`SetMutationHandler[oop`ob, oop`mut2]
Language`HandleMutation[oop`ob[sym][[1]] = 2]
(* oop`ob::mutreclim: Too many nested mutations occurred. *)
(* oop`ob::modfl: The modification oop`ob[sym][[1]]=2 could not be performed. *)
(* ==> $Failed *)
Language`MutationFallthrough
Language`MutationFallthrough
seems to tell the system to abort the mutation process and raise the most recent failed result, for instance this total failure:
oop`mut3~SetAttributes~HoldAllComplete
Language`SetMutationHandler[oop`ob, oop`mut3]
Language`HandleMutation[oop`ob[sym][[1]] = 2]
(* oop`ob::modfl: The modification oop`ob[sym][[1]]=2 could not be performed. *)
(* ==> $Failed *)
is transmogrified into this basic failure we'd expect without the mutation system when using Language`MutationFallthrough
:
oop`mut3[___] := Language`MutationFallthrough
Language`HandleMutation[oop`ob[sym][[1]] = 2]
(* Set::setps: oop`ob[sym] in the part assignment is not a symbol. *)
(* ==> HoldComplete[2] *)
Language`*
do"? $\endgroup$Language`*VariableLengthInteger
functions allow one to convert an arbitrary integer to a short byte sequence and vice versa. This encoding method is used in WXF file format and described in the sectionLength Encoding (Varint)
of reference.wolfram.com/language/tutorial/… $\endgroup$