# Can you enable coercion between types?

**URL:** <https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268>\
**Category:** Ruby\
**Created:** [March 18, 2006, 8:50pm UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268 "2006-03-18T20:50:40Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 18, 2006, 8:50pm UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/1 "2006-03-18T20:50:40Z")

</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:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 19, 2006, 1:35am UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/2 "2006-03-19T01:35:28Z")

</div>

On Sun, 19 Mar 2006, larry wrote:

> larry  
> try this:

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

 p(40.0 + Duration::new(2.0))
 p(40 + Duration::new(2))

 harp:~ > ruby a.rb
 42.0
 42

```

hth.

-a

---

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 19, 2006, 2:20am UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/3 "2006-03-19T02:20:58Z")

</div>

removed\_email\_address@domain.invalid wrote:

> ```
> else
> [Float(@seconds), Float(other)]
> end
> end
> end
> 
> ```

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

Thanks,  
T.

---

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 18, 2006, 9:24pm UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/4 "2006-03-18T21:24:09Z")

</div>

Did you try #to\_f?

T.

---

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 19, 2006, 3:27am UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/5 "2006-03-19T03:27:22Z")

</div>

On Sun, 19 Mar 2006, Trans wrote:

> > ```
> > if other.class == @seconds.class
> > [@seconds, other]
> > else
> > [Float(@seconds), Float(other)]
> > end
> > end
> > end
> > 
> > ```
> 
> Could you explain what this is doing? I don’t get the effect.

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

def + other  
x, y = other.coerce self  
x + y  
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

duration = Duration::new 42.0

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:

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

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

 harp:~ > ruby a.rb
 42.0
 42
 42.0
 42.0
 42
 42.0
 42.0
 42.0

```

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

regards.

-a

---

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 19, 2006, 7:29am UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/6 "2006-03-19T07:29:54Z")

</div>

On Sat, 2006-03-18 at 17:11, removed\_email\_address@domain.invalid wrote:

> ```
> else
> [Float(@seconds), Float(other)]
> end
> 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.

–MarkusQ

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

---

<div class="post-metadata">

**Author:** ![larry](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/l/47e85d/32.png) [@larry](https://www.ruby-forum.com/u/larry)\
**Post date:** [March 19, 2006, 4:20pm UTC](https://www.ruby-forum.com/t/can-you-enable-coercion-between-types/55268/7 "2006-03-19T16:20:34Z")

</div>

On Sun, 19 Mar 2006, Markus wrote:

> > ```
> > if other.class == @seconds.class
> > 
> > ```
> 
> 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.

indeed. good catch.

cheers.  
-a
