Prevent ruby constant variables from changing?

Hi,

I understand that ruby constant variables are declared by using
uppercase letter. However, the constant variable can still be
reassigned even though a warning is issued.

Is there a way I can fix the value that is initially assigned to the
constant variable?

Thanks

···

--
Posted via http://www.ruby-forum.com/.

irb(main):014:0> CONSTANT::X
=> 100

it's a blessing in disguise; i think i may stick to this scheme. Considering how applications grow and how vars/constants clash, somehow i feel like i should qualify my constants. It's safer, and readable too. (and don't worry, there is no unfreeze in ruby :wink:

kind regards -botp

···

From: George Wang [mailto:stdcells@yahoo.com]
# Is there a way I can fix the value that is initially assigned to the
# constant variable?

arggh, ruby constants are global vars that croaks when you modify them :slight_smile:

i too had this problem, and the closest i can get is to wrap the constants in a module and then freeze the module.

eg,

botp@botp-desktop:~$ irb

irb(main):001:0> module CONSTANT
irb(main):002:1> X=1
irb(main):003:1> Y=2
irb(main):004:1> Z="test"
irb(main):005:1> end
=> "test"

irb(main):006:0> CONSTANT.constants
=> ["Z", "Y", "X"]

irb(main):008:0> CONSTANT::X
=> 1

irb(main):009:0> CONSTANT::X = 100
(irb):9: warning: already initialized constant X
=> 100

irb(main):010:0> CONSTANT::X
=> 100

irb(main):011:0> CONSTANT.freeze
=> CONSTANT

irb(main):012:0> CONSTANT::X
=> 100

irb(main):013:0> CONSTANT::X = 99
TypeError: can't modify frozen module
        from (irb):13
        from :0

George Wang wrote:

However, the constant variable can still be
reassigned even though a warning is issued.

Am I the only person who thinks that constants should be unchangeable?

Being new to Ruby, it seems weird to me that constants aren't actually
constant. I'm sure there must be some arcane reason for it, but surely
most people want their constants to remain constant! That's how it works
in most languages.

Freezing would seem like a good idea but I haven't actually tried it.
Yet.

···

--
Posted via http://www.ruby-forum.com/\.

If you noticed, class names are constants. As you can change classes at runtime, constants must be changable.
Actually overwriting Constants emits a warning. A you should program warnings-free, that should be no problem :).

Regards,
Florian Gilcher

···

On May 22, 2008, at 1:01 PM, Dave Bass wrote:

George Wang wrote:

However, the constant variable can still be
reassigned even though a warning is issued.

Am I the only person who thinks that constants should be unchangeable?

Being new to Ruby, it seems weird to me that constants aren't actually
constant. I'm sure there must be some arcane reason for it, but surely
most people want their constants to remain constant! That's how it works
in most languages.

Freezing would seem like a good idea but I haven't actually tried it.
Yet.
--
Posted via http://www.ruby-forum.com/\.

George Wang wrote:

However, the constant variable can still be
reassigned even though a warning is issued.

Am I the only person who thinks that constants should be unchangeable?

Probably not. However, there are more spots like this in Ruby (e.g. private methods). It is a general feature of the language to not be too restrictive about such things. For me this was never an issue. YMMV though. OTOH this makes some things (mostly related to meta programming) pretty easy that are hard to impossible in other languages. For example, if you want to write code in Java that modifies arbitrary private instance variables, you can do it but it's much more involved than using #instance_variable_set. It's probably good that it is not made too easy in Java - and equally good that it's the way it is in Ruby.

Being new to Ruby, it seems weird to me that constants aren't actually constant. I'm sure there must be some arcane reason for it, but surely most people want their constants to remain constant! That's how it works in most languages.

Freezing would seem like a good idea but I haven't actually tried it. Yet.

Freezing does something else: freezing prohibits assigning to and creation of instance variables. This helps if you want to use an instance of an otherwise mutable class as constant.

I agree with Pena that the safest approach is probably the one he demonstrated.

Kind regards

  robert

···

On 22.05.2008 13:01, Dave Bass wrote:

i'm sure you're aware but:

cfp:~ > cat a.rb
(

   module Namespace
     X = 4
     Y = 2
   end

).freeze

Object.send :remove_const, :Namespace

Namespace = Module.new
Namespace::X = 2
Namespace::Y = 4

puts Namespace::Y, Namespace::X

cfp:~ > ruby a.rb
4
2

it's hard to get around the dynamic aspects of ruby (thankfully) :wink:

a @ http://codeforpeople.com/

···

On May 22, 2008, at 1:49 AM, Peña, Botp wrote:

i too had this problem, and the closest i can get is to wrap the constants in a module and then freeze the module.

--
we can deny everything, except that we have the possibility of being better. simply reflect on that.
h.h. the 14th dalai lama

Interesting new knowledge for me when I test this out. I didn't know that what
is returned from the end of a class ... end and module .. end block is NilClass.

  % cat x.rb
  module C
    X = 42
  end.freeze

  puts "C::X => #{C::X}"
  C::X = 99

  puts "C::X => #{C::X}"
  C.freeze
  C::X = 42

  puts "C::X => #{C::X}"

  % ruby x.rb
  C::X => 42
  x.rb:6: warning: already initialized constant X
  C::X => 99
  x.rb:10: can't modify frozen module (TypeError)

Hmm... lets look at what is returned by the end of a module and a class

% cat c.rb
c = class C; end
puts c.inspect

m = module M; end
puts m.inspect

% ruby c.rb
nil
nil

You learn something new every day.

enjoy,

-jeremy

···

On Thu, May 22, 2008 at 04:49:32PM +0900, Pe??a, Botp wrote:

From: George Wang [mailto:stdcells@yahoo.com]

i too had this problem, and the closest i can get is to wrap the constants in
a module and then freeze the module.

--

Jeremy Hinegardner jeremy@hinegardner.org

Peña, Botp wrote:

i too had this problem, and the closest i can get is to wrap the
constants in a module and then freeze the module.

I was inspired by Perl's use of subroutines as wrappers for constants to
come up with the following technique. It doesn't involve modules or
freezing:

