Prevent ruby constant variables from changing?

G

George Wang

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
 
D

Dave Bass

George said:
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.
 
F

Florian Gilcher

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


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.

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
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkg1WvgACgkQJA/zY0IIRZYmkQCeJvyw4XwGA2+sYWN8RdYt+F/7
1pkAn3pRTl129HoSddfetPJhyji3gBg/
=8BGR
-----END PGP SIGNATURE-----
 
R

Robert Klemme

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
 
R

Robert Klemme

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
 
R

Robert Dober

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




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
 
F

Florian Gilcher

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


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


So how does the creation of an anonymous class hurt the argument that
class names are constants?
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkg1cSMACgkQJA/zY0IIRZaVYACfYKNZSIRdk1IUeEVSgCAMhto6
vP8An25z7xkB0HzOwszj8U6zlocudryQ
=oNYV
-----END PGP SIGNATURE-----
 
A

ara.t.howard

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


it's not not anonymous, it's held in a variable, just as normal
classes are

c = Class.new

class C; end

C = Class.new

it's subtle, but there is no such thing as a 'class name', rather
there are classes that a held in variables, often these variables are
constants, but not always, and it is true that ruby give you the
illusion that they are names via a handy Class#name method, but note
that this is really just inspect and not specific to classes:

cfp:~ > ruby -e 'class C;end; module M;end; p C.name; p C; p
M.name; p M'
"C"
C
"M"
M


the name is not special, just a method:

cfp:~ > ruby -e' class C;end; Constant = C; p Constant.name; def
Constant.name; "Constant"; end; p Constant.name '
"C"
"Constant"

regards.

a @ http://codeforpeople.com/
 
A

ara.t.howard

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

i'm sure you're aware but:

cfp:~ > cat a.rb
(

module Namespace
X =3D 4
Y =3D 2
end

).freeze

Object.send :remove_const, :Namespace

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

puts Namespace::Y, Namespace::X

cfp:~ > ruby a.rb
4
2



it's hard to get around the dynamic aspects of ruby (thankfully) ;-)

a @ http://codeforpeople.com/
 
R

Robert Dober

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





So how does the creation of an anonymous class hurt the argument that class
names are constants?
I will try to answer your question with another one.
What is the name of the class above? Well it is "", would you say this
is a constant?
This however is not what was most missleading. It does not matter if a
constant is pointing to a class or not, class names are not constants
at all, there is just this little quirck in Ruby that
X = Class::new
sets X.name to "X" by some magic.
This allows to reopen the class with
class X
instead of writing
c.module_eval

c.module_eval creates faster code though...

Cheers
Robert
 
R

Robert Dober

it's subtle, but there is no such thing as a 'class name', rather there are
classes that a held in variables, often these variables are constants, but
not always, and it is true that ruby give you the illusion that they are
names via a handy Class#name method, but note that this is really just
inspect and not specific to classes:
Hmm Ara, are you sure?
Is it not the interpreter that "quirks", as I have put it, the name of
a class when it is assigned to a constant, either via
class Klass
but also via
Klass = Class::new
while it quirks it to "" if we do
c = Class::new

I think it is a mess, after reading your metakoan Rubyquiz I should
never ever have used constants to point to classes anymore, I am a
weakling ;)
Cheers
Robert
 
A

ara.t.howard

Hmm Ara, are you sure?
Is it not the interpreter that "quirks", as I have put it, the name of
a class when it is assigned to a constant, either via
class Klass
but also via
Klass = Class::new
while it quirks it to "" if we do
c = Class::new

heh - point taken. i think we are saying the same thing: the concept
of a class 'name' is quite fragile.

I think it is a mess, after reading your metakoan Rubyquiz I should
never ever have used constants to point to classes anymore, I am a
weakling ;)


lol - well, like many things in ruby it's quite 'human' feeling quite
natural yet containing some internal contradiction. i guess the main
point is that we all seem to find it fairly natural to use - that
counts for something.

cheers.

a @ http://codeforpeople.com/
 
D

Dave Bass

Robert said:
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)?
 
R

Robert Dober

really? that's interesting.
You are right I better recheck that ...
... indeed I was wrong, I just increased N from 10**5 to 10**6 and
that equals out what must have been measurement fluctations caused by
the extremely short runtime.
The performance is equal.

require 'benchmark'

class A
def a; 42 end
end
a = A.new
B = Class::new
B.module_eval do
def a; 42 end
end
b = B.new

N=100_000

Benchmark::bmbm do |bm|
bm.report( "classic" ) do
N.times do
a.a
end
end
bm.report( "meval" ) do
N.times do
b.a
end
end
end
R.
 
M

Mark Wilden

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
 
J

Jeremy Hinegardner

From: George Wang [mailto:[email protected]]

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

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
 
X

Xavier Noria

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.
 
S

Sebastian Hungerecker

Jeremy said:
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
 
F

Florian Gilcher

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


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

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

===
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
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkg2ZR8ACgkQJA/zY0IIRZYUNwCfR5r7LiPwdrH4TirnxjxgG6ZU
UNgAnih2Bt6gDeWK7i7ss71xxW3F+meT
=R5cD
-----END PGP SIGNATURE-----
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top