Newbie question: Defining a numeric type

I have a type which has a bit of internal magic, but fundamentally, I
want
it to behave for most purposes like the value it yields from
to_i/to_int.

Basically, is there a way to avoid having to write +, -, etcetera, when
in each case it’d be:
def (other)
self.to_i other
end

I think I’m thinking something like the Comparable mixin; sort of a
“I have a to_i, make me a number” module.

-s

Have a look at Forwardable

Seebs wrote:

I have a type which has a bit of internal magic, but fundamentally, I
want
it to behave for most purposes like the value it yields from
to_i/to_int.

Does it need to be a class of its own? You could use a module and just
include it where necessary:

module Magical
def magic

end
end


@val = 5
class << @val
include Magical
end
@val.magic

Basically, is there a way to avoid having to write +, -, etcetera, when
in each case it’d be:
def (other)
self.to_i other
end

If you don’t like the first solution, try:

[:+, :*, :-, :/, :%].each do |op|
define_method op {|other| self.send op, other}
end

You could wrap this in a module too.

I think I’m thinking something like the Comparable mixin; sort of a
“I have a to_i, make me a number” module.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Seebs wrote:

I have a type which has a bit of internal magic, but fundamentally, I
want
it to behave for most purposes like the value it yields from
to_i/to_int.

Does it need to be a class of its own? You could use a module and just
include it where necessary:

module Magical
def magic

end
end


@val = 5
class << @val
include Magical
end
@val.magic

Basically, is there a way to avoid having to write +, -, etcetera, when
in each case it’d be:
def (other)
self.to_i other
end

If you don’t like the first solution, try:

[:+, :*, :-, :/, :%].each do |op|
define_method op {|other| self.to_i.send op, other}
end

You could wrap this in a module too.

I think I’m thinking something like the Comparable mixin; sort of a
“I have a to_i, make me a number” module.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Seebs wrote:

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

Does it need to be a class of its own?

I think it makes more sense that way. It’s a category of objects which
have common additional methods they support, but which can be used in
nearly
any context where you could use an integer.

Then they should most likely be Integers. Extend them either with
module inclusion or by subclassing.

If you don’t like the first solution, try:

[:+, :*, :-, :/, :%].each do |op|
define_method op {|other| self.to_i.send op, other}
end

You could wrap this in a module too.

Could, but…

The suggestion to try Forwardable got me to find SimpleDelegator, which
turns out to work beautifully.

Yeah, but it’s probably not conceptually right for this case. Have you
been following the thread about using mixins rather than declaring new
classes?

Basically, I’m doing a roguelike mostly for fun and/or as a learning
exercise, and I wanted a way to encode “stats” – things like strength
or intelligence, which characters have. Stats might have temporary
modifiers, or remember their highest previous value, or whatever… But
90% of the time, you just want to refer to them and get the value
they currently have. Making the user write “player.str.current_value”
is annoying; I’d rather just use “player.str”. So having that delegate
to an internal member which really is just an integer works; then,
whenever
that value changes, I point the delegator at it, and Everything Just
Works.

If you use actual Integers as I suggested above, everything will Just
Work with less effort, and your design will be clearer.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

Does it need to be a class of its own?

I think it makes more sense that way. It’s a category of objects which
have common additional methods they support, but which can be used in
nearly
any context where you could use an integer.

If you don’t like the first solution, try:

[:+, :*, :-, :/, :%].each do |op|
define_method op {|other| self.to_i.send op, other}
end

You could wrap this in a module too.

Could, but…

The suggestion to try Forwardable got me to find SimpleDelegator, which
turns out to work beautifully.

Basically, I’m doing a roguelike mostly for fun and/or as a learning
exercise, and I wanted a way to encode “stats” – things like strength
or intelligence, which characters have. Stats might have temporary
modifiers, or remember their highest previous value, or whatever… But
90% of the time, you just want to refer to them and get the value
they currently have. Making the user write “player.str.current_value”
is annoying; I’d rather just use “player.str”. So having that delegate
to an internal member which really is just an integer works; then,
whenever
that value changes, I point the delegator at it, and Everything Just
Works.

-s

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

Seebs wrote:

