On Sat, Apr 30, 2011 at 12:58 PM, Iñaki Baz Castillo <ibc / aliax.net> wrote:
> 2011/4/30 Robert Klemme <shortcutter / googlemail.com>:
>> On 30.04.2011 21:25, Iñaki Baz Castillo 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 commonor 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?

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