irb(main):001:0> def self.Const
irb(main):002:1> 1
irb(main):003:1> end
=> nil
irb(main):004:0> self.Const
=> 1
irb(main):005:0> self.Const = 2
NoMethodError: undefined method `Const=' for main:Object
        from (irb):5
irb(main):006:0> self.Const
=> 1

Anyone see problems? It at least avoids accidental modification of a
constant, and it's simple.

···

--
Posted via http://www.ruby-forum.com/\.

Hi,

Thanks to everyone for their helpful replies. Actually I want to be
able to encapsulate a variable which is a Firefox browser instance.

I tried the following but to no avail. Any ideas?

irb(main):001:0> require 'firewatir'
irb(main):002:0> include FireWatir
irb(main):003:0> module CONSTANT
irb(main):004:0> browser=FireWatir::Firefox.start('http://1.2.3.4/'\)
irb(main):005:0> end
irb(main):006:0> CONSTANT.constants
=>
irb(main):007:0> CONSTANT::browser
NoMethodError: undefined method 'browser' for CONSTANT::Module
        from (irb):7

George

Peña, Botp wrote:

···

From: George Wang [mailto:stdcells@yahoo.com]
# Is there a way I can fix the value that is initially assigned to the
# constant variable?

arggh, ruby constants are global vars that croaks when you modify them
:slight_smile:

i too had this problem, and the closest i can get is to wrap the
constants in a module and then freeze the module.

eg,

botp@botp-desktop:~$ irb

irb(main):001:0> module CONSTANT
irb(main):002:1> X=1
irb(main):003:1> Y=2
irb(main):004:1> Z="test"
irb(main):005:1> end
=> "test"

irb(main):006:0> CONSTANT.constants
=> ["Z", "Y", "X"]

irb(main):008:0> CONSTANT::X
=> 1

irb(main):009:0> CONSTANT::X = 100
(irb):9: warning: already initialized constant X
=> 100

irb(main):010:0> CONSTANT::X
=> 100

irb(main):011:0> CONSTANT.freeze
=> CONSTANT

irb(main):012:0> CONSTANT::X
=> 100

irb(main):013:0> CONSTANT::X = 99
TypeError: can't modify frozen module
        from (irb):13
        from :0

irb(main):014:0> CONSTANT::X
=> 100

it's a blessing in disguise; i think i may stick to this scheme.
Considering how applications grow and how vars/constants clash, somehow
i feel like i should qualify my constants. It's safer, and readable too.
(and don't worry, there is no unfreeze in ruby :wink:

kind regards -botp

--
Posted via http://www.ruby-forum.com/\.

If you noticed, class names are constants. As you can change classes at runtime, constants must be changable.

No, not necessarily: you can change a class without reassignment to the constant.

Actually overwriting Constants emits a warning. A you should program warnings-free, that should be no problem :).

At least it's a good guiding rule to follow.

Kind regards

  robert

···

On 22.05.2008 13:38, Florian Gilcher wrote:

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

George Wang wrote:

However, the constant variable can still be
reassigned even though a warning is issued.

Am I the only person who thinks that constants should be unchangeable?

Being new to Ruby, it seems weird to me that constants aren't actually
constant. I'm sure there must be some arcane reason for it, but surely
most people want their constants to remain constant! That's how it works
in most languages.

Freezing would seem like a good idea but I haven't actually tried it.
Yet.
--
Posted via http://www.ruby-forum.com/\.

If you noticed, class names are constants.

Not necessarily.
c = Class::new { def ... }

As you can change classes at
runtime, constants must be changable.

Not at all, you can always change the object a constant points to,
unless it is frozen.
Robert

···

On Thu, May 22, 2008 at 1:38 PM, Florian Gilcher <flo@andersground.net> wrote:

On May 22, 2008, at 1:01 PM, Dave Bass wrote:

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Robert Klemme wrote:

It is a general feature of the language to not be too
restrictive about such things.

Maybe we could have the option of generating an error rather than a
warning if a constant is changed. Maybe there's some way to do this
already (raising an exception)?

···

--
Posted via http://www.ruby-forum.com/\.

Sure, you can change classes at runtime, but should you be able to change which object is referenced by a class name? I haven't heard of that before. Do you have a real-world example of someone doing that? Just curious.

///ark

···

On May 22, 2008, at 4:38 AM, Florian Gilcher wrote:

If you noticed, class names are constants. As you can change classes at runtime, constants must be changable.
Actually overwriting Constants emits a warning. A you should program warnings-free, that should be no problem :).

Class names are strings.

The name of an anonymous class is an empty string.

The first time a class is assigned to a constant gets its name from
the constant identifier.

That happens automatically behind the scenes the first time you say class Foo.

Once a class gets its name the container where the class object lives
is irrelevant, the name is set in stone.

Normally constant User holds a class named "User", but technically it
could store a class named "Project".

Apart from those rules, constants and class objects are kind of
decoupled because they are just basic pieces of Ruby put together.

Jeremy Hinegardner wrote:

I didn't know that what
is returned from the end of a class ... end and module .. end block is
NilClass.

It's not. A class/module ... end block returns the value of the last
expression in it. So
module C
  X = 42
end.freeze
calls freeze on 42

HTH,
Sebastian

···

--
NP: Depeche Mode - Master And Servant
Jabber: sepp2k@jabber.org
ICQ: 205544826

Dave Bass wrote:

Peña, Botp wrote:

i too had this problem, and the closest i can get is to wrap the constants in a module and then freeze the module.

I was inspired by Perl's use of subroutines as wrappers for constants to come up with the following technique. It doesn't involve modules or freezing:

irb(main):001:0> def self.Const
irb(main):002:1> 1
irb(main):003:1> end
=> nil
irb(main):004:0> self.Const
=> 1
irb(main):005:0> self.Const = 2
NoMethodError: undefined method `Const=' for main:Object
        from (irb):5
irb(main):006:0> self.Const
=> 1

Anyone see problems? It at least avoids accidental modification of a constant, and it's simple.

you have to stick to the self.Const syntax though.

def self.Const; 1; end
Const = 2
p Const

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

So how does the creation of an anonymous class hurt the argument that class names are constants?

···

On May 22, 2008, at 2:36 PM, Robert Dober wrote:

If you noticed, class names are constants.

Not necessarily.
c = Class::new { def ... }

"Hot code replace" comes to my mind. Completely reloading a class while keeping the system running. There, it makes sense to completely obliterate the old class.

Actually, this is how the RoR class-reloading in development mode works. They clear all loaded application classes so that they are loaded again by the classloader upon need. (via const_missing)

About "class name". Yes, #name is just a method. So is #instance_eval and #type and almost every other method. So you could argue that there is no such thing as evaluation in an instance context or a type as language features. On that standpoint, you could argue that there are no classes in ruby, because Ruby only exists of undefinable masses:

···

On May 22, 2008, at 6:51 PM, Mark Wilden wrote:

On May 22, 2008, at 4:38 AM, Florian Gilcher wrote:

If you noticed, class names are constants. As you can change classes at runtime, constants must be changable.
Actually overwriting Constants emits a warning. A you should program warnings-free, that should be no problem :).

Sure, you can change classes at runtime, but should you be able to change which object is referenced by a class name? I haven't heard of that before. Do you have a real-world example of someone doing that? Just curious.

///ark

===
class Object
   def class
     "undefinable mass"
   end
end

Lets put it like that: In most sane Ruby systems, #name is either the name of the constant a class was bound to or "", the first being named (with a "class name"), the other one anonymous (or call it "ad-hoc", if you prefer). Also, the inability of #name to tell you the internal name of a class doesn't mean that it doesn't have one. This may be a verbal convention and not be enforcemed by the interpreter, but it is a common and reasonable concept. I see no use in oh-so-cool nitpicking that makes it much harder for not-so-zen rubyists to follow discussions.

Regards,
Florian Gilcher

Jeremy Hinegardner wrote:

I didn't know that what
is returned from the end of a class ... end and module .. end block is
NilClass.

It's not. A class/module ... end block returns the value of the last
expression in it. So
module C
X = 42
end.freeze
calls freeze on 42

Now I am a big user of 42 but you surely made a mistake here, freeze
has to be called on 32, right? (Hint: here in Europe we rather call it
on 0).
Well this is offtopic, let us get ontopic again :wink:
I feel it is interesting how many different views we got here on the subject...

look at these semantics
517/17 > irb
irb(main):001:0> class A
irb(main):002:1> end
=> nil
irb(main):003:0> B = A
=> A
irb(main):004:0> class B
irb(main):005:1> def a; 42 end
irb(main):006:1> end
=> nil
irb(main):007:0> A.new.a
=> 42
irb(main):008:0> B.name
=> "A"

I just feel to think more seriously now never to use "class X" again,
I want to avoid the very subtle inconsistencies it implies but I
really hate, that after

C = Class::new
C.name equals "C".
This is the first time ever since I discovered that blocks cannot have
block parameters that I feel that Ruby stands in my way, no it is
worse, Ruby overrules me, decides for me, that is *soooo* untypical
for Ruby. And furthermore the former went away in 1.9 while the later
did not. I guess I will write an RCR right away.

You cannot even trick the parser!!!

irb(main):001:0> C = _ = Class::new
=> C
irb(main):002:0> C.name
=> "C"

but finally

irb(main):006:0> _ = Class::new
=> #<Class:0xb7d5af90>
irb(main):007:0> _.name
=> ""
irb(main):008:0> X = _
=> ""
irb(main):009:0> X.name
NoMethodError: undefined method `name' for "":String
        from (irb):9
irb(main):010:0>

I get where I wanted :).

···

On Thu, May 22, 2008 at 11:12 PM, Sebastian Hungerecker <sepp2k@googlemail.com> wrote:
        from :0

HTH,
Sebastian
--
NP: Depeche Mode - Master And Servant
Jabber: sepp2k@jabber.org
ICQ: 205544826

--
http://ruby-smalltalk.blogspot.com/

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Joel VanderWerf wrote:

you have to stick to the self.Const syntax though.

Yes indeed, self.Const and Const are two different objects.

Also you can redefine self.Const at any time (using def). So it's by no
means a perfect solution.

···

--
Posted via http://www.ruby-forum.com/\.