I think it makes more sense that way. It’s a category of objects which
have common additional methods they support, but which can be used in
nearly
any context where you could use an integer.

Then they should most likely be Integers. Extend them either with
module inclusion or by subclassing.

Hmm. I tried subclassing, but perhaps incorrectly. The problem is that
it really is, internally, an object with several integers, but unless
you
know that and care about it, all you need is one particular one of those
integers.

Yeah, but it’s probably not conceptually right for this case. Have you
been following the thread about using mixins rather than declaring new
classes?

Only sort of.

If you use actual Integers as I suggested above, everything will Just
Work with less effort, and your design will be clearer.

I’m curious about this, but I’m having a hard time wrapping my head
around it. So far as I can tell, unless the integer is a Bignum, it’ll
be a Fixnum – which means that any two things with the same value
are the same object, and so on.

But I don’t want any two statistics which currently have the same
apparent
value to be the same object – because I need to be able to, say, tack
on
a modifier to one of them and have it not affect the other.

As an example, some hypothetical object might do something like:

x = Stat.new(10)
y = Stat.new(10)

x.adjust_to(15)

At this point, “x + 1” should be 16, and “y + 1” should be 11. If I
tacked
on a “+3” modifier to x, x would report itself as 18… But internally,
it’s a 15 and a +3. 18 is just its value for most purposes.

I can’t figure out how to express that by subclassing Integer. The stat
has several integers, although one of them is the one you probably want
if
you’re trying to perform arithmetic on it.

(Note the “adjust_to” – you can’t, for obvious reasons, assign a new
value with =. Things which have stats define the attr= for those stats
to use adjust_to.)

-s

Seebs wrote:

I think I’m thinking something like the Comparable mixin; sort of a
“I have a to_i, make me a number” module.

You could just delegate to the number:

class Foo
def initialize(n)
@n = n
end
def to_int
@n
end
def method_missing(*args)
to_int.send(*args)
end
end

f = Foo.new(12)
puts f + 3
puts 2 + f

Note that there is a subtle distinction between to_int and to_i, as
there is between to_str and to_s. I think you want to_int here, since
you are declaring that your object is, to all intents and purposes, an
integer.

You could also look at the #coerce method, but I don’t think it’s needed
here.

Seebs wrote:

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

Seebs wrote:

I think it makes more sense that way. It’s a category of objects which
have common additional methods they support, but which can be used in
nearly
any context where you could use an integer.

Then they should most likely be Integers. Extend them either with
module inclusion or by subclassing.

Hmm. I tried subclassing, but perhaps incorrectly. The problem is that
it really is, internally, an object with several integers, but unless
you
know that and care about it, all you need is one particular one of those
integers.

Oh, then that’s a different story. In this case, delegation is probably
the right thing to do.

Yeah, but it’s probably not conceptually right for this case. Have you
been following the thread about using mixins rather than declaring new
classes?

Only sort of.

If you use actual Integers as I suggested above, everything will Just
Work with less effort, and your design will be clearer.

I’m curious about this, but I’m having a hard time wrapping my head
around it. So far as I can tell, unless the integer is a Bignum, it’ll
be a Fixnum – which means that any two things with the same value
are the same object, and so on.

But I don’t want any two statistics which currently have the same
apparent
value to be the same object – because I need to be able to, say, tack
on
a modifier to one of them and have it not affect the other.

Sure. I didn’t realize you were doing things like that. And you’re
right that the singleton nature of Bignums makes them less flexible in
this regard.

As an example, some hypothetical object might do something like:

x = Stat.new(10)
y = Stat.new(10)

x.adjust_to(15)

At this point, “x + 1” should be 16, and “y + 1” should be 11. If I
tacked
on a “+3” modifier to x, x would report itself as 18… But internally,
it’s a 15 and a +3. 18 is just its value for most purposes.

I can’t figure out how to express that by subclassing Integer.

It’s probably not worth it. I didn’t understand your structure
originally.

The stat
has several integers, although one of them is the one you probably want
if
you’re trying to perform arithmetic on it.

Brian’s suggestion of #coerce may be a good one.

(Note the “adjust_to” – you can’t, for obvious reasons, assign a new
value with =. Things which have stats define the attr= for those stats
to use adjust_to.)

