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

Discussion in 'Ruby' started by Iñaki Baz Castillo, Apr 30, 2011.

  1. 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
    <>
     
    Iñaki Baz Castillo, Apr 30, 2011
    #1
    1. Advertising

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

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, Apr 30, 2011
    #2
    1. Advertising

  3. 2011/4/30 Robert Klemme <>:
    > On 30.04.2011 21:25, I=C3=B1aki 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. =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
    <>
     
    Iñaki Baz Castillo, Apr 30, 2011
    #3
  4. Iñaki Baz Castillo

    7stud -- Guest

    "I=C3=B1aki Baz Castillo" <> 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.

    -- =

    Posted via http://www.ruby-forum.com/.=
     
    7stud --, Apr 30, 2011
    #4
  5. 2011/4/30 7stud -- <>:
    > "I=C3=B1aki Baz Castillo" <> 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*? =C2=A0ruby has variables for that=
     
    Iñaki Baz Castillo, Apr 30, 2011
    #5
  6. On Sat, Apr 30, 2011 at 12:58 PM, I=C3=B1aki Baz Castillo <> w=
    rote:
    > 2011/4/30 Robert Klemme <>:
    >> On 30.04.2011 21:25, I=C3=B1aki 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. =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?


    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
     
    Christopher Dicely, May 1, 2011
    #6
  7. 2011/5/1 Christopher Dicely <>:
    > 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
    <>
     
    Iñaki Baz Castillo, May 1, 2011
    #7
  8. On Sun, May 1, 2011 at 1:48 AM, I=F1aki Baz Castillo <> 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. :)

    > 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.
     
    Phillip Gawlowski, May 1, 2011
    #8
  9. 2011/5/1 Phillip Gawlowski <>:
    > 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
    <>
     
    Iñaki Baz Castillo, May 1, 2011
    #9
  10. On 01.05.2011 02:24, Iñaki Baz Castillo wrote:
    > 2011/5/1 Phillip Gawlowski<>:
    >> 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 :)


    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

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, May 1, 2011
    #10
  11. 2011/5/1 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.


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


    >> So I'll use it, something like:
    >>
    >> module MyApp
    >> =C2=A0 CONFIGURATION =3D {}
    >> end

    >
    > 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
    <>
     
    Iñaki Baz Castillo, May 1, 2011
    #11
  12. On 04/30/2011 05:13 PM, Phillip Gawlowski wrote:
    > On Sun, May 1, 2011 at 1:48 AM, Iñaki Baz Castillo<> 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 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...
     
    Joel VanderWerf, May 1, 2011
    #12
  13. On 01.05.2011 14:36, Iñaki Baz Castillo wrote:
    > 2011/5/1 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.

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


    Don't. You know what Knuth said about it, do you?

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


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

    >> 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 alsomakes
    >> testing easier. You can pass in whatever mock you want to use to testa
    >> 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.


    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

    --
    remember.guy do |as, often| as.you_can - without end
    http://blog.rubybestpractices.com/
     
    Robert Klemme, May 1, 2011
    #13
  14. 2011/5/1 Robert Klemme <>:
    >>> This might be a corner case but I would generally advice to not use
    >>> global
    >>> variables (or constants) for this. =C2=A0The reason is simply that you =

    loose a
    >>> lot of flexibility. =C2=A0You can only ever have one active configurati=

    on at a
    >>> time - and you cannot change it concurrently as well.

    >>
    >> Well, I can change it globaly:

    >
    > Of course. =C2=A0But you need synchronization to make that thread safe.


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




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

    --=20
    I=C3=B1aki Baz Castillo
    <>
     
    Iñaki Baz Castillo, May 1, 2011
    #14
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. johny smith
    Replies:
    8
    Views:
    445
    Peter Koch Larsen
    Jul 2, 2004
  2. Mr. SweatyFinger
    Replies:
    2
    Views:
    2,222
    Smokey Grindel
    Dec 2, 2006
  3. Joe Van Dyk

    Defining a constant in a class

    Joe Van Dyk, Apr 20, 2006, in forum: C++
    Replies:
    8
    Views:
    339
    Victor Bazarov
    Apr 21, 2006
  4. david.karr
    Replies:
    21
    Views:
    951
    Arne Vajhøj
    Mar 14, 2010
  5. John Pywtorak
    Replies:
    3
    Views:
    151
    Eric Hodel
    Oct 3, 2007
Loading...

Share This Page