Seebs wrote: > I'm pretty sure I really do want to have these things have non-trivial > internal state. That's fine - make each individual attribute be an object. But you also want these stats to appear to be readable and writable as if they were vanilla integers. I think I'd do this by hiding this behavior in the parent class, the Character which owns the Stats. class Stat attr_reader :val def initialize(val=0, max_val=val) @val, @max_val = val, max_val end def val=(x) @val = x @max_val = x if x > @max_val end def restore @val = @max_val end def to_i @val end end class Character attr_reader :name def initialize(name) @name = name end def str_stat @str_stat ||= Stat.new end def str str_stat.val end def str=(v) str_stat.val = v.to_i end def dex; 0; end # placeholder def con; 0; end # placeholder def level str + dex + con end end c = Character.new("Ogre") c.str = 14 # => 14 puts c.level c.str = 8 # => 8 puts c.level c.str_stat.restore puts c.level # => 14 The points I'm trying to make here are: 1. Whilst you want the individual stats to behave as integers, you probably don't want the entire Character to behave as an integer - the Character is likely to have many other attributes, such as 'name' in the above example. So, whenever you deal with individual stats, you are always going to do c.str or c.str=val. This is a convenient place to masquerade the Stat. 2. When you set the strength of a character, you don't want to replace the entire Stat object, you want to update its state so it can retain history. So when you write c.str = x then really you don't want to replace the strength Stat object inside c; you are sending a message to it to update its state. If you use the code I've shown above, then it avoids you having to write c.str.val = x which is what you'd have to do if c.str returned the Stat object itself. 3. When dealing with the Character, I think you will infrequently want to deal with the underlying Stat object directly, but I have added an accessor (str_stat) to allow this if you need it. With sufficient proxy methods you could hide the underlying Stat objects entirely: e.g. class Character def restore_strength @str_stat.restore end end You can still make the character objects be Comparable, if normally you want to order them by level. class Character include Comparable def <=>(other) level <=> other.level end end And if you really want to, you can define to_int and method_missing so that the entire Character resolves to its level value. But I think this is more likely to be confusing rather than helpful. If you ever want to do arithmetic on levels, I think it would be clearer to see "ogre.level - elf.level" rather than "ogre - elf", because ogres have more attributes than just their level. In other words, ogres are like onions :-) Regards, Brian. -- Posted via http://www.ruby-forum.com/.