Philosophical point: many people (myself included, I think) believe that
unlike entity objects (say, Player in your game), value objects should
be immutable. This means

class Stat
def adjust_to(n)
# bad:
@base = n
# good:
Stat.new(n, @modifier)
end
end

See http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable . Among other
things, this means you never have to worry about modifying an object
referred to in multiple places.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

(Note the “adjust_to” – you can’t, for obvious reasons, assign a new
value with =. Things which have stats define the attr= for those stats
to use adjust_to.)

end
end

See http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable . Among other
things, this means you never have to worry about modifying an object
referred to in multiple places.

In this case, I think the correct model is that this isn’t really a
value
object, it’s just an object which has a value. Imagine that I wanted to
talk about “my paycheck”. Well, there’s a base salary, and there’s
various
taxes and deductions and withholding… But except when I’m doing the
tax
accounting, all I really care about is the take-home pay, so if I
refer to “salary” I probably mean the output value of all those
calculations.

Basically, if someone else has a reference to a specific stat, and it
changes, I think they DO want to see the now-changed value.

-s

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

(Note the “adjust_to” – you can’t, for obvious reasons, assign a new
value with =. Things which have stats define the attr= for those stats
to use adjust_to.)

end
end

See http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable . Among other
things, this means you never have to worry about modifying an object
referred to in multiple places.

In this case, I think the correct model is that this isn’t really a
value
object, it’s just an object which has a value. Imagine that I wanted to
talk about “my paycheck”. Well, there’s a base salary, and there’s
various
taxes and deductions and withholding… But except when I’m doing the
tax
accounting, all I really care about is the take-home pay, so if I
refer to “salary” I probably mean the output value of all those
calculations.

Basically, if someone else has a reference to a specific stat, and it
changes, I think they DO want to see the now-changed value.

-s

Seebs wrote:

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

(Note the “adjust_to” – you can’t, for obvious reasons, assign a new
value with =. Things which have stats define the attr= for those stats
to use adjust_to.)

end
end

See http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable . Among other
things, this means you never have to worry about modifying an object
referred to in multiple places.

In this case, I think the correct model is that this isn’t really a
value
object, it’s just an object which has a value.

I think you are likely wrong. But there’s a simple conceptual test you
can apply:

a = Stat.new(5)
b = Stat.new(5)

Should a == b return true or false?

If false, then this is probably not a value object in the conventional
sense.

If true, then it probably is.

Imagine that I wanted to
talk about “my paycheck”. Well, there’s a base salary, and there’s
various
taxes and deductions and withholding… But except when I’m doing the
tax
accounting, all I really care about is the take-home pay, so if I
refer to “salary” I probably mean the output value of all those
calculations.

Poor analogy. I think your paycheck is like your character’s entire
stat block, whereas the individual Stat objects seem to be analogous to
the dollar amounts on each like of the paycheck – and those are
certainly value objects.

Basically, if someone else has a reference to a specific stat, and it
changes, I think they DO want to see the now-changed value.

And I think you’re probably wrong.

john = Character.new
john.strength = Stat.new(15)
mary = Character.new
mary.strength = john.strength
mary.strength += 1

Now, what should john.strength be? 15 or 16?

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Seebs wrote:

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

a = Stat.new(5)
b = Stat.new(5)

Should a == b return true or false?

If false, then this is probably not a value object in the conventional
sense.

If true, then it probably is.

Hmm.

I would think it should return true.

So would I.

Poor analogy. I think your paycheck is like your character’s entire
stat block, whereas the individual Stat objects seem to be analogous to
the dollar amounts on each like of the paycheck – and those are
certainly value objects.

An individual stat might have:
base value 10
modifier (racial, no duration) +3
modifier (training, no duration) +2
modifier (drunk, duration 15 turns) -1

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.

Of course it isn’t. Here’s how I see this working (for simplicity, I’ll
just assume one modifier):

a = Stat.new 10, 0
b = Stat.new 10, 2
c = Stat.new 12, -2
d = Stat.new 12, -2
c == d # true
a == b # false
a == c # false
a.to_i == c.to_i # true

Does that all seem right?

And I think you’re probably wrong.

