Dynamic local vars

Discussion in 'Ruby' started by Vasyl Smirnov, Dec 7, 2007.

  1. Hi,

    I wonder if there is any way to create local variables dynamically,
    for example, given

    def foo
    bar
    puts x, y
    end

    is it possible for bar to somehow create and initialize x and y?
    Binding doesn't seem to be modifiable..

    Or am I asking too much? :)
     
    Vasyl Smirnov, Dec 7, 2007
    #1
    1. Advertising

  2. Vasyl Smirnov

    MonkeeSage Guest

    On Dec 7, 2:19 am, Vasyl Smirnov <> wrote:
    > Hi,
    >
    > I wonder if there is any way to create local variables dynamically,
    > for example, given
    >
    > def foo
    > bar
    > puts x, y
    > end
    >
    > is it possible for bar to somehow create and initialize x and y?
    > Binding doesn't seem to be modifiable..
    >
    > Or am I asking too much? :)


    There are probably more clever ways than this, but I'm dumb...

    def bar
    x = 10
    y = 20
    binding
    end

    def foo
    eval("puts x, y", bar)
    end

    Regards,
    Jordan
     
    MonkeeSage, Dec 7, 2007
    #2
    1. Advertising

  3. Vasyl Smirnov

    Tim Hunter Guest

    Vasyl Smirnov wrote:
    > Hi,
    >
    > I wonder if there is any way to create local variables dynamically,
    > for example, given
    >
    > def foo
    > bar
    > puts x, y
    > end
    >
    > is it possible for bar to somehow create and initialize x and y?
    > Binding doesn't seem to be modifiable..
    >
    > Or am I asking too much? :)
    >


    Hmmm...local variables are called local because they're local to the
    method that uses them. A variable that's shared between two methods
    isn't local.

    If foo and bar are both methods in the same class, use instance
    variables. If they're not both in the same class, use global variables.

    --
    RMagick: http://rmagick.rubyforge.org/
     
    Tim Hunter, Dec 7, 2007
    #3
  4. On Dec 7, 11:35 am, MonkeeSage <> wrote:
    > On Dec 7, 2:19 am, Vasyl Smirnov <> wrote:
    >
    > def bar
    > x = 10
    > y = 20
    > binding
    > end
    >
    > def foo
    > eval("puts x, y", bar)
    > end
    >


    This would do, but I'd like to have the content of foo as simple as
    possible (that's actually the reason for the question).
     
    Vasyl Smirnov, Dec 7, 2007
    #4
  5. 2007/12/7, Vasyl Smirnov <>:
    > I wonder if there is any way to create local variables dynamically,
    > for example, given
    >
    > def foo
    > bar
    > puts x, y
    > end
    >
    > is it possible for bar to somehow create and initialize x and y?
    > Binding doesn't seem to be modifiable..


    You cannot do this easily because of the method / variable ambiguity.
    There's a hack to do it: you need to define them before you use them
    but it is ugly and does not work properly.

    14:23:17 ~
    $ ruby <<XXX
    > def foo
    > x=y=nil
    > bar(binding)
    > puts x,y
    > end
    > def bar(b)
    > eval("x=1;y=2",b)
    > end
    > foo
    > XXX

    1
    2

    The problem with dynamically introducing local variables is that your
    code needs to be statically aware of them in order to use them. Even
    though you can inject any number of additional local variables into a
    binding, they won't get used because they do not appear in the code of
    that method.

    A much better solution to the problem of storing dynamic values is a Hash.

    def foo
    data = {}
    bar data
    puts data[:x], data[:y]
    end

    def bar(x)
    x[:x] = 1
    x[:y] = 2
    end

    But you can as well return multiple values

    def foo
    x,y = bar
    puts x, y
    end

    def bar
    return 1,2
    end

    Kind regards

    robert

    --
    use.inject do |as, often| as.you_can - without end
     
    Robert Klemme, Dec 7, 2007
    #5
  6. On Dec 7, 3:06 pm, Tim Hunter <> wrote:
    > Vasyl Smirnov wrote:
    > > Hi,

    >
    > > I wonder if there is any way to create local variables dynamically,
    > > for example, given

    >
    > > def foo
    > > bar
    > > puts x, y
    > > end

    >
    > > is it possible for bar to somehow create and initialize x and y?
    > > Binding doesn't seem to be modifiable..

    >
    > > Or am I asking too much? :)

    >
    > Hmmm...local variables are called local because they're local to the
    > method that uses them. A variable that's shared between two methods
    > isn't local.
    >
    > If foo and bar are both methods in the same class, use instance
    > variables. If they're not both in the same class, use global variables.
    >


    Yes, instance vars are an option. Though what would be better is
    something like a C-style macro,
    which would just define and assign these local vars inside foo. I
    thought maybe there's a way to do it in Ruby.

    MonkeeSage and Tim, thank you both for your replies!
     
    Vasyl Smirnov, Dec 7, 2007
    #6
  7. On Dec 7, 3:28 pm, "Robert Klemme" <> wrote:
    > 2007/12/7, Vasyl Smirnov <>:
    >
    > > I wonder if there is any way to create local variables dynamically,
    > > for example, given

    >
    > > def foo
    > > bar
    > > puts x, y
    > > end

    >
    > > is it possible for bar to somehow create and initialize x and y?
    > > Binding doesn't seem to be modifiable..

    >
    > You cannot do this easily because of the method / variable ambiguity.
    > There's a hack to do it: you need to define them before you use them
    > but it is ugly and does not work properly.
    >
    > 14:23:17 ~
    > $ ruby <<XXX> def foo
    > > x=y=nil
    > > bar(binding)
    > > puts x,y
    > > end
    > > def bar(b)
    > > eval("x=1;y=2",b)
    > > end
    > > foo
    > > XXX

    >
    > 1
    > 2
    >
    > The problem with dynamically introducing local variables is that your
    > code needs to be statically aware of them in order to use them. Even
    > though you can inject any number of additional local variables into a
    > binding, they won't get used because they do not appear in the code of
    > that method.
    >


    Thanks for clarifying that.


    > A much better solution to the problem of storing dynamic values is a Hash.
    >
    > def foo
    > data = {}
    > bar data
    > puts data[:x], data[:y]
    > end
    >
    > def bar(x)
    > x[:x] = 1
    > x[:y] = 2
    > end
    >
    > But you can as well return multiple values
    >
    > def foo
    > x,y = bar
    > puts x, y
    > end
    >
    > def bar
    > return 1,2
    > end


    The hash approach is nice, and I actually use it for some other code.

    I've posted this question because I wanted to eliminate the need to
    write "x, y = bar" and just go with "bar".
    The reason is that I have a bunch of methods, each starting with a
    kind of "x, y = bar", only with longer variable names.
    So it looked like it would be nice to somehow reduce them.

    So, it looks like I should either a) stop whining about it, or b) use
    one of the proposed approaches.
     
    Vasyl Smirnov, Dec 7, 2007
    #7
  8. Vasyl Smirnov

    MonkeeSage Guest

    On Dec 7, 7:47 am, Vasyl Smirnov <> wrote:
    > On Dec 7, 3:28 pm, "Robert Klemme" <> wrote:
    >
    >
    >
    > > 2007/12/7, Vasyl Smirnov <>:

    >
    > > > I wonder if there is any way to create local variables dynamically,
    > > > for example, given

    >
    > > > def foo
    > > > bar
    > > > puts x, y
    > > > end

    >
    > > > is it possible for bar to somehow create and initialize x and y?
    > > > Binding doesn't seem to be modifiable..

    >
    > > You cannot do this easily because of the method / variable ambiguity.
    > > There's a hack to do it: you need to define them before you use them
    > > but it is ugly and does not work properly.

    >
    > > 14:23:17 ~
    > > $ ruby <<XXX> def foo
    > > > x=y=nil
    > > > bar(binding)
    > > > puts x,y
    > > > end
    > > > def bar(b)
    > > > eval("x=1;y=2",b)
    > > > end
    > > > foo
    > > > XXX

    >
    > > 1
    > > 2

    >
    > > The problem with dynamically introducing local variables is that your
    > > code needs to be statically aware of them in order to use them. Even
    > > though you can inject any number of additional local variables into a
    > > binding, they won't get used because they do not appear in the code of
    > > that method.

    >
    > Thanks for clarifying that.
    >
    >
    >
    > > A much better solution to the problem of storing dynamic values is a Hash.

    >
    > > def foo
    > > data = {}
    > > bar data
    > > puts data[:x], data[:y]
    > > end

    >
    > > def bar(x)
    > > x[:x] = 1
    > > x[:y] = 2
    > > end

    >
    > > But you can as well return multiple values

    >
    > > def foo
    > > x,y = bar
    > > puts x, y
    > > end

    >
    > > def bar
    > > return 1,2
    > > end

    >
    > The hash approach is nice, and I actually use it for some other code.
    >
    > I've posted this question because I wanted to eliminate the need to
    > write "x, y = bar" and just go with "bar".
    > The reason is that I have a bunch of methods, each starting with a
    > kind of "x, y = bar", only with longer variable names.
    > So it looked like it would be nice to somehow reduce them.
    >
    > So, it looks like I should either a) stop whining about it, or b) use
    > one of the proposed approaches.


    Not so much like a C macro, but more like a C struct...you could...use
    a Struct ;)

    V = Struct.new:)x, :y).new(nil, nil)

    def bar
    V.x = 10
    V.y = 20
    end
    def foo
    bar
    puts V.x, V.y
    end

    Regards,
    Jordan
     
    MonkeeSage, Dec 7, 2007
    #8
  9. Vasyl Smirnov

    Tim Hunter Guest

    Jordan Callicoat wrote:
    >
    > Not so much like a C macro, but more like a C struct...you could...use
    > a Struct ;)
    >
    > V = Struct.new:)x, :y).new(nil, nil)
    >
    > def bar
    > V.x = 10
    > V.y = 20
    > end
    > def foo
    > bar
    > puts V.x, V.y
    > end
    >
    > Regards,
    > Jordan


    Of course the Struct is not actually allowing him to share data between
    bar and foo. It's the global constant V that's doing that.
    --
    Posted via http://www.ruby-forum.com/.
     
    Tim Hunter, Dec 7, 2007
    #9
  10. Vasyl Smirnov

    MonkeeSage Guest

    On Dec 7, 8:33 am, Tim Hunter <> wrote:
    > Jordan Callicoat wrote:
    >
    > > Not so much like a C macro, but more like a C struct...you could...use
    > > a Struct ;)

    >
    > > V = Struct.new:)x, :y).new(nil, nil)

    >
    > > def bar
    > > V.x = 10
    > > V.y = 20
    > > end
    > > def foo
    > > bar
    > > puts V.x, V.y
    > > end

    >
    > > Regards,
    > > Jordan

    >
    > Of course the Struct is not actually allowing him to share data between
    > bar and foo. It's the global constant V that's doing that.
    > --
    > Posted viahttp://www.ruby-forum.com/.


    Yeah. I thought it fit the desired behavior though, since it shortened
    the call to bar (as per desired behavior) and only adds four more
    chars ("V." twice) over the original example.

    Regards,
    Jordan
     
    MonkeeSage, Dec 7, 2007
    #10
  11. Vasyl Smirnov

    Liam Guest

    On Fri, Dec 07, 2007 at 10:06:15PM +0900, Tim Hunter wrote:
    > Hmmm...local variables are called local because they're local to the
    > method that uses them. A variable that's shared between two methods
    > isn't local.
    >
    > If foo and bar are both methods in the same class, use instance
    > variables. If they're not both in the same class, use global variables.


    Do they need to be "variables"?


    def bar(arg1,arg2)
    klass=class << self; self; end
    klass.send:)define_method,:x) { arg1 }
    klass.send:)define_method,:y) { arg2 }
    end
    def foo
    bar(42,23)
    puts x,y
    end
    foo

    Of course, x and y continue to exist after the scope of foo, but with a
    little more wrapping, you could solve that, too. You could create
    setters, but they'd have to be accessed like "self.x=".
     
    Liam, Dec 7, 2007
    #11
  12. On Dec 7, 6:28 pm, Liam <> wrote:
    > On Fri, Dec 07, 2007 at 10:06:15PM +0900, Tim Hunter wrote:
    > > Hmmm...local variables are called local because they're local to the
    > > method that uses them. A variable that's shared between two methods
    > > isn't local.

    >
    > > If foo and bar are both methods in the same class, use instance
    > > variables. If they're not both in the same class, use global variables.

    >
    > Do they need to be "variables"?
    >
    > def bar(arg1,arg2)
    > klass=class << self; self; end
    > klass.send:)define_method,:x) { arg1 }
    > klass.send:)define_method,:y) { arg2 }
    > end
    > def foo
    > bar(42,23)
    > puts x,y
    > end
    > foo
    >
    > Of course, x and y continue to exist after the scope of foo, but with a
    > little more wrapping, you could solve that, too. You could create
    > setters, but they'd have to be accessed like "self.x=".


    Actually, they whole thing has to be thread-safe and reentrant :)
     
    Vasyl Smirnov, Dec 7, 2007
    #12
  13. On 07.12.2007 16:48, MonkeeSage wrote:
    > On Dec 7, 8:33 am, Tim Hunter <> wrote:
    >> Jordan Callicoat wrote:
    >>
    >>> Not so much like a C macro, but more like a C struct...you could...use
    >>> a Struct ;)
    >>> V = Struct.new:)x, :y).new(nil, nil)
    >>> def bar
    >>> V.x = 10
    >>> V.y = 20
    >>> end
    >>> def foo
    >>> bar
    >>> puts V.x, V.y
    >>> end
    >>> Regards,
    >>> Jordan

    >> Of course the Struct is not actually allowing him to share data between
    >> bar and foo. It's the global constant V that's doing that.
    >> --
    >> Posted viahttp://www.ruby-forum.com/.

    >
    > Yeah. I thought it fit the desired behavior though, since it shortened
    > the call to bar (as per desired behavior) and only adds four more
    > chars ("V." twice) over the original example.


    Global variables are considered harmful for a reason. Sometimes more
    explicitness is better. I.e. in this case I'd rather use multiple
    returns or - more likely - instance variables. But since I know nothing
    about the algorithm I cannot make a recommendation here. I'd just
    generally suggest to look at command pattern.

    Kind regards

    robert
     
    Robert Klemme, Dec 8, 2007
    #13
  14. Vasyl Smirnov

    MonkeeSage Guest

    On Dec 8, 5:01 am, Robert Klemme <> wrote:
    > On 07.12.2007 16:48, MonkeeSage wrote:
    >
    >
    >
    > > On Dec 7, 8:33 am, Tim Hunter <> wrote:
    > >> Jordan Callicoat wrote:

    >
    > >>> Not so much like a C macro, but more like a C struct...you could...use
    > >>> a Struct ;)
    > >>> V = Struct.new:)x, :y).new(nil, nil)
    > >>> def bar
    > >>> V.x = 10
    > >>> V.y = 20
    > >>> end
    > >>> def foo
    > >>> bar
    > >>> puts V.x, V.y
    > >>> end
    > >>> Regards,
    > >>> Jordan
    > >> Of course the Struct is not actually allowing him to share data between
    > >> bar and foo. It's the global constant V that's doing that.
    > >> --
    > >> Posted viahttp://www.ruby-forum.com/.

    >
    > > Yeah. I thought it fit the desired behavior though, since it shortened
    > > the call to bar (as per desired behavior) and only adds four more
    > > chars ("V." twice) over the original example.

    >
    > Global variables are considered harmful for a reason. Sometimes more
    > explicitness is better. I.e. in this case I'd rather use multiple
    > returns or - more likely - instance variables. But since I know nothing
    > about the algorithm I cannot make a recommendation here. I'd just
    > generally suggest to look at command pattern.
    >
    > Kind regards
    >
    > robert


    Yeah, yeah...but it still fit (what was given) of the spec. :p

    Regards,
    Jordan
     
    MonkeeSage, Dec 8, 2007
    #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. Jon

    app vars and cache vars

    Jon, Dec 14, 2004, in forum: ASP .Net
    Replies:
    3
    Views:
    395
  2. Linuxguy123
    Replies:
    7
    Views:
    694
    Paddy O'Loughlin
    Feb 20, 2009
  3. caccolangrifata
    Replies:
    18
    Views:
    395
    Chris Torek
    Jul 22, 2011
  4. Dirk Einecke

    GET-parameters an local vars

    Dirk Einecke, May 15, 2004, in forum: Ruby
    Replies:
    4
    Views:
    101
    Dirk Einecke
    May 15, 2004
  5. David Combs
    Replies:
    3
    Views:
    197
    Michele Dondi
    Aug 9, 2004
Loading...

Share This Page