8

I would like to change the self value of a float instance.

I have the following method :

class Float
  def round_by(precision)
    (self * 10 ** precision).round.to_f / 10 ** precision
  end
end

And I would like to add the round_by! method which will modify the self value.

class Float
  def round_by!(precision)
    self = self.round_by(precision)
  end
end

But I got an error saying I can't change the value of self.

Any idea ?

Arkan
  • 6,196
  • 3
  • 38
  • 54
  • 2
    Can you imagine if calling `x = 13.2; x.round!` caused all values of `13.2` everywhere in your application to become `13`? How unlucky that would be. – Phrogz Jan 10 '11 at 01:43

3 Answers3

11

You can't change the value of self. It always points to the current object, you can't make it point to something else.

When you want to mutate the value of an object, you either do this by calling other mutating methods or setting or changing the values of instance variables, not by trying to reassign self. However in this case, that won't help you, because Float doesn't have any mutating methods, and setting instance variables won't buy you anything, because none of the default float operations are affected by any instance variables.

So the bottom line is: you can't write mutating methods on floats, at least not in the way you want.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
2

You can also create a class and store the float in a instance variable:

class Variable

  def initialize value = nil
    @value = value
  end

  attr_accessor :value

  def method_missing *args, &blk
    @value.send(*args, &blk)
  end

  def to_s
    @value.to_s
  end

  def round_by(precision)
    (@value * 10 ** precision).round.to_f / 10 ** precision
  end

  def round_by!(precision)
    @value = round_by precision
  end
end

a = Variable.new 3.141592653

puts a           #=> 3.141592653

a.round_by! 4

puts a           #=> 3.1416

More about using "class Variable" here.

Sony Santos
  • 5,435
  • 30
  • 41
0

This is actually a really good question and I'm sorry to say that you can't - at least not with the Float class. It's immutable. My suggestion would be to create your own class the implements Float (aka inherits all the methods), like so in pseudo-code

class MyFloat < Float
  static CURRENT_FLOAT

  def do_something
    CURRENT_FLOAT = (a new float with modifications)
  end
end
Andrew Grimm
  • 78,473
  • 57
  • 200
  • 338
sethvargo
  • 26,739
  • 10
  • 86
  • 156
  • 2
    I'm not sure what `static CURRENT_FLOAT` is supposed to do, but it definitely doesn't do it. Also `CURRENT_FLOAT` is a constant and thus should not be reassigned. You probably want to use an instance variable (`@`) instead. Also since the `Float` class actually allows instance variables (since unlike Fixnum it's not an immediate value and thus not technically immutable), you don't actually need to subclass Float to do this, you can just monkey patch it. Though whether that's recommended is another issue (as a matter of fact I wouldn't recommend either and just not define a mutable method). – sepp2k Jan 09 '11 at 18:35
  • the idea was to create a static variable of the class that is a float object and then whenever you use a bang method, create a new float and set it to current_float, hence being destructive – sethvargo Jan 09 '11 at 19:37