Seebs wrote: > On 2009-11-16, Marnen Laibow-Koser <marnen / marnen.org> wrote: >> a.to_i == c.to_i # true >> Does that all seem right? > > Hmm. > > I would actually expect a==c to be true. There's no point where I > really > want to perform an object-identity test on them, so even then, I'm just > comparing their to_i values, which will ==, since they're both 10. But you yourself said: [...] > That's "a 14". It is *equal to* another stat which has a base value of 14 > and no modifiers. But it's not the same *thing* as that other stat. == means "conceptually the same thing", I think. Not necessarily the same object reference -- but equivalent. So I actually don't think you want a==c to be true. You may want a==10 to be true, but that's a different story. > >>> 15. But you don't copy stats -- you use their values. > >> Right! In other words, they're identified by their value, not by the >> individual object reference. Ergo, *they are value objects*, by >> definition. > > "identified" may not be the right term. OK, think of it like this: if their values are the same, they are considered equal. Stat.new(5) == Stat.new(5) even though Stat.new(5) doesn't equal? Stat.new(5) -- that is, they are equal even though they're not necessarily the same object. How you define "values are the same" is up to you. I think it's best to consider it as meaning total equality for both base and modifiers. > > Two stats which yield the same result value may *compare* equal -- > because > if you're comparing them you're just working with values. But that > doesn't > mean that they're the same thing. Right. But two stats which have the same base and modifiers *are* the same thing, aren't they? There's no reason to know whether they're different objects in the VM -- for all practical purposes, they are *the same thing*. And that fact (if it is a fact) means that we're talking about value objects. [...] > So if something, for some reason, has intentionally obtained a reference > to john.strength, then it really does want to see the current value of > john.strength That's not the way Ruby references work. You can obtain a reference to the object returned by john.strength at a given time, but you can't know whether john.strength will always return that same object. In other words, you could call john.strength.object_id and get a value (let's say 12345). If you later call john.strength.object_id, the returned value might or might not be 12345. The caller should make no assumptions in this regard. >-- but that's the exceptional case, not the normal case, > so > assigning it to mary.strength wouldn't do that. > >>> In fact, in "john.strength = Stat.new(15)", what really happens is that >>> john does the same thing -- adjust the already-existing stat so that it >>> will >>> have an effective value of 15. > >> No. If you call a constructor, you might as well use the object. :) > > Except that people might already have, for some crazy reason, an > intentional > reference into "the strength stat for john". There is no such thing in Ruby, as I explained above. There is nothing really to be gained by keeping the object_id the same. > > Although it occurs to me that there's really no REASON for them to ever > do > that. And really no way to do it. (Even if they do figure out a way, that's abuse of your interface. They shouldn't expect it to work.) [...] >> So you *do* want to do something like john.strength.modifiers[:racial], >> right? > > Maybe. > >> If so, then the Stat class is not internal. Personally, I think >> that's fine -- a stat is not jet a simple number, and so you might as >> well represent it with an appropriate value object. > > So when the modifiers change, your solution would be to replace the > entire > object, duplicating its whole set of modifiers and other state? Yes. That is the best way of handling value objects -- in fact, it's the way Ruby handles Fixnums! irb(main):001:0> a = 1 => 1 irb(main):002:0> a.object_id => 3 irb(main):003:0> a += 5 => 6 irb(main):004:0> a.object_id => 13 Object 1 is the Fixnum 1, and object 13 is the Fixnum 6. When the value of a changes, the variable a holds an entirely different object reference. > > Hmm. > > I guess my current thought is... A statistic really IS an object of its > own with complicated internal state which changes over time. It doesn't > make sense to replace and duplicate that potentially-quite-complicated > state. Then maybe a statistic should be composed of several value objects. I was operating under the assumption that it's just a base Fixnum and a Hash containing a few modifier Fixnums. What else is there? > However, 90% of references will end up not caring about any of > that > state, and only wanting the object's final-value -- which really IS a > value object. Right -- probably a Fixnum. > > So it would make some sense to just always right john.strength.value, > except > that this would get to be really annoying, and since 90% of usages are > going > to be like that, I come up with the alternative: Any reference to > john.strength in a context that looks like it might be arithmetic yields > the > value, which is at any given time an immutable object, Which you can do with delegation and coercion. > and bypasses the > large, complicated, mutable object. From what you've described, Stat isn't large and complicated. What's missing from your description? > > -s Best, -- Marnen Laibow-Koser http://www.marnen.org marnen / marnen.org -- Posted via http://www.ruby-forum.com/.