"once" meta-method without "module_eval" (Pickaxe)

Discussion in 'Ruby' started by Greg Weeks, Nov 14, 2007.

  1. Greg Weeks

    Greg Weeks Guest

    My impression is that Ruby meta-programming used to lean heavily on
    evaluating strings as code, but is moving away from that. (Good!) In
    that spirit, it would be nice to replace this example from Chapter 24,
    Classes and Objects:

    class Date
    class <<self
    def once(*ids) # :nodoc:
    for id in ids
    module_eval <<-"end;"
    alias_method :__#{id.to_i}__, :#{id.to_s}
    private :__#{id.to_i}__
    def #{id.to_s}(*args, &block)
    (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
    end
    end;
    end
    end
    end
    ...
    once :as_string, :as_YMD
    end

    "once" replaces a specified method with a method that caches the return
    value on the first call.

    The example above served to illustrate the use of class instance
    variables. However, the replacement that comes to mind does not:

    class <<self
    def once(*ids)
    values = {}
    for id in ids
    new_id = "__#{id.to_i}__".to_sym
    alias_method new_id, id
    private new_id
    define_method (id) do |*args|
    (values[id] ||= [ method(new_id).call(*args) ])[0]
    end
    end
    end
    end

    Is there some way to avoid evals and still use class instance variables?

    Is there some way to avoid evals and still handle the "&block" argument?

    Is there a natural alternative to the local hash variable?

    Am I right to think that eval-ing strings is retro?

    (By the way, neither implementation allows "once" to be called twice
    with the same symbol.)
    --
    Posted via http://www.ruby-forum.com/.
    Greg Weeks, Nov 14, 2007
    #1
    1. Advertising

  2. Greg Weeks

    Trans Guest

    On Nov 14, 1:23 am, Greg Weeks <> wrote:
    > My impression is that Ruby meta-programming used to lean heavily on
    > evaluating strings as code, but is moving away from that. (Good!) In
    > that spirit, it would be nice to replace this example from Chapter 24,
    > Classes and Objects:
    >
    > class Date
    > class <<self
    > def once(*ids) # :nodoc:
    > for id in ids
    > module_eval <<-"end;"
    > alias_method :__#{id.to_i}__, :#{id.to_s}
    > private :__#{id.to_i}__
    > def #{id.to_s}(*args, &block)
    > (@__#{id.to_i}__ ||= [__#{id.to_i}__(*args, &block)])[0]
    > end
    > end;
    > end
    > end
    > end
    > ...
    > once :as_string, :as_YMD
    > end
    >
    > "once" replaces a specified method with a method that caches the return
    > value on the first call.
    >
    > The example above served to illustrate the use of class instance
    > variables. However, the replacement that comes to mind does not:
    >
    > class <<self
    > def once(*ids)
    > values = {}
    > for id in ids
    > new_id = "__#{id.to_i}__".to_sym
    > alias_method new_id, id
    > private new_id
    > define_method (id) do |*args|
    > (values[id] ||= [ method(new_id).call(*args) ])[0]
    > end
    > end
    > end
    > end
    >
    > Is there some way to avoid evals and still use class instance variables?


    instance_variable_get/set

    > Is there some way to avoid evals and still handle the "&block" argument?


    Wait for 1.9.

    > Is there a natural alternative to the local hash variable?


    instance_variable_get/set if you want to do it like the original, but
    your local might be better.

    > Am I right to think that eval-ing strings is retro?


    I'm not sure there's anything really wrong with eval. Often the code
    looks cleaner compared to these long winded meta-methods.

    T.
    Trans, Nov 14, 2007
    #2
    1. Advertising

  3. Greg Weeks wrote:
    > My impression is that Ruby meta-programming used to lean heavily on
    > evaluating strings as code, but is moving away from that. (Good!)


    I have just one question: why is that good? Is it just that avoiding
    evaluation of strings somehow "feels cleaner" or is there actually a
    justification for that?

    If you rememer that load/require basically has the effect of eval'ing
    the content of a file, string eval doesn't feel so evil anymore.

    Daniel
    Daniel DeLorme, Nov 14, 2007
    #3
  4. Greg Weeks

    ara.t.howard Guest

    On Nov 14, 2007, at 5:24 AM, Daniel DeLorme wrote:

    > If you rememer that load/require basically has the effect of
    > eval'ing the content of a file, string eval doesn't feel so evil
    > anymore.


    not to mention it doesn't create a closure/leak...

    a @ http://codeforpeople.com/
    --
    share your knowledge. it's a way to achieve immortality.
    h.h. the 14th dalai lama
    ara.t.howard, Nov 14, 2007
    #4
  5. Greg Weeks

    Trans Guest

    On Nov 14, 12:37 pm, "ara.t.howard" <> wrote:
    > On Nov 14, 2007, at 5:24 AM, Daniel DeLorme wrote:
    >
    > > If you rememer that load/require basically has the effect of
    > > eval'ing the content of a file, string eval doesn't feel so evil
    > > anymore.

    >
    > not to mention it doesn't create a closure/leak...


    another good point! and i still think there should be a way to shut
    out the closure for a block.

    T.
    Trans, Nov 14, 2007
    #5
  6. Greg Weeks

    Greg Weeks Guest

    First, thanks (you all) for the info I asked for.

    > > Am I right to think that eval-ing strings is retro?

    >
    > I'm not sure there's anything really wrong with eval. Often the code
    > looks cleaner compared to these long winded meta-methods.


    My intuition is that a good argument could be given. But I'm not the
    person to give it.

    > not to mention it doesn't create a closure/leak...


    The fact that I can use "define-method" to *almost but not quite*
    achieve the affect of a "def" is almost certainly a Ruby wart. If I run
    into trouble I'll just blame Matz :)
    --
    Posted via http://www.ruby-forum.com/.
    Greg Weeks, Nov 14, 2007
    #6
  7. Greg Weeks

    Phrogz Guest

    On Nov 13, 11:23 pm, Greg Weeks <> wrote:
    > Am I right to think that eval-ing strings is retro?


    My first dynamically-typed, runtime-interpreted scripting language was
    JavaScript. In JavaScript, eval is considered a bad idea. Loading a
    string of JavaScript code compiles it to bytecode and then executes
    the byte code. Hitting an eval() call in the middle of a program
    requires booting up the lexer and bytecode compiler again, to handle
    that one string, before it can be run. It's inefficient, and almost
    never needed.

    I gather the same is not true in Ruby currently. I think (but may be
    horribly wrong) that this is not so much because of some excellent
    implementation of eval, but a because everything is in the same slow
    pool of interpretation.

    I'm totally guessing, but I would suspect that at some point in Ruby's
    runtime future, startup optimizations/compilations will happen once
    only. If this is true (and I know very little about virtual machines
    and bytecodes and the actual implementation, so I could be wrong),
    then I would suspect that eval of a string (not a block) will incur
    undesirable overhead.

    For these reasons (my history with eval in JS and my suspicion that it
    may become undesirable from a performance standpoint) I personally
    never eval strings.
    Phrogz, Nov 14, 2007
    #7
    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. Nym Pseudo

    META NAME and META HTTP-EQUIV

    Nym Pseudo, Sep 26, 2003, in forum: HTML
    Replies:
    1
    Views:
    544
    =?iso-8859-1?Q?brucie?=
    Sep 26, 2003
  2. Simon Strandgaard

    overload method in module_eval, how?

    Simon Strandgaard, Nov 10, 2003, in forum: Ruby
    Replies:
    12
    Views:
    224
    Simon Strandgaard
    Nov 10, 2003
  3. Henrik
    Replies:
    3
    Views:
    106
  4. ChrisKaelin
    Replies:
    7
    Views:
    96
    ChrisKaelin
    Apr 22, 2007
  5. 7stud --
    Replies:
    8
    Views:
    104
    James Edward Gray II
    Nov 26, 2007
Loading...

Share This Page