The basic problem I have been running into is making readable code, where in other languages I am more familiar with I might have been using class or struct like objects. For example, you can imagine I might want to create a circle object, which would, at the very least, store the radius and position of the circle. In an object-oriented language, I might access the $x$-coordinate of the center of the circle using something like circ.pos.x
. In Mathematica, however, I find myself using nothing more than nested lists, and as a result, wind up with code looking something like circ[[2]][[1]]
(circ[[1]]
is the radius and circ[[2]]
is the position vector, say). You can imagine how code like this could become very unreadable very fast. Presumably, this is because I'm not 'doing it right'. So, then, what is the 'right' way to implement something like this? Does Mathematica support built-in object-oriented features I'm not aware of?
|
||||
It is probably debatable to what extent it has built-in object oriented features. In any case, this answer is not intended to lead you to try to emulate object oriented programming, which is in general a bad idea. (see @Leonid 's answer) However, it is not debatable that Mathematica is tremendously flexible (as to style and notation at least, the evaluation model is quite limited) and offers you a lot of more options than the one you mention you are taking to write clear code. (With great freedom comes great responsibility) The most natural way of doing what you want the Mathematica way is using immutable data structures, as recommeded by Leonid in a comment in his answer. For example, storing a circle as
A few others options
I am being serious when I say these are just a few. You could even end up creating your own graphical language if you start adding input aliases and playing with boxes. Useless example
Now, in a new cell write |
||||
|
At the risk of repeating myself, I would like to stress that one has to be critical towards the superficial flexibility offered by Mathematica, when (particularly mutable) data structures are concerned. Using mutable data structures assumes a programming style for which Mathematica is not optimized. It can emulate it, yes, and we have seen a number of such emulations in the mentioned and newly posted answers (and I am myself responsible for a number of such emulations), but I personally find most of them unsatisfactory in several important aspects. For mutable data structures, some of them are:
For immutable data structures (such as lists of rules), which some folks suggest to use to emulate structs, the main issues I see are
I suspect that the above are some of the reasons why most or all of the multiple suggested approaches based on the top-level code did not massively take off. The main reason must be, of course, performance. Here and here are two recent examples of how much the choice of the right data structures in Mathematica may affect the performance (how about 3-4 orders of magnitude difference?). The problem is, you will not get a good performance from mutable data structures implemented in the top-level, and you have to understand Mathematica really well to pick the right (for a given problem) fast immutable structures. So, my suggestion is that we stop offering countless new emulations and stop praising Mathematica flexibility where it does not serve us well, since data structures are not the place where we have to be flexible - it is a place where we have to be clear and fast and compositional. Let's face it, currently Mathematica does not have a native support for mutable performant general data structures in the way that C or Java do. Perhaps, at some point it will, and then it will be different. Now, why I am so much against emulations? Because at the end, you waste your time. I found that when I really need mutable data structures (which is usually for performance - demanding problems), I do things much faster in Java and link to Mathematica, than write in Mathematica and spend hours to optimize the top-level code. So, a pragmatic advice: either reformulate your problem in such a way that you can handle it with constructs natural to Mathematica (immutable lists, trees, rules, symbolic heads as containers for types, etc - if performance requirements of your problem allow that), or, if you really need mutable data structures, implement that part in a language which natively supports them, and link that to Mathematica. You will save your time. |
|||||||||||||||||||
|
{radius -> 3}
. – Szabolcs Jul 24 '12 at 21:14circ[[2,1]]
instead ofcirc[[2]][[1]]
. – Verbeia♦ Jul 24 '12 at 21:55Circle[{0,0}, 2}]
. Then when defining a function that processes a circle, you can decompose the data using patterns:fun[circ: Circle[pos: {x_,y_}, r_]] := ...
. Now you can refer to the position aspos
, radius asr
, etc. You can use similar patterns in replacements or other functions. This is just a small example on what I would do in Mathematica in certain situations when having to handle a circle. – Szabolcs Jul 25 '12 at 6:38