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

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?

On 30.04.2011 21:25, Iaki Baz C. wrote:

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ñaki Baz C.” [email protected] wrote in post #995996:

Ok. Then one question more: why is not possible to reassing a value to
a constant

Why do you want to change a constant? ruby has variables for that.
Ruby doesn’t really ever forbid anything, hence the reason you only get
a warning.

2011/4/30 Robert K. [email protected]:

On 30.04.2011 21:25, Iñaki Baz C. wrote:

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

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.

2011/4/30 7stud – [email protected]:

“Iñaki Baz C.” [email protected] wrote in post #995996:

Ok. Then one question more: why is not possible to reassing a value to
a constant

Why do you want to change a constant? ruby has variables for that.

Because it’s more efficient. Consider this example:

module M
class C
KAKA = 123

def self.kaka
  @kaka ||= 123
end

end
end

Let’s initialize @kaka:

M::C.kaka
=> 123

$kaka = 123


Benchmark.realtime { 10000000.times { M::C::KAKA } }
=> 0.9098186492919922

Benchmark.realtime { 10000000.times { M::C.kaka } }
=> 1.9608278274536133

Benchmark.realtime { 10000000.times { $kaka } }
=> 0.9143557548522949

2011/5/1 Christopher D. [email protected]:

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

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.

end
end

Interesting, thanks a lot :slight_smile:

On Sat, Apr 30, 2011 at 12:58 PM, Iñaki Baz C. [email protected]
wrote:

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 = 123
def self.konst=(val)
remove_const :KONST
const_set :KONST, val
end
end

On Sun, May 1, 2011 at 1:48 AM, Iaki Baz C. [email protected] wrote:

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. :slight_smile:

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. :slight_smile:


Phillip G.

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.

On 01.05.2011 02:24, Iaki Baz C. wrote:

2011/5/1 Phillip G.[email protected]:

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

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

2011/5/1 Phillip G. [email protected]:

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

So I’ll use it, something like:

module MyApp
CONFIGURATION = {}
end

Thanks.

2011/5/1 Robert K. [email protected]:

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

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 :slight_smile:
Yoo much-preoptimization :slight_smile:

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.

Well, I can change it globaly:

H1 = {:qwe=>123}

H1.object_id
=> 21460540

h2 = {:asd=>999}

H1.replace h2

H1
=> {:asd=>999}

H1.object_id
21460540

:slight_smile:

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

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.

On 04/30/2011 05:13 PM, Phillip G. wrote:

2011/5/1 Robert K. [email protected]:

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.

Well, I can change it globaly:

Of course. But you need synchronization to make that thread safe.

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

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?

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

On 01.05.2011 14:36, Iaki Baz C. wrote:

2011/5/1 Robert K.[email protected]:

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

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 :slight_smile:
Yoo much-preoptimization :slight_smile:

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