tags:

views:

252

answers:

4

What does Ruby constants really mean? The following code doesn't show any 'constant' attribute. The warning is there, but I still get to change what A refers to.

A = 1
puts A # => 1
A = 2  # warning: already initialized constant A
puts A # => 2

Or is Ruby constants are just an indication without any enforcement?

+3  A: 

That's right -- assigning to a constant is a warning, not an error; "constants" are just an indicator of how you should use something, not a rule that you do use it that way.

That may sound horrendous coming from a static-programming world, but it's immensely useful in various metaprogramming facilities, and it enables things that would otherwise be completely impossible in static languages.

That said, if you really want to make sure people keep their grubby hands off your references, you can use Object#freeze. It's still okay to change what a reference points to with this; you just can't change the contents of the reference itself:

irb(main):001:0> class Fruit; attr_accessor :name; end
=> nil
irb(main):002:0> f = Fruit.new
=> #<Fruit:0xb7e06570>
irb(main):003:0> f.name = "apple"
=> "apple"
irb(main):004:0> f.freeze                # After freeze, can't touch this Fruit.
=> #<Fruit:0xb7e06570 @name="apple">
irb(main):005:0> f.name = "banana"
TypeError: can't modify frozen object    # Kablammo!
    from (irb):5:in `name='
    from (irb):5

But this is okay:

irb(main):006:0> f = Fruit.new
=> #<Fruit:0xb7dfed84>
irb(main):007:0> f.name = "banana"
=> "banana"
John Feminella
In your example the _constant_ would be `Fruit`. So it should be `Fruit.freeze` instead of `f.freeze`
Pablo Fernandez
Right, but I think the OP was implicitly asking how to make a value immutable once it's been created. Constants don't do that; `freeze` does (and you can use `freeze` on any object).
John Feminella
Don't you mean "Assigning to a constant is a warning, not an error"?
Andrew Grimm
@Andrew: Yep! Thanks for the correction.
John Feminella
+3  A: 

That's right, constants are just like variables in ruby, but you get a warning if you change them.

Also, there's one difference with mere variables: You can access constants even if they are defined inside another class or module, for example given this snippet:

module Constants
  PI = 3,1415
  other = "variable"
end

You can reach PI doing Constants::PI while Constants::other will not work.

Pablo Fernandez
this explanation is too over-simplified. The lookup rules for constants are completely different to those of ordinary variables, see my answer below for a link to a blog post explaining this
banister
The question was simple, and @bryantsai was looking for a simple answer. Note that the accepted answer is even more simpler than mine
Pablo Fernandez
@Pablo, yours is currently the accepted answer (look at the green tick) - that's why im picking on you ;)
banister
I meant the most up-voted answer :) sorry
Pablo Fernandez
+6  A: 

Yes, Ruby constants aren't enforced, other than printing that warning.

Splat
+2  A: 

"Constant" is really a misnomer, the most important aspect of Ruby's "Constants" is not their immutability but their lookup rules.

see: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/

banister