# Can you enable coercion between types?

**URL:** <https://rubytalk.org/t/can-you-enable-coercion-between-types/25895>\
**Category:** ruby-talk\
**Created:** [18 March 2006 19:48 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895 "2006-03-18T19:48:49Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Larry\_White](https://avatars.discourse-cdn.com/v4/letter/l/ebca7d/32.png) [@Larry\_White](https://rubytalk.org/u/Larry_White)\
**Post date:** [18 March 2006 19:48 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/1 "2006-03-18T19:48:49Z")

</div>

I have a ruby class called Duration that represents a unit of time.  
It's main attribute is a number that represents the duration in  
seconds.

If I try to save it to a DB using Rails, I get a "Duration can not be  
coerced into Float" error. Is there a way to modify the definition of  
Duration to enable automatic coercion into a float? (I'm thinking of  
something like adding a "to\_float" method to the class.)

thanks in advance  
larry

---

<div class="post-metadata">

**Author:** ![7rans](https://avatars.discourse-cdn.com/v4/letter/7/a8b319/32.png) [@7rans](https://rubytalk.org/u/7rans)\
**Post date:** [18 March 2006 20:23 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/2 "2006-03-18T20:23:49Z")

</div>

Did you try #to\_f?

T.

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [18 March 2006 23:11 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/3 "2006-03-18T23:11:59Z")

</div>

try this:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p(40.0 + Duration::new(2.0))  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p(40 + Duration::new(2))

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> ruby a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42

hth.

-a

> **···**
>
> On Sun, 19 Mar 2006, larry wrote:
> 
> > I have a ruby class called Duration that represents a unit of time.  
> > It's main attribute is a number that represents the duration in  
> > seconds.
> > 
> > If I try to save it to a DB using Rails, I get a "Duration can not be  
> > coerced into Float" error. Is there a way to modify the definition of  
> > Duration to enable automatic coercion into a float? (I'm thinking of  
> > something like adding a "to\_float" method to the class.)
> > 
> > thanks in advance  
> > larry
> 
> --  
> share your knowledge. it's a way to achieve immortality.  
> - h.h. the 14th dali lama

---

<div class="post-metadata">

**Author:** ![7rans](https://avatars.discourse-cdn.com/v4/letter/7/a8b319/32.png) [@7rans](https://rubytalk.org/u/7rans)\
**Post date:** [19 March 2006 01:18 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/4 "2006-03-19T01:18:48Z")

</div>

Could you explain what this is doing? I don't get the effect.

Thanks,  
T.

> **···**
>
> ara.t.howard@noaa.gov wrote:
> 
> > try this:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

---

<div class="post-metadata">

**Author:** ![Markus](https://avatars.discourse-cdn.com/v4/letter/m/b782af/32.png) [@Markus](https://rubytalk.org/u/Markus)\
**Post date:** [19 March 2006 05:20 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/5 "2006-03-19T05:20:28Z")

</div>

There's a gottcha here. Coerce is used to implement double dispatch and  
so needs to return the coerced values in the opposite order (see Pick  
Axe)--(other,self), not (self,other).

The way you wrote it works fine for addition & multiplication, but  
you'll pull your hair out the first time you try to subtract or divide.

--MarkusQ

P.S. And I think (as Tom noted) that "to\_f" was the answer to the  
original question.

> **···**
>
> On Sat, 2006-03-18 at 17:11, ara.t.howard@noaa.gov wrote:
> 
> > try this:
> > 
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [19 March 2006 02:25 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/6 "2006-03-19T02:25:04Z")

</div>

my understanding of coerce is that it's used to produce a pair of operands -  
myself and other - which can be used to perform operations.

so, in the case of Fixnum#+ we might see

&nbsp;&nbsp;&nbsp;def + other  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x, y = other.coerce self  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x + y  
&nbsp;&nbsp;&nbsp;end

which is to say Fixnum need not know about how to add every possible class -  
rather it leaves that knowledge up to those classes to export via thier coerce  
method. as i understand it that method should return two new objects which  
interoperate so, in the case above (which is made up) we might have

&nbsp;&nbsp;&nbsp;duration = Duration::new 42.0

&nbsp;&nbsp;&nbsp;42 + duration

here would call duration(42) and expect back an x and y which could be added  
together. so, if @seconds happens to be a Fixnum the result will be another  
Fixnum. if @seconds happens to a Float the result would be a Float.

i admit that i'm not crystal clear on this, but it sure seems to work:

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def + other  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x, y = coerce(other)  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;x + y  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def Duration(\*a, &b); Duration::new(\*a, &b); end

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( 40 + Duration(2.0) ) # Float 42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( 40 + Duration(2) ) # Fixnum 42  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( 40.0 + Duration(2.0) ) # Float 42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( 40.0 + Duration(2) ) # Float 42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( Duration(40) + 2 ) # Fixnum 42  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( Duration(40) + 2.0 ) # Float 42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( Duration(40.0) + 2) # Float 42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p( Duration(40.0) + 2.0 ) # Float 42.0

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> ruby a.rb  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42.0  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;42.0

i assume one would do something nice with the coerce method using Time, Date,  
and DateTime objects too...

regards.

-a

> **···**
>
> On Sun, 19 Mar 2006, Trans wrote:
> 
> > ara.t.howard@noaa.gov wrote:
> > 
> > > try this:
> > > 
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > Could you explain what this is doing? I don't get the effect.
> 
> --  
> share your knowledge. it's a way to achieve immortality.  
> - h.h. the 14th dali lama

---

<div class="post-metadata">

**Author:** ![Ara.T.Howard6](https://avatars.discourse-cdn.com/v4/letter/a/958977/32.png) [@Ara.T.Howard6](https://rubytalk.org/u/Ara.T.Howard6)\
**Post date:** [19 March 2006 15:20 UTC](https://rubytalk.org/t/can-you-enable-coercion-between-types/25895/7 "2006-03-19T15:20:15Z")

</div>

indeed. good catch.

cheers.  
-a

> **···**
>
> On Sun, 19 Mar 2006, Markus wrote:
> 
> > On Sat, 2006-03-18 at 17:11, ara.t.howard@noaa.gov wrote:
> > 
> > > try this:
> > > 
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;harp:~ \> cat a.rb  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class Duration  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def initialize seconds  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@seconds = seconds  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def coerce other  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if other.class == @seconds.class  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[@seconds, other]  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[Float(@seconds), Float(other)]  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end  
> > > &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end
> > 
> > There's a gottcha here. Coerce is used to implement double dispatch and  
> > so needs to return the coerced values in the opposite order (see Pick  
> > Axe)--(other,self), not (self,other).
> > 
> > The way you wrote it works fine for addition & multiplication, but  
> > you'll pull your hair out the first time you try to subtract or divide.
> 
> --  
> share your knowledge. it's a way to achieve immortality.  
> - h.h. the 14th dali lama