john = Character.new
john.strength = Stat.new(15)
mary = Character.new
mary.strength = john.strength
mary.strength += 1

Now, what should john.strength be? 15 or 16?

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

So what really
happens is that mary defines strength= such that it applies modifiers
to mary.strength.

Or simply creates a new immutable value object, which will save some
headache.

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. :slight_smile:

Hmm.

So, thinking about it, it seems like what I’m getting to is that really,
the “Stat” class is largely internal to characters. It’s a way to
express
something that, in general, no one else should use. (Not quite true;
you can query the modifiers that currently apply to a stat, for
instance.)

So you do want to do something like john.strength.modifiers[:racial],
right? 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.

For the purposes of nearly any possible interaction, john.strength is
just the value 15.

The easiest way to achieve that is with conversion and/or coercion.

You’re asking some really good questions here, thanks.

-s

You’re welcome! These are questions I struggle with as well – I like
to learn by teaching.
Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

On 2009-11-16, Marnen Laibow-Koser [email protected] wrote:

a = Stat.new(5)
b = Stat.new(5)

Should a == b return true or false?

If false, then this is probably not a value object in the conventional
sense.

If true, then it probably is.

Hmm.

I would think it should return true.

Poor analogy. I think your paycheck is like your character’s entire
stat block, whereas the individual Stat objects seem to be analogous to
the dollar amounts on each like of the paycheck – and those are
certainly value objects.

An individual stat might have:
base value 10
modifier (racial, no duration) +3
modifier (training, no duration) +2
modifier (drunk, duration 15 turns) -1

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.

And I think you’re probably wrong.

john = Character.new
john.strength = Stat.new(15)
mary = Character.new
mary.strength = john.strength
mary.strength += 1

Now, what should john.strength be? 15 or 16?

  1. But you don’t copy stats – you use their values. So what really
    happens is that mary defines strength= such that it applies modifiers
    to mary.strength.

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.

Hmm.

So, thinking about it, it seems like what I’m getting to is that really,
the “Stat” class is largely internal to characters. It’s a way to
express
something that, in general, no one else should use. (Not quite true;
you can query the modifiers that currently apply to a stat, for
instance.)
For the purposes of nearly any possible interaction, john.strength is
just the value 15.

You’re asking some really good questions here, thanks.

-s

On 2009-11-16, Marnen Laibow-Koser [email protected] 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.

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

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. The primary way you’d identify a
stat
is by knowing which stat it is, for which entity.

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 – 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. :slight_smile:

Except that people might already have, for some crazy reason, an
intentional
reference into “the strength stat for john”.

Although it occurs to me that there’s really no REASON for them to ever
do
that.

something that, in general, no one else should use. (Not quite true;
you can query the modifiers that currently apply to a stat, for
instance.)

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?

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

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, and bypasses the
large, complicated, mutable object.

-s

On 2009-11-17, Marnen Laibow-Koser [email protected] wrote:

== means “conceptually the same thing”, I think. Not necessarily the
same object reference – but equivalent.

Hmm.

I guess I think of == as more like “functionally the same”. Two 14s
function
the same way. If the question is “who is stronger”, then if both
characters
have a current functional strength of 14, it’s a tie.

But that doesn’t make them the same object.

Basically: 14.0 == 14. That doesn’t mean they’re the same thing,
because
obviously they’re different things. And they’re not even quite
equivalent;
15 / 14.0 is not the same as 15 / 14. But they’re still equal, because
they
have the same value.

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.

I don’t, though, because the only reason to be comparing two values is
to
see whether one is larger than the other – say, whether one creature is
stronger than another.

Right. But two stats which have the same base and modifiers are the
same thing, aren’t they?

I don’t think so. Even if john and mary both have the same base
strength,
and the same modifiers, they’re not the same thing – making john
stronger
doesn’t make mary stronger.

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.

Right – which is why my initial plan was to commit that, after
initialize(),
john.strength DOES always yield the same object, no matter what changes
are made to its value.

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!

This sounds extremely expensive for an extremely commonplace thing. In
an ordinary turn of a game, I might have thirty or forty modifiers which
change, meaning that I’d be duplicating-but-modifying non-trivial object
trees thirty or forty times.

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.

