bryantsai
bryantsai

Reputation: 3455

What does Ruby constant mean?

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?

Upvotes: 5

Views: 3580

Answers (6)

Daniel
Daniel

Reputation: 15483

If you're coming from other programming languages, Ruby handles constants differently than what you may be used to. Constants, in general, take values that do not change through the entire application. The syntax is to use all capital letters while naming your constant so that the application knows how to handle it. For example, to set a constant to hold a baseball team you would declare it this way:

TEAM = "Angels"

I know you know this much, bear with me here. Typically, other programming languages will not allow you to change the value of TEAM. However, Ruby does not hold you back and takes the last value assigned to the constant. In the above example, I can change its value to:

TEAM = "Athletics"

Other programming languages would either throw an error or would print the value of Angels. However, Ruby prints the value Athletics because that is the last value assigned to the variable TEAM. Also, it gives a warning message that says that the constant was already initialized and was changed because changing a constant is considered a poor programming practice. But, it still allows you to make the change and follows the Ruby convention of trusting the developer to make the right programming decision. So, be careful while using constants in Ruby since they can be overridden.

Upvotes: 0

BrunoF
BrunoF

Reputation: 3543

Constants are used to store values that should not be changed. Their names must start with an uppercase letter. By convention, most constant names are written in all uppercase letters with an underscore as word separator, such as SOME_CONSTANT.

Constants defined within classes can be accessed by all methods of that class. Those created outside a class can be accessed globally (within any method or class).

class Car
  WHEELS = 4

  def initialize
    puts WHEELS
  end
end

c = Car.new     # Output: 4

Note that Ruby does not stop us from changing the value of a constant, it only issues a warning.

SOME_CONSTANT = "foo"
SOME_CONSTANT = "bar"
warning: already initialized constant SOME_CONSTANT
warning: previous definition of SOME_CONSTANT was here

In Ruby, all class and module names are constants, but convention dictates they should be written in camel case, such as SomeClass.

Constants can be accessed from outside the class, even within another class, by using the :: (double colon) operator. To access the WHEELS constant from outside the Car class, we would use Car::WHEELS. The :: operator allows constants, public instance methods and class methods to be accessed from outside the class or module on which they are defined.

A built-in method called private_constant makes constants private (accessible only within the class on which they were created). The syntax is as follows:

class Car
  WHEELS = 4

  private_constant:WHEELS
end

Car::WHEELS    # Output: NameError: private constant Car::WHEELS referenced

Upvotes: 0

John Feminella
John Feminella

Reputation: 311735

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"

Upvotes: 4

horseyguy
horseyguy

Reputation: 29915

"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/

Upvotes: 1

Pablo Fernandez
Pablo Fernandez

Reputation: 105258

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.

Upvotes: 14

Splat
Splat

Reputation: 763

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

Upvotes: 8

Related Questions