Using symbols to store data and object-like functions
Here are interesting functions to use symbols like objects. (I originally posted these thoughts in What is in your Mathematica tool bag?)
It is already well known that you can store data in symbols and quickly access them using DownValues.
(*Write/Update*)
mysymbol["property"]=2;
(*Access*)
mysymbol["property"]
(*Delete*)
Unset[mysymbol["property"]]
It is similar to a hashtable, new rules are added for each property to DownValues[mysymbol]. But internally, from what I understood, rules of a symbol are stored as a hashtable so that Mathematica can quickly find which one to use. The key ("property" in the example) doesn't need to be a string, it can be any expression (which can be used to cache expressions, as also shown in the post quoted above).
Keys
You can access the list of keys (or properties) of a symbol using these functions based on what dreeves once submitted (I was quite lucky to have found his post early in my Mathematica learning curve, because it allowed me to work on functions working with lots of different arguments, as you can pass the symbol containing the stored properties to a function and see which keys this symbol contains using Keys):
SetAttributes[RemoveHead, {HoldAll}];
RemoveHead[h_[args___]] := {args};
NKeys[_[symbol_Symbol]]:=NKeys[symbol]; (*for the head[object] case*)
NKeys[symbol_] := RemoveHead @@@ DownValues[symbol(*,Sort->False*)][[All,1]];
Keys[symbol_] := Replace[NKeys[symbol], {x_} :> x, {1}];
Usage example of Keys
a["b"]=2;
a["d"]=3;
Keys[a]
(*getting the values associated with the keys of the a symbol*)
a /@ Keys[a]
If you use multiple keys for indexing a value
b["b",1]=2;
b["d",2]=3;
Keys[b]
(*getting the values associated with the keys of the b symbol*)
b @@@ Keys[b]
PrintSymbol
I use this function a lot to display all infos contained in the DownValues of a symbol (which uses one key per value):
PrintSymbol[symbol_] :=
Module[{symbolKeys=Keys[symbol]},
TableForm@Transpose[{symbolKeys, symbol /@ symbolKeys}]
];
PrintSymbol[a]
Replacing a part of a list stored in a symbol
The following would produce an error
mysymbol["x"]={1,2};
mysymbol["x"][[1]]=2
One way to do this would be either to introduce a temporary variable for the list stored in mysymbol["x"], modify it and put it back in mysymbol["x"] or, if possible, use a syntax like
mysymbol["x"] = ReplacePart[mysymbol["x"], 1 -> 2]
Creation of objects with integrated functions
Finally here is a simple way to create a symbol that behaves like an object in object oriented programming, different function syntaxes are shown :
Options[NewObject]={y->2};
NewObject[OptionsPattern[]]:=
Module[{newObject,aPrivate = 0},
(*Stored in DownValues[newObject]*)
newObject["y"]=OptionValue[y];
newObject["list"] = {3, 2, 1};
(*Stored in UpValues[newObject]*)
function[newObject,x_] ^:= newObject["y"]+x;
newObject /: newObject.function2[x_] := 2 newObject["y"]+x;
(* "Redefining the LessEqual operator" *)
LessEqual[newObject,object2_]^:=newObject["y"]<=object2["y"];
(* "Redefining the Part operator" *)
Part[newObject, part__] ^:= newObject["list"][[part]];
(*Syntax stored in DownValues[newObject], could cause problems by
being considered as a property with Keys*)
newObject@function3[x_] := 3 newObject["y"]+x;
(*function accessing a "private" variable*)
functionPrivate[newObject] ^:= aPrivate++;
(* "Redefining the [ ] operator" *)
newObject[x_] := x newObject["list"];
(*Format*)
Format[newObject,StandardForm]:="newObject with value y = "~~ToString[object["y"]];
newObject
];
Properties are stored as DownValues and methods as delayed Upvalues (except for the [ ] redefinition also stored as DownValues) in the symbol created by Module that is returned. I found the syntax for function2 that is the usual OO-syntax for functions in Tree data structure in Mathematica.
Private variable
The variable aPrivate can be seen as a private variable as it is only seen by the functions of each newObject (you wouldn't see it using Keys). Such a function could be used to frequently update a list and avoid the issue of the previous paragraph.
If you wanted to DumpSave newObject you could know which aPrivate$xxx variable to also save by using the depends function of Leonid Shifrin described in the post Automatically generating a dependency graph of an arbitrary Mathematica function?.
depends[NewObject[]]
Note that xxx is equal to $ModuleNumber - 1 when this expression is evaluted inside Module so this information could be stored in newObject for later use.
Other way for storing functions in a different symbol
You could also store the function definition not in newObject but in a type symbol, so if NewObject returned type[newObject] instead of newObject you could define function and function2 like this outside of NewObject (and not inside) and have the same usage as before. See the second part of the post below for more on this.
(*Stored in UpValues[type]*)
function[type[object_], x_] ^:= object["y"] + x;
type /: type[object_].function2[x_] := 2 object["y"]+x;
(*Stored in SubValues[type]*)
type[object_]@function3[x_] := 3 object["y"]+x;
Usage example
x = NewObject[y -> 3]
x // FullForm
x["y"]=4
x@"y"
function[x, 4]
x.function2[5]
x@function3[6]
(*LessEqual redefinition test with Sort*)
z = NewObject[]
{x["y"],z["y"]}
l = Sort[{x,z}, LessEqual]
{l[[1]]["y"],l[[2]]["y"]}
(*Part redefinition test*)
x[[3]]
(*function accessing a "private" variable*)
functionPrivate[x]
(*[ ] redefinition test*)
x[4]
Reference/Extension
For a list of existing types of values each symbol has, see http://reference.wolfram.com/mathematica/tutorial/PatternsAndTransformationRules.html and http://www.verbeia.com/mathematica/tips/HTMLLinks/Tricks_Misc_4.html.
You can go further if you want to emulate object inheritance using a package called InheritRules available here http://library.wolfram.com/infocenter/MathSource/671/
Further ideas when storing functions in a head symbol
The idea is to use DownValues for storing properties in different symbols corresponding to objects and UpValues for storing methods in a unique head symbol (MyObject in the example below). We then use expressions of the form MyObject[object].
Here is a summary of what I currently use.
Constructor
Options[MyObject]={y->2};
MyObject[OptionsPattern[]]:=
Module[{newObject,aPrivate = 0},
newObject["y"]=OptionValue[y];
newObject["list"] = {3, 2, 1};
(*function accessing a "private" variable*)
functionPrivate[MyObject[newObject]] ^:= aPrivate++;
MyObject[newObject]
];
MyObject is used as "constructor" and as head of the returned object (for example MyObject[newObject$23]). This can be useful for writing functions that take into account the head of an object. For example
f[x_MyObject] := ...
Properties (like the value corresponding to the key "y") are stored as DownValues in a newObject symbol created by Module whereas functions will be stored in the MyObject symbol as UpValues.
Private variable
functionPrivate in the constructor definition has access to the "private" variable aPrivate. It is stored as UpValues of MyObject but with a dependency on each newObject symbol created in Module (which breaks the indendance between data stored in newObject and methods stored in MyObject that other function syntaxes described below share). It must be defined in Module contrary to other kind of functions described below, so that the symbols newObject and aPrivate generated in the same Module are stored in a same rule and thus can "see" each other.
Some methods stored as UpValues in MyObject (different syntaxes are shown)
(*Stored in UpValues[MyObject]*)
function[MyObject[object_], x_] ^:= object["y"] + x;
MyObject/: MyObject[object_].function2[x_] := 2 object["y"]+x;
(* "Redefining the LessEqual operator" *)
LessEqual[MyObject[object1_],MyObject[object2_]]^:=object1["y"]<=object2["y"];
(* "Redefining the Part operator" *)
Part[MyObject[object_], part__] ^:= object["list"][[part]];
myGet[MyObject[object_], key_] ^:= object[key];
mySet[MyObject[object_], key_, value_] ^:= (object[key]=value);
Methods stored as SubValues in MyObject
A method stored to easily access the properties of an object. We restrict here key to be a string in order not to interfere with other functions defined as SubValues.
MyObject[object_Symbol][key_String] := object[key];
Another function stored in SubValues[MyObject]
MyObject[object_]@function3[x_] := 3 object["y"]+x;
Redefinition of the [ ] operator
MyObject[object_][x_] := x object["list"];
"Static" variable
Similarly to what is used for a private variable, a variable can be shared among all the objects of a similar class using a following definition for the function that accesses it. (Such variables use the keyword static in C++-like languages)
Module[{staticVariable=0},
staticFunction[MyObject[object_]]^:=(staticVariable+=object["y"]);
]
Format
You can format the way the object is displayed with something like this:
Format[MyObject[object_Symbol],StandardForm]:="MyObject with value y = "~~ToString[object["y"]];
Creating an object
x = MyObject[y->3]
Test of the different functions
x // FullForm
function[x, 2]
x.function2[3]
x@function3[4]
x["y"]
x@"y"
(*LessEqual redefinition test with Sort*)
z = MyObject[]
{x["y"],z["y"]}
l = Sort[{x,z}, LessEqual]
{l[[1]]["y"],l[[2]]["y"]}
(*Part redefinition test*)
x[[3]]
(*function accessing a "private" variable*)
functionPrivate[x]
(*[ ] redefinition test*)
x[4]
(*static function example*)
staticFunction[x]
staticFunction[z]
Update properties
To update the "y" property of z you can use this (or use a setter function like mySet defined above)
ObjectSet[(_[symbol_Symbol]|symbol_),key_,value_]:=symbol[key]=value;
ObjectSet[z,"y",3]
If an object is of the kind MyObject[object] then value will be assigned to object[key] (DownValues of object) instead of being assigned to MyObject[object][key] (SubValues of MyObject whereas I want functions to be in general stored as UpValues of MyObject and properties as DownValues of object).
Another way that doesn't involve another function is to do
z[[1]]["y"] = 4
Update properties using Set
You can automate ObjectSet by overloading Set. This is what I use, as this makes the syntax more convenient for modifying the property of an object of the kind MyObject[object], but thouching to a function as important as Set is dangerous, especially if you're not the only user of your code, in this case use one of the method of the previous paragraph.
See this post for alternatives Alternative to overloading Set
enableAutomaticObjectSet[]:=
(
Unprotect[Set];
Set[symbol_[key_],value_] /; !TrueQ[$inObjectSet] :=
Block[{$inObjectSet=True},
ObjectSet[symbol,key,value]
];
Protect[Set];
);
disableAutomaticObjectSet[]:=
(
Unprotect[Set];
DownValues[Set]={};
Protect[Set];
);
So that you can do
enableAutomaticObjectSet[];
z["y"] = 4
function[z, 2]
This syntax works also for sub-objects
z["u"]=MyObject[]
z["u"]["i"]=2
PrintSymbol[z["u"]]