Yes, I know that.

But I don’t think a stat is a value. I think it’s a complicated model,
which
happens to yield a value.

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?

History of previous values (in some cases), and the modifiers aren’t
fixnums; they’re name/value pairs probably plus other traits such as
a duration (some expire, some don’t). There will probably be more
tweaks to that over time.

From what you’ve described, Stat isn’t large and complicated. What’s
missing from your description?

As time goes on, stats are expected to be much more complicated. A stat
will likely have its original starting base value, its highest recorded
base
value, and a set of modifiers (which may change quite often). Possibly
more
things beyond those.

So right now, I think it is probably nearly-sanest for me to have it
delegate
nearly everything to the fixnum current value, which really is a value
object.
So it isn’t a value, but it delegates to one.

Basically, anything that has internal state to keep track of which is
not part
of how you use it strikes me as not really being a value, even if it
looks
like one from the outside.

That said!

I am thinking that perhaps it should present as immutable – that is,
I
should not define john.strength = 15 in any way, but rather, if you want
to
ask it to change its value, you have to send it messages. So instead of
john.strength += 1, you’d write john.strength.adjust_by(1).

Hmm. I suppose the thing, then, would be to simply not provide a
strength=
method for the things that have stats.

-s

Seebs wrote:

On 2009-11-16, Marnen Laibow-Koser [email protected] 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.

  1. 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. :slight_smile:

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
[email protected]

On 2009-11-17, Marnen Laibow-Koser [email protected] wrote:

I didn’t say the same object – I said the same thing.
a = Stat.new(15, -2)
b = Stat.new(15, -2)
It doesn’t matter in the slightest whether a.object_id == b.object_id.
Regardless, a and b are the same thing to all intents and purposes –
and you can tell that, in part, precisely because the object_id is
irrelevant.

Perhaps, but (15, -2) and (14, -1) are also equal, even though they’re
obviously different things.

Two fives equal a ten. When I am talking about money, all I care about
is the net value, not the internal representation (coins or bills).
Unless
I have to deal with a vending machine.

But 99% of the time, 10==10 is the correct interpretation of a
comparison
between two fives and a ten.

call. You’re confusing the method with its return value. The
difference is subtle but important.

Hmm.

Oh, heyyyyy.

Okay, so one option would be:
def str
@str.to_i
end

In short, just return the value rather than the object I’m using to
model
it.

The problem is, I sort of want to be able to do things like:
john.str.add_modifier(“drunk”, -3)

Because really, the fact that str is a stat is part of the intended
published interface.

It’s just that, if you aren’t doing something uniquely stat-like to a
stat, you just want its integer value.

English: John’s strength, in the abstract, isn’t the same thing as
Mary’s strength in the abstract.
Ruby: john.method(:strength) != mary.method(:strength)

English: The current value of John’s strength happens to be equal to the
current value of Mary’s strength.
Ruby: john.strength == mary.strength

Does this make sense?

Yup.

Why? There’s no point to doing so as far as I can see. Even if it were
a Fixnum, it would already be yielding different objects every time it
changed. The client should make no assumptions about
john.strength.object_id.

Not as a specified interface that people should rely on, but rather, as
an
implementation choice – it seems crazy to me to regenerate whole
object-trees
frequently.

This sounds extremely expensive for an extremely commonplace thing. In
an ordinary turn of a game, I might have thirty or forty modifiers which
change, meaning that I’d be duplicating-but-modifying non-trivial object
trees thirty or forty times.

It may sound expensive, but it really is the best way of handling value
objects. This is how classes like Fixnum, Date, and BigDecimal work.
(Actually, Fixnum uses the Flyweight pattern under the hood; the others
might also.)

None of those classes are complicated trees containing five or ten or
thirty other objects, though, are they?

History of previous values (in some cases), and the modifiers aren’t
fixnums; they’re name/value pairs

Really? You’re not just doing
@modifiers = {:racial => 2, :class => 1, :armor => -1}?

Modifier is a class too, which can handle things like counting down its
duration, etcetera.

And a stat has a handful of them.

probably plus other traits such as
a duration (some expire, some don’t).

