Why defining a constant in a method is not allowed but usingself.class.const_set is allowed?

  • Thread starter Iñaki Baz Castillo
  • Start date
I

Iñaki Baz Castillo

Hi, assinging a value to a constant within a method is not allowed
(SyntaxError:: dynamic constant assignment) but I can use
self.class.const_set within a method. Which is the difference?

--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 
R

Robert Klemme

Hi, assinging a value to a constant within a method is not allowed
(SyntaxError:: dynamic constant assignment) but I can use
self.class.const_set within a method. Which is the difference?

You described the difference pretty accurately. It is quite common for
Ruby to forbid doing bad things directly while still leaving a way to do
it nevertheless (just think of private methods and #send).

Kind regards

robert
 
I

Iñaki Baz Castillo

2011/4/30 Robert Klemme said:
You described the difference pretty accurately. =C2=A0It is quite common = for Ruby
to forbid doing bad things directly while still leaving a way to do it
nevertheless (just think of private methods and #send).

Ok. Then one question more: why is not possible to reassing a value to
a constant (even using self.class.const_set)? Is there internal issue
with it? I get a warning doing it (I suppose it depends on $safe
value), but what is the real problem with it?

Thanks a lot.

--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 
C

Christopher Dicely

Ok. Then one question more: why is not possible to reassing a value to
a constant (even using self.class.const_set)? Is there internal issue
with it? I get a warning doing it (I suppose it depends on $safe
value), but what is the real problem with it?

It is possible. As you note, it produces a warning, because more than
one assignment to a constant indicates something that is likely to be
an error (since the use of a constant rather than a variable implies
that the value is intended to be constant once defined.)

At any rate, sure, constant (or global variable) lookup is maybe twice
as fast as accessing an instance variable of another object (class or
otherwise) through a simple getter method (though maybe not; it seems
close to that on Windows Ruby 1.9.2, but the ratio seems a lot closer
on JRuby 1.6.1 [which makes sense, since JRuby has done a lot of work,
IIRC, to optimize method calls, which are where the extra time seems
to be], and the results may differ for other implementations), and you
might save a tenth of a microsecond or so (on fairly modest current
hardware) per access from outside of the object to which the value
belongs, but are you really spending so much of your programs time on
that kind of access where speeding that access up is going to make a
difference?

Since looking up instance variables that are in scope is about as fast
as looking up remote constants, you may (depending on the access
pattern and frequency of change involved) be able to get a similar
speedup without abusing constants simply by caching the value of the
remote attribute in a local instance variable of the objects consuming
it, and registering them as listeners that are notified on updates to
the value.

OTOH, if you absolutely must redefine constants and avoid producing
warnings (without actually changing the settings affecting warning
levels), its simple enough to do (Ruby rarely stops you from doing
things):

class C
KONST =3D 123
def self.konst=3D(val)
remove_const :KONST
const_set :KONST, val
end
end
 
I

Iñaki Baz Castillo

2011/5/1 Christopher Dicely said:
It is possible. As you note, it produces a warning, because more than
one assignment to a constant indicates something that is likely to be
an error (since the use of a constant rather than a variable implies
that the value is intended to be constant once defined.)

Yes, I understand that redeining a constant is not "good" in any
language, just wondering why Ruby, being so flexible, also behaves
like others.

At any rate, sure, constant (or global variable) lookup is maybe twice
as fast as accessing an instance variable of another object (class or
otherwise) through a simple getter method

Yes, I assume it occurs because Ruby must perform two lookups:

1) the method
2) the attribute returned by the method

but are you really spending so much of your programs time on
that kind of access where speeding that access up is going to make a
difference?

Well, is just minimum of course, I just wanted to study it. or sure
accessing an attribute (through a method) will not be the bottleneck
of my application :)

Since looking up instance variables that are in scope is about as fast
as looking up remote constants, you may (depending on the access
pattern and frequency of change involved) be able to get a similar
speedup without abusing constants simply by caching the value of the
remote attribute in a local instance variable of the objects consuming
it, and registering them as listeners that are notified on updates to
the value.

It seems not very suitable in my application. Basically I get a conf
file and want to store configuration data in constants (for faster
lockup). But I also need to change those values in realtime.

But as said before, I'll probasbly move to attribute variables.


OTOH, if you absolutely must redefine constants and avoid producing
warnings (without actually changing the settings affecting warning
levels), its simple enough to do (Ruby rarely stops you from doing
things):

class C
=C2=A0KONST =3D 123
=C2=A0def self.konst=3D(val)
=C2=A0 =C2=A0remove_const :KONST
=C2=A0 =C2=A0const_set :KONST, val
=C2=A0end
end

Interesting, thanks a lot :)


--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 
P

Phillip Gawlowski

Yes, I understand that redeining a constant is not "good" in any
language, just wondering why Ruby, being so flexible, also behaves
like others.

It's called a "constant". What would you expect it to be? Ever
changing like like the wind, or steady and everlasting like the
mountains?*

Ruby gives you the mountain--and the tools to change the mountain into
a sculpture.

It's the Principle Of Least Surprise (To Matz) hard at work. :)
It seems not very suitable in my application. Basically I get a conf
file and want to store configuration data in constants (for faster
lockup). But I also need to change those values in realtime.

