October 2009


Options: Use Monospaced Font
Show Text Part by Default
Show All Mail Headers

Message: [<< First] [< Prev] [Next >] [Last >>]
Topic: [<< First] [< Prev] [Next >] [Last >>]
Author: [<< First] [< Prev] [Next >] [Last >>]

Print Reply
Sean Luke <[log in to unmask]>
Reply To:
MASON Multiagent Simulation Toolkit <[log in to unmask]>
Tue, 27 Oct 2009 19:41:46 +0100
text/plain (92 lines)
I'm facing a tough decision on Double2D which could affect the entire  
community and so I'm interested in some feedback.

I've been going through the physics2d engine and doing some cleanup  
and one thing that could really help in that cleanup is to add some  
functions to Double2D which are presently only in MutableDouble2D, but  
to do so in such a way that Double2D's version would have somewhat  
different semantics.

MutableDouble2D has four kinds of ways of "adding":

MutableDouble2D m1, m2, m3;  // 2d vectors
double v;  // a scalar

m1.addIn(m2);   // m1 <- m1 + m2, return m1
m1.addIn(v);    // m1 <- m1 + v (at all slots in m1), return m1

m1.add(m2, m3); // m1 <- m2 + m3, return m1
m1.add(m2, v);  // m1 <- m2 + v (at all slots in m1), return m1

The use of "add" in this context is unfortunate, I know.  It's going  
to cause problems in a second.  But originally my idea was to enable  
stuff like this:

m1 = new MutableDouble2D().add(m2, m3).multiplyIn(v).normalize();

Which does
	m1 <- normalize((m2 + m3) * v)

... but doesn't do any new allocations at all, because at each step we  
just overwrite the variables inside the MutableDouble2D we created.

Okay, so that's cute.  The problem comes when I want to add similar  
functionality to Double2D.  I can't implement an "addIn" method  
because Double2D is IMMUTABLE.  Instead, I'd do something like this:

Double2D d1, d2, d3;
double v;

d1 = d2.add(d3).mutiply(v).normalize();

This does the same thing but at each step a new Double2D is created.   
For example,

d1.add(d2);	// new d <- d1 + d2, return d

That's a good, easy to understand functional style which is much less  
convoluted than the MutableDouble2D approach, BUT it allocates lots of  
Double2Ds, which isn't particularly efficient, though it's not  
horrible.  So it's a useful functionality to have in Double2D.

The problem is that the semantics are somewhat different than  
MutableDouble2D's semantics, in which the original object is  
OVERWRITTEN.  This is particularly obvious in the normalize() method,  
which in MutableDouble2D normalizes the actual MutableDouble2D, but  
for Double2D would produce a new Double2D (it's have to).

Also MutableDouble2D's add(...) method, for example, takes two  
arguments and has totally different semantics than Double2D's add(...)  
method would.

I'm trying to nail down what options I have.  One choice I have been  
mulling over is to add methods to Double2D like add(d) [note one  
argument], multiply(v), etc., and then also create similar  
MutableDouble2D methods with the same names.  But the question is how  
the MutableDouble2D methods should work.  Should they (A) produce NEW  
MutableDouble2D instances or (B) overwrite the existing  
MutableDouble2D instance, like other MutableDouble2D methods presently  

(A) is more semantically consistent with the proposed new Double2D  

(B) is semantically consistent with the existing MutableDouble2D  

I'm trying to follow the principle of least surprise but I don't know  
which of these would have less surprise.   normalize() in particular  
will *have* to be case (B).  There's no way around it.  Which has been  
nudging me to wards doing (B).   A third option would be to just  
create Double2D methods and not create ANY equivalent MutableDouble2D  

The decision made here will have a long-standing effect on use of  
these classes, and they're so integral to MASON that I want to be very  
very careful.  Backward compatability will be retained but I am  
concerned about making things weird in the future.

So I'd really appreciate some opinions on the matter.