Does that really belong in the values itself? I’d tend to think not;
rather, that probably belongs in your event system.

It seems to me that the knowledge that a modifier expires is best
handled
by embedding it in the modifier.

But if you want history, then the StatValue object or whatever you wind
up using will probably have to be immutable anyway, so you can be sure
your history is accurate!

Ahh, but I don’t necessarily care whether it’s accurate, just whether I
have a record.

For a concrete example: A lot of games would have, say, a strength
stat,
and things that can lower your strength. Then you find a “potion of
restore strength”, which restores your strength to its highest previous
value.

To my mind, this is the kind of thing that should be handled entirely
by the stat object. It’s not john’s job to know what his highest score
was for a given stat; it’s the stat’s job to know what its highest score
was.

Then refactor your design at that time. Design for what you have now,
rather than predicting the future. Remember YAGNI.

In this case, though, I really do know that I need a fair bit of this.
The ability to damage and restore stats is pretty much essential to a
roguelike.

Since you don’t know yet, don’t design yet for them (your future plans
could easily change). Design a model that works for what you actually
have, and be ready to change it as necessary.

Yeah, but changing this into an immutable object is a lot MORE work. So
I’m not sure I should put extra work into making the object less
flexible
on the off chance that I won’t later not need to have done that work.

Largely correct, although I can think of exceptions. You’ll probably
want to break this down into a composed object containing one or more
value objects.

I think so.

No need. The former is a lot friendlier. You can always redefine
Character#strength= .

True.

That strikes me as silly. There’s no reason that the client class
should care whether your strength= method really does an assignment
operation.

True.

Hmm.

So yeah, I think at this point, I really do want a complicated composite
object, which happens to delegate to a value object which has traits
which
are useful for my purposes – in this case, almost certainly a fixnum.

-s

Seebs wrote:

On 2009-11-17, Marnen Laibow-Koser [email protected] wrote:

I didn’t say the same object – I said the same thing.
a = Stat.new(15, -2)
b = Stat.new(15, -2)
It doesn’t matter in the slightest whether a.object_id == b.object_id.
Regardless, a and b are the same thing to all intents and purposes –
and you can tell that, in part, precisely because the object_id is
irrelevant.

Perhaps, but (15, -2) and (14, -1) are also equal, even though they’re
obviously different things.

Two fives equal a ten. When I am talking about money, all I care about
is the net value, not the internal representation (coins or bills).
Unless
I have to deal with a vending machine.

But 99% of the time, 10==10 is the correct interpretation of a
comparison
between two fives and a ten.

