In my current modeling project using MASON and Clojure, I’m trying to develop tools and strategies for using MASON in ways that will relatively easy and idiomatic for Clojure. I’ve been defining agents
as Clojure defrecord data structures, which are very easy to work with. For certain certain kinds of model designs, defrecords are the obvious and natural way to represent MASON agents in Clojure.
One thing that’s nice about MASON is that with little or no additional programming effort, I can double-click on a portrayal of an agent in the GUI and immediately get a inspector. Another nice thing is
that if I need a custom inspector for agents, I don’t necessarily have to write an inspector class; I can define my agents as implementing Proxiable, giving them a propertiesProxy() method to return an alternative object that will be inspected instead of the
original agent. That’s very convenient.
The use case and problem:
I need to use Proxiable or some other method to deal with a problem I’m having with inspectors for my defrecord agents.
However, Proxiable only works with non-collection objects—not with Maps, ArrayLists, etc. I this think makes sense for Java, but for Clojure it would be nice to be able to use Proxiable with collections:
Defrecords implement java.util.Map, which is part of what makes defrecords so convenient. (Roughly speaking, defrecords are Objects in which the names of the instance variables can be used as if they were Map keys, and which can be treated using certain functions
that also operate on Clojure maps.)
So if I define agents using defrecord, I can’t make use of Proxiable: Since defrecords are Maps, the MASON inspector mechanism uses sim.util.CollectionProperties rather than sim.util.SimpleProperties to
extract properties from the agent. While SimpleProperties will use a proxy object if the original object implements Proxiable, CollectionProperties currently won’t.
There are of course ways to work around this issue. For example, I could use Clojure’s deftypes instead defrecords, since deftypes aren’t Maps. However, the easy strategies I’ve thought about so far would
thwart the goal of making use of Clojure with MASON easy and relatively natural, or just involve more work. I may end up writing my own inspector class, for example, but Proxiable seems like an easier approach.
From a Clojure point of view, being able to make a deftype but not a defrecord Proxiable seems like an arbitrary limitation. Obviously, though, MASON was written for use with Java, not Clojure, and almost
no one uses MASON with Clojure. I’ll understand if it’s felt that it would be a mistake to let CollectionProperties handle Proxiable. Maybe I’ll make my own custom fork, but I’d be interested in feedback regardless. There might be technical reasons that
this would be a bad idea, too, for all I know.
(Why do I need a proxy agent? I’m using functional programming style code whenever possible, which means that on each timestep the defrecord that models an agent is new. There are some minor tricks involved
in this, but it works well. The only problem so far is that inspectors have no way of knowing that a new object is supposed to be inspected on every timestep. This isn’t a MASON problem: Any way of inspecting individual agents in an ABM framework will work
most naturally with objects that retain their identity while changing over time. Maybe this is the most significant drawback, from my point of view, to writing an ABM in largely functional style. MASON provides tools to help work around this problem, however.)
Marshall Abrams, Associate Professor
Department of Philosophy, University of Alabama at Birmingham
Mail: HB 414A, 900 13th Street South, Birmingham, AL 35294-1260; Office: HB 418