Prevent ruby constant variables from changing?

R

Robert Dober

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 ;)
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
from :0
irb(main):010:0>

I get where I wanted :).
 
P

Peña, Botp

From: Robert Dober [mailto:[email protected]]=20
#

ff is my limited understanding of ruby.. pardon in advance..

# irb(main):001:0> class A
# irb(main):002:1> end
# =3D> nil

here we defined a class object referenced by a constant A, ruby gives =
the object a name "A". The name "A" is now set in stone :)
Consider "A" as the name of A, or the name of object named A. ...arggh, =
this reminds of me something... No worry, it's just a name.. :)

# irb(main):003:0> B =3D A
# =3D> A

we copy the constant A to constant B. B now points to class pointed by A =
wc is still named "A".=20

# irb(main):004:0> class B
# irb(main):005:1> def a; 42 end
# irb(main):006:1> end
# =3D> nil

we define a method a in class referred by constant B, wc is A, ergo we =
are reopening A.

# irb(main):007:0> A.new.a
# =3D> 42

ok

# irb(main):008:0> B.name
# =3D> "A"

the (class) object referred to by B is still named "A". Stoned. Even if =
you remove constant A, B.name will still be "A"

(note, you just operationaly demonstrated what XNoria wrote in prev post =
:)


# 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
#=20
# C =3D Class::new
# C.name equals "C".

ruby's behaviour is to get the class name fr the very first constant it =
encounters or it is assigned to. yes, by the very fact that _it_ is a =
constant. sorry, but what could be simpler? We've assigned it to a =
constant, and still we expect it to have no name?? But hey, again, it's =
just a name. maybe what is confusing here is the word "name" itself :)

irb(main):001:0> A=3DB=3DC=3DClass.new
=3D> C
irb(main):002:0> A.name
=3D> "C"
irb(main):003:0> B.name
=3D> "C"
irb(main):004:0> C.name
=3D> "C"

constant C is not coupled w name "C", see,

irb(main):007:0> Object.send :remove_const, :C
=3D> C
irb(main):008:0> C.name
NameError: uninitialized constant C
from (irb):8
from :0
irb(main):009:0> A.name
=3D> "C"
irb(main):010:0> B.name
=3D> "C"


# irb(main):001:0> C =3D _ =3D Class::new
# =3D> C
# irb(main):002:0> C.name
# =3D> "C"
#
# but finally
#=20
# irb(main):006:0> _ =3D Class::new
# =3D> #<Class:0xb7d5af90>
# irb(main):007:0> _.name
# =3D> ""

in ruby1.9, this is nil. wc mean, we have no name yet. better than =
saying my name is empty.


btw, careful w using "_" in irb, since irb uses it :)


# irb(main):008:0> X =3D _
# =3D> ""

of course, since the last result was ""

# irb(main):009:0> X.name
# NoMethodError: undefined method `name' for "":String
# from (irb):9
# from :0
# irb(main):010:0>

as expected


kind regards -botp
 
M

Mark Wilden

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

You're not really loading a different class - you're just updating the
current class, which could be done more tediously by redefining its
methods and reinitializing its attributes. But I see what you mean,
and you're right.

///ark
 
A

ara.t.howard

You're not really loading a different class - you're just updating
the current class, which could be done more tediously by redefining
its methods and reinitializing its attributes. But I see what you
mean, and you're right.


*sometimes*

the way rails does things you can do

class C
end

... edit ...

module C
end

... reload ...

and it can work.

a @ http://codeforpeople.com/
 
R

Robert Dober

(note, you just operationaly demonstrated what XNoria wrote in prev post :)
yes as you were repeating all I had done, obviously I did not succeed
in expressing my intent, sorry
<skip>

ruby's behaviour is to get the class name fr the very first constant it encounters or it is assigned to. yes, by the very fact that _it_ is a constant. sorry, but what could be simpler?
Simple????? I mean I can understand that behavior, but I feel it is
very mean to do such things ;). No really, why the heck is Ruby doing
this, what could it be good for?
We've assigned it to a constant, and still we expect it to have no name?? But hey, again, it's just a name. maybe what is confusing here is the word "name" itself :)
you got me;)
# irb(main):006:0> _ = Class::new
# => #<Class:0xb7d5af90>
# irb(main):007:0> _.name
# => ""

in ruby1.9, this is nil. wc mean, we have no name yet. better than saying my name is empty.


btw careful w using "_" in irb, since irb uses it :)
True enough, but I have tested it - surprisingly enough ;) - with Ruby
and Ruby1.9 I guess it is always dangerous to use irb to show some
sophisticated behavior, good point.
# irb(main):008:0> X = _
# => ""

of course, since the last result was ""
of course, of course, but there are shocking consequences, unless, and
that is my point, one does not need Class#name.
# irb(main):009:0> X.name
# NoMethodError: undefined method `name' for "":String
# from (irb):9
# from :0
# irb(main):010:0>

as expected
as I would like to expect for all classes.
kind regards -botp
Cheers
Robert
 
F

Florian Gilcher

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


You're not really loading a different class - you're just updating
the current class, which could be done more tediously by redefining
its methods and reinitializing its attributes. But I see what you
mean, and you're right.

///ark

"Updating" is a bit of a wild guess in a language where a class can
change during runtime. I cannot easily "update" a class in ruby as
there is no good possibility to determine the delta between a class
and the version you want to update to.

So usually, the practicable approach really is to delete the class an
completely reload it.

Regards,
Florian Gilcher
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

iEYEARECAAYFAkg25EkACgkQJA/zY0IIRZbGBACcCLW1HrlAfABN6KDuJ13S8zuf
GrkAni0AB1yamnIVz6U5A9Bc3kEQIf1F
=HWyr
-----END PGP SIGNATURE-----
 
D

Dave Bass

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

Joel VanderWerf

Dave said:
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
 
S

Sebastian Hungerecker

ara.t.howard said:
'in any context'::upcase

In the following context :: is not a synonym for .:
class A; class B; end end
A::B #works
A.B #does not
 
D

Dave Bass

Joel said:
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.
 
M

Mark Wilden

In the following context :: is not a synonym for .:
class A; class B; end end
A::B #works
A.B #does not

The context I was thinking it did not apply was 1.2 :)

///ark
 
G

George Wang

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


From: George Wang [mailto:[email protected]]
# 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
:)

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 ;)

kind regards -botp
 

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

No members online now.

Forum statistics

Threads
474,202
Messages
2,571,057
Members
47,667
Latest member
DaniloB294

Latest Threads

Top