a = Cash.new(Array.new(2, Banknote.new(5, :usd)))
b = Cash.new([Banknote.new(10, :usd))
a.to_money = b.to_money
a.banknotes != b.banknotes
a ?== b # depends on your definition of equality.

call. You’re confusing the method with its return value. The
difference is subtle but important.

Hmm.

Oh, heyyyyy.

Okay, so one option would be:
def str
@str.to_i
end

In short, just return the value rather than the object I’m using to
model
it.

That would be the appropriate solution if you never wanted to expose the
Stat object.

The problem is, I sort of want to be able to do things like:
john.str.add_modifier(“drunk”, -3)

Because really, the fact that str is a stat is part of the intended
published interface.

Then your clients will know that it’s a Stat object, and expect to call
to_i on it. I don’t see anything wrong with that; you can overload Stat

  • Fixnum and so on as we discussed earlier in this thread.

But if you really want automatic, you can have it:
class Stat
def to_int
self.to_i
end
end

(According to to_i Vs to_int | Ruby Fleebie , to_int is
called automatically as necessary and will make your class act as an
Integer. to_i, of course, will not do that.)

[…]

Why? There’s no point to doing so as far as I can see. Even if it were
a Fixnum, it would already be yielding different objects every time it
changed. The client should make no assumptions about
john.strength.object_id.

Not as a specified interface that people should rely on, but rather, as
an
implementation choice – it seems crazy to me to regenerate whole
object-trees
frequently.

For your use case, you’re probably right. For real value objects, it’s
a different story.

This sounds extremely expensive for an extremely commonplace thing. In
an ordinary turn of a game, I might have thirty or forty modifiers which
change, meaning that I’d be duplicating-but-modifying non-trivial object
trees thirty or forty times.

It may sound expensive, but it really is the best way of handling value
objects. This is how classes like Fixnum, Date, and BigDecimal work.
(Actually, Fixnum uses the Flyweight pattern under the hood; the others
might also.)

None of those classes are complicated trees containing five or ten or
thirty other objects, though, are they?

Fixnum probably isn’t. Date probably contains about 5 other objects
(totally guessing here – haven’t looked at the implementation). The
BigDecimal library I wrote for Rubinius contained about 3-5 other
objects, but I don’t know if MRI or JRuby does it the same way. The
Address class I wrote for Quorum ( http://quorum2.sourceforge.net )
contains about 6 fields in an immutable value object. Of course, I
rarely only need to modify one field in someone’s address.

History of previous values (in some cases), and the modifiers aren’t
fixnums; they’re name/value pairs

Really? You’re not just doing
@modifiers = {:racial => 2, :class => 1, :armor => -1}?

Modifier is a class too, which can handle things like counting down its
duration, etcetera.

And a stat has a handful of them.

OK…these are your value object candidates, perhaps.

probably plus other traits such as
a duration (some expire, some don’t).

Does that really belong in the values itself? I’d tend to think not;
rather, that probably belongs in your event system.

It seems to me that the knowledge that a modifier expires is best
handled
by embedding it in the modifier.

It might be.

But if you want history, then the StatValue object or whatever you wind
up using will probably have to be immutable anyway, so you can be sure
your history is accurate!

Ahh, but I don’t necessarily care whether it’s accurate, just whether I
have a record.

If it’s not accurate, then there’s no point keeping a record.

For a concrete example: A lot of games would have, say, a strength
stat,
and things that can lower your strength. Then you find a “potion of
restore strength”, which restores your strength to its highest previous
value.

To my mind, this is the kind of thing that should be handled entirely
by the stat object. It’s not john’s job to know what his highest score
was for a given stat; it’s the stat’s job to know what its highest score
was.

That depends. A good argument could be made for having the Character
store its own history, and just having the Stats be values.

In either case, though, for this sort of functionality you don’t
necessarily need a full-fledged history. All you need is something like
class Stat
def value=(new_value)
@max_value = [new_value, @value].max
@value = new value
end
end
If you’re ambitious, you could put together something like
ActiveRecord’s before_save (which is probably what I’d use for this in a
Rails app).

Then refactor your design at that time. Design for what you have now,
rather than predicting the future. Remember YAGNI.

In this case, though, I really do know that I need a fair bit of this.
The ability to damage and restore stats is pretty much essential to a
roguelike.

Well, then you’ll run into the design issues when you’re ready for them.
For now, though, and at every future step, try to
http://c2.com/cgi/wiki?DoTheSimplestThingThatCouldPossiblyWork – that
is, work with the state of the app at that time. I know premature
generalization is tempting, but it’s not usually a good idea.

Since you don’t know yet, don’t design yet for them (your future plans
could easily change). Design a model that works for what you actually
have, and be ready to change it as necessary.

Yeah, but changing this into an immutable object is a lot MORE work. So
I’m not sure I should put extra work into making the object less
flexible
on the off chance that I won’t later not need to have done that work.

Right. It’s now clear that your stat object is too complex to be a
simple immutable value object, although some of its components might
well be.

Largely correct, although I can think of exceptions. You’ll probably
want to break this down into a composed object containing one or more
value objects.

I think so.

No need. The former is a lot friendlier. You can always redefine
Character#strength= .

True.

That strikes me as silly. There’s no reason that the client class
should care whether your strength= method really does an assignment
operation.

True.

Hmm.

So yeah, I think at this point, I really do want a complicated composite
object, which happens to delegate to a value object which has traits
which
are useful for my purposes – in this case, almost certainly a fixnum.

I don’t think delegation will work here – for one thing, you may not
need to store the total value in any actual instance variable. Using
to_int or possibly coerce will work much better.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]

Seebs wrote:
[…]

Right. But two stats which have the same base and modifiers are the
same thing, aren’t they?

I don’t think so. Even if john and mary both have the same base
strength,
and the same modifiers, they’re not the same thing – making john
stronger
doesn’t make mary stronger.

I didn’t say the same object – I said the same thing.
a = Stat.new(15, -2)
b = Stat.new(15, -2)
It doesn’t matter in the slightest whether a.object_id == b.object_id.
Regardless, a and b are the same thing to all intents and purposes –
and you can tell that, in part, precisely because the object_id is
irrelevant. John’s strength isn’t the same thing as Mary’s strength,
but that’s a very different issue. The English concept “John’s strength
(in the abstract)” is equivalent to the Ruby method call john.strength.
The English concept “the concrete value that, for the moment, represents
John’s strength” is equivalent to the return value from that method
call. You’re confusing the method with its return value. The
difference is subtle but important.

English: John’s strength, in the abstract, isn’t the same thing as
Mary’s strength in the abstract.
Ruby: john.method(:strength) != mary.method(:strength)

English: The current value of John’s strength happens to be equal to the
current value of Mary’s strength.
Ruby: john.strength == mary.strength

Does this make sense?

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.

Right – which is why my initial plan was to commit that, after
initialize(),
john.strength DOES always yield the same object, no matter what changes
are made to its value.

Why? There’s no point to doing so as far as I can see. Even if it were
a Fixnum, it would already be yielding different objects every time it
changed. The client should make no assumptions about
john.strength.object_id.

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!

This sounds extremely expensive for an extremely commonplace thing. In
an ordinary turn of a game, I might have thirty or forty modifiers which
change, meaning that I’d be duplicating-but-modifying non-trivial object
trees thirty or forty times.

It may sound expensive, but it really is the best way of handling value
objects. This is how classes like Fixnum, Date, and BigDecimal work.
(Actually, Fixnum uses the Flyweight pattern under the hood; the others
might also.)

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.

Yes, I know that.

But I don’t think a stat is a value. I think it’s a complicated model,
which
happens to yield a value.

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?

History of previous values (in some cases), and the modifiers aren’t
fixnums; they’re name/value pairs

Really? You’re not just doing
@modifiers = {:racial => 2, :class => 1, :armor => -1}?

probably plus other traits such as
a duration (some expire, some don’t).

Does that really belong in the values itself? I’d tend to think not;
rather, that probably belongs in your event system.

There will probably be more
tweaks to that over time.

OK, then this is getting more complex than a simple value object. If
you want history, maybe you should have a separate StatValue object, or
simply a hash.

But if you want history, then the StatValue object or whatever you wind
up using will probably have to be immutable anyway, so you can be sure
your history is accurate!

From what you’ve described, Stat isn’t large and complicated. What’s
missing from your description?

As time goes on, stats are expected to be much more complicated.

Then refactor your design at that time. Design for what you have now,
rather than predicting the future. Remember YAGNI.

A stat
will likely have its original starting base value, its highest recorded
base
value, and a set of modifiers (which may change quite often). Possibly
more
things beyond those.

Since you don’t know yet, don’t design yet for them (your future plans
could easily change). Design a model that works for what you actually
have, and be ready to change it as necessary.

So right now, I think it is probably nearly-sanest for me to have it
delegate
nearly everything to the fixnum current value, which really is a value
object.
So it isn’t a value, but it delegates to one.

Basically, anything that has internal state to keep track of which is
not part
of how you use it strikes me as not really being a value, even if it
looks
like one from the outside.

Largely correct, although I can think of exceptions. You’ll probably
want to break this down into a composed object containing one or more
value objects.

That said!

I am thinking that perhaps it should present as immutable – that is,
I
should not define john.strength = 15 in any way, but rather, if you want
to
ask it to change its value, you have to send it messages. So instead of
john.strength += 1, you’d write john.strength.adjust_by(1).

No need. The former is a lot friendlier. You can always redefine
Character#strength= .

Hmm. I suppose the thing, then, would be to simply not provide a
strength=
method for the things that have stats.

That strikes me as silly. There’s no reason that the client class
should care whether your strength= method really does an assignment
operation.

Remember, one of the nice things about OO programming is that interface
and implementation needn’t resemble each other in the slightest.

-s

Best,

Marnen Laibow-Koser
http://www.marnen.org
[email protected]