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/.