Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Newbie question: Defining a numeric type

Reply
Thread Tools

Newbie question: Defining a numeric type

 
 
Seebs
Guest
Posts: n/a
 
      11-15-2009
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 <op>(other)
self.to_i <op> 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
--
Copyright 2009, all wrongs reversed. Peter Seebach / http://www.velocityreviews.com/forums/(E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
 
Mario Camou
Guest
Posts: n/a
 
      11-16-2009
Have a look at Forwardable

On Monday, November 16, 2009, Seebs <(E-Mail Removed)> wrote:
> I have a type which has a bit of internal magic, but fundamentally, I wan=

t
> 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:
> =A0 =A0 =A0 =A0def <op>(other)
> =A0 =A0 =A0 =A0 =A0self.to_i <op> other
> =A0 =A0 =A0 =A0end
>
> I think I'm thinking something like the Comparable mixin; sort of a
> "I have a to_i, make me a number" module.
>
> -s
> --
> Copyright 2009, all wrongs reversed. =A0Peter Seebach / usenet-nospam@see=

bs.net
> http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
> http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
>
>


--=20
-Mario.

--
I want to change the world but they won't give me the source code.

 
Reply With Quote
 
 
 
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-16-2009
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 <op>(other)
> self.to_i <op> 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
(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-16-2009
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 <op>(other)
> self.to_i <op> 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
(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      11-16-2009
On 2009-11-16, Marnen Laibow-Koser <(E-Mail Removed)> 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
--
Copyright 2009, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-16-2009
Seebs wrote:
> On 2009-11-16, Marnen Laibow-Koser <(E-Mail Removed)> 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
(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Brian Candler
Guest
Posts: n/a
 
      11-16-2009
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.
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-16-2009
Seebs wrote:
> On 2009-11-16, Marnen Laibow-Koser <(E-Mail Removed)> 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
(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      11-16-2009
On 2009-11-16, Marnen Laibow-Koser <(E-Mail Removed)> 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.)


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


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
--
Copyright 2009, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      11-16-2009
On 2009-11-16, Marnen Laibow-Koser <(E-Mail Removed)> 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.)


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


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
--
Copyright 2009, all wrongs reversed. Peter Seebach / (E-Mail Removed)
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Defining iterator type through container object type Urs Thuermann C++ 6 11-04-2011 02:10 PM
int to numeric numeric(18,2) ? jobs ASP .Net 2 07-22-2007 12:32 AM
Arithmetic overflow error converting numeric to data type numeric. darrel ASP .Net 4 07-19-2007 09:57 PM
check if string contains numeric, and check string length of numeric value ief@specialfruit.be C++ 5 06-30-2005 01:08 PM
defining or not defining destructors johny smith C++ 8 07-02-2004 08:51 AM



Advertisments