So the problem with (B) is this. Let's say that M (and M0) is a MutableDouble2D and D (and D0) is a Double2D. If I say: Double2D Q = D.add(M) or Double2D Q = D.add(D0) This will put into Q the result of D+M (or D+D0), but neither D, nor D0, nor M will be modified. However if I say MutableDouble2D Q = M.add(D) or MutableDouble2D Q = M.add(M0) This will put into Q the result of D+M (or M0+M), but also set M to that result. I would imagine this would be... fairly surprising. Wouldn't you? That's what concerns me. Sean On Oct 29, 2009, at 10:49 AM, Matthew Berryman wrote: > Sean, > > I agree with your points on (B), and this would be personally least > surprising to me, given the other existing methods (it is mutable, > after all :) > I'm just a sample size of one, though. > > Cheers, > Dr Matthew Berryman > Defence and Systems Institute > SPRI Building > University of South Australia > Mawson Lakes SA 5095 > t +61 8 8302 5882 > f +61 8 8302 5344 > m +61 413 458 594 > CRICOS Provider Number: 00121B > > > > On 29/10/2009, at 7:40 PM, Sean Luke wrote: > >> 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 >>> >>>