Well, before making constants mutable, I'd see if they actually are a
worthwhile target of optimization (and the possible breakage this
introduces).

Maybe a configuration Hash is an acceptable compromise between lookup
speed and mutability?


* I know, mountains erode, and winds actually have patterns to them,
but allow me to be a bit flowery for once. :)

--=20
Phillip Gawlowski

Though the folk I have met,
(Ah, how soon!) they forget
When I've moved on to some other place,
There may be one or two,
When I've played and passed through,
Who'll remember my song or my face.
 
I

Iñaki Baz Castillo

2011/5/1 Phillip Gawlowski said:
Maybe a configuration Hash is an acceptable compromise between lookup
speed and mutability?

Humm, yes, having a HASH constant containing a hash is faster than
accessing instance variables within a class. Just a bit, but faster :)

So I'll use it, something like:

module MyApp
CONFIGURATION =3D {}
end

Thanks.

--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 
R

Robert Klemme

Humm, yes, having a HASH constant containing a hash is faster than
accessing instance variables within a class. Just a bit, but faster :)

You never mentioned a performance problem you are trying to solve.
Could be that you are worrying too much about an irrelevant detail.
So I'll use it, something like:

module MyApp
CONFIGURATION = {}
end

This might be a corner case but I would generally advice to not use
global variables (or constants) for this. The reason is simply that you
loose a lot of flexibility. You can only ever have one active
configuration at a time - and you cannot change it concurrently as well.

It may be OK for a small script or application but if you make that
design a habit you might run into problems later. Generally it is
better to provide configuration and other information from the outside
because that also makes testing easier. You can pass in whatever mock
you want to use to test a particular feature. If OTOH instances decide
themselves where to get the information from (i.e. the global variable /
constant) you are out of luck (or you need to patch methods of the class
under test while testing which is generally not a good idea because then
you don't test any more what will be productive eventually).

Kind regards

robert
 
I

Iñaki Baz Castillo

2011/5/1 Robert Klemme said:
You never mentioned a performance problem you are trying to solve. Could = be
that you are worrying too much about an irrelevant detail.

Yes, I know :)
Yoo much-preoptimization :)

This might be a corner case but I would generally advice to not use globa= l
variables (or constants) for this. =C2=A0The reason is simply that you lo= ose a
lot of flexibility. =C2=A0You can only ever have one active configuration= at a
time - and you cannot change it concurrently as well.

Well, I can change it globaly:


H1 =3D {:qwe=3D>123}

H1.object_id
=3D> 21460540

h2 =3D {:asd=3D>999}

H1.replace h2

H1
=3D> {:asd=3D>999}

H1.object_id
21460540


:)



It may be OK for a small script or application but if you make that desig= n a
habit you might run into problems later. =C2=A0Generally it is better to = provide
configuration and other information from the outside because that also ma= kes
testing easier. =C2=A0You can pass in whatever mock you want to use to te= st a
particular feature. =C2=A0If OTOH instances decide themselves where to ge= t the
information from (i.e. the global variable / constant) you are out of luc= k
(or you need to patch methods of the class under test while testing which= is
generally not a good idea because then you don't test any more what will = be
productive eventually).

I read the configuration from a text file (maybe YAML). But later, for
each request in my server, my classes and methods must access some
configuration fields (for each request), for example the log level.
This is the reason I need such access to be as fast as possible.

Anyhow, I don't want to loose flexibility neither mantain ugly code
(deleting and re-creating constants for each configuration change).
After this thread I hope that using a constant hash (i.e:
MyServer::CONFIGURATION) is a good choice between
ellegancy/flexibility and efficience.


Thanks a lot for your response.




--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 
J

Joel VanderWerf

It's called a "constant". What would you expect it to be? Ever
changing like like the wind, or steady and everlasting like the
mountains?*

Ruby programs may operate *on* programs. One program's constant is
another program's variable. For example: test code for a library that
uses a constant...
 
R

Robert Klemme

Yes, I know :)
Yoo much-preoptimization :)

Don't. You know what Knuth said about it, do you?
Well, I can change it globaly:

Of course. But you need synchronization to make that thread safe.
I read the configuration from a text file (maybe YAML). But later, for
each request in my server, my classes and methods must access some
configuration fields (for each request), for example the log level.
This is the reason I need such access to be as fast as possible.

Passing a configuration via a setter is not really something to worry
about speed wise.
Anyhow, I don't want to loose flexibility neither mantain ugly code
(deleting and re-creating constants for each configuration change).
After this thread I hope that using a constant hash (i.e:
MyServer::CONFIGURATION) is a good choice between
ellegancy/flexibility and efficience.

Is your code loaded once or is it reloaded for every request?
Thanks a lot for your response.

You're welcome!

Kind regards

robert
 
I

Iñaki Baz Castillo

2011/5/1 Robert Klemme said:
Of course. =C2=A0But you need synchronization to make that thread safe.

My code is thread safe (EventMachine with no threads inside) :)



Is your code loaded once or is it reloaded for every request?

The configuration is loaded when starting the server. But I also
provide a maangement interface so the admin can reload the
configuration in runtime (for example, to change the log level).

--=20
I=C3=B1aki Baz Castillo
<[email protected]>
 

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,733
Messages
2,569,439
Members
44,829
Latest member
PIXThurman

Latest Threads

Top