Dynamic local vars

V

Vasyl Smirnov

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? :)
 
M

MonkeeSage

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
 
T

Tim Hunter

Vasyl said:
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.
 
V

Vasyl Smirnov

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

Robert Klemme

2007/12/7 said:
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
 
V

Vasyl Smirnov

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!
 
V

Vasyl Smirnov

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 ~


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

MonkeeSage

2007/12/7, Vasyl Smirnov <[email protected]>:
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 ~


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
 
T

Tim Hunter

Jordan said:
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.
 
M

MonkeeSage

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.

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
 
L

Liam

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=".
 
V

Vasyl Smirnov

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

Robert Klemme

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
 
M

MonkeeSage

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
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top