Struct equivalent in Mathematica?

Update: Mathematica 10 has introduced Association, which can be used as a close equivalent of structs.

params = <| "par1" -> 1, "par2" -> 2 |>

params["par1"]
(* ==> 1 *)

In version 10 pure functions can have named arguments, and can be effectively used as expression templates where the slots can be populated from an association. This is similar to the technique I describe in the original version of this post (below the line).

#par1 + #par2 & [params]

will evaluate to 1 + 2 then to 3.

That said, my personal workflow still fits better with the approach described below the line (withRules). The reason for this is that I tend to build up calculations interactively and incrementally. This means that I do not start by writing the equivalent of an expression template (which would require thinking ahead...). Instead I start with all the values explicitly written out, and later I replace them with a global variable. This global variable can be simply Unset, and given a local value using withRules, then eventually changed into a function argument.


Quoting the OP's comment:

Most of the work I do involves constructing mathematical models and then testing various scenarios against those models. I'd like to be able to populate a particular scenario and then pass that scenario to a model. I'd also like to be able to copy that scenario, modify one or more parameters, and then pass the new scenario to the model.

The requirement, as I understand, is to be able to pass many parameter values around in a structured way. Lists of rules are convenient for this:

params = {par1 -> 1, par2 -> 2, par3 -> {x,y,z}}

They can be extracted like this:

par1 /. params

(* ==> 1 *)

Once I wrote a function for substituting such parameter lists into bigger pieces of code:

ClearAll[withRules]
SetAttributes[withRules, HoldAll]
withRules[rules_, expr_] :=
  First@PreemptProtect@Internal`InheritedBlock[
    {Rule, RuleDelayed},
    SetAttributes[{Rule, RuleDelayed}, HoldFirst];
    Hold[expr] /. rules
]

It can be used like this:

withRules[params,
  par1 + par2
]

(* ==> 3 *)

withRules can contain complex code inside, and all occurrences of par1, par2, etc. will be substituted with the values from the parameter list.

We can also write a function for easily modifying only a single parameter (from the whole list), and returning a new parameter list. Here's a simple implementation:

setParam[paramList_, newRules_] :=
 DeleteDuplicates[Join[newRules, paramList], 
  First[#1] === First[#2] &]

Example usage:

setParam[params, {par2 -> 10}]

(* ==> {par2 -> 10, par1 -> 1, par3 -> {x, y, z}} *)

Another list which has a different value for par2 is returned.


If needed, this could be extended to support more complex, structured lists such as { par1 -> 1, group1 -> {par2x -> 10, par2y -> 20}}, much how like the built-in option-handling works.


Addendum by celtschk: It's possible to extract a value from a list of rules using OptionValue as well: OptionValue[params, par1].


This answer may be unacceptable right from the outset because it uses undocumented functions. However, it has advantages over some of the approaches suggested so far which might be redeeming enough in certain scenarios to recommend it in practice. In particular, it provides totally encapsulated state (unlike, e.g., DownValues or Temporary symbols) and O(1) access and updates (unlike, e.g., a list of rules).

I would suggest a System`Utilities`HashTable object, which exists in at least Mathematica 7 and 8 (but not in 5.2, and I didn't check 6). This is manipulated using a relatively small number of simple functions:

  • System`Utilities`HashTable[]: creates a new hash table.
  • System`Utilities`HashTableAdd[ht, key, val]: adds a key-value pair {key, val} to the hash table ht.
  • System`Utilities`HashTableGet[ht, key]: given a hash table ht and a key key, retrieves the value corresponding to key.
  • System`Utilities`HashTableRemove[ht, key]: given a hash table ht and a key key, removes key from ht.
  • System`Utilities`HashTableContainsQ[ht, key]: given a hash table ht and a key key which may or may not exist in ht, determines whether or not key does in fact exist in ht. (This is useful since adding a key that already exists or querying/removing a nonexistent key produces an ugly message.)

I trust that this is all quite self-explanatory, but the following is a brief usage example for reference:

h = System`Utilities`HashTable[]
 (* -> System`Utilities`HashTable[<0>] *)

(* Setting properties for an "account" *)
System`Utilities`HashTableAdd[h, accountID, 47];
System`Utilities`HashTableAdd[h, balance, 1632.40];

(* Querying a property *)
accid = System`Utilities`HashTableGet[h, accountID]
 (* -> 47 *)

(* Updating a property *)
bal = System`Utilities`HashTableGet[h, balance];
System`Utilities`HashTableRemove[h, balance];
System`Utilities`HashTableAdd[h, balance, bal + 506.31];

System`Utilities`HashTableGet[h, balance]
 (* -> 2138.71 *)

If you aren't completely put off by the fact that all of this is undocumented, the System`Utilities`HashTable looks it could offer a passable alternative to a struct for many applications.


There were several attempts to emulate structs in Mathematica. Emphasis on emulate, since AFAIK there is no built - in support for it yet. One reason for that may be that structs are inherently mutable, while idiomatic Mathematica gravitates towards immutability. You may find these discussions interesting:

Struct-data-type-in-mathematica

Object-oriented-mathematica-programming

Question-on-setting-up-a-struct-in-mathematica-safely

Mathematica-oo-system-or-alternatives

My own take on it is in this answer:

Tree-data-structure-in-mathematica

where I describe one possible emulation of structs, which I use every now and then when I need something like a struct (this is, of course, a personal preference. There are many ways to do this). It looks to be somewhat similar to your method. For a recent use case where I put similar approach to heavy use and where it really pays off (because structs are not the bottleneck there), see this answer, where I use this as an encapsulation mechanism for file-backed lists.

That said, a built-in support for mutable structures would be, I think, very desirable. Three major reasons I could think of, why various emulation approaches did not really take off:

  • Performance. Structs are the work-horse of data structures, and their performance is critical. OTOH, all emulations which are to be general, are bound to use the top-level code, and that is slow.
  • Garbage collection. The available ways to create encapsulated mutable state almost always involve creating definitions for symbols, and those definitions are frequently not automatically amenable to garbage collection
  • (The lack of) standardization. If there were a single emulation which would accumulate a significant code base, tools and practices of using it, that may have been different.