Not hearing a peep from the peanut gallery :-( I'm inclined to make the (B) modifications. Going once, going twice? Sean On Oct 27, 2009, at 7:41 PM, Sean Luke wrote: > 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 do? > > (A) is more semantically consistent with the proposed new Double2D > methods. > > (B) is semantically consistent with the existing MutableDouble2D > methods. > > 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 methods. > > 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. > > Sean > >