Programmatically creating a local variable using a symol

Hi,

Where are variables actually stored? Or rather: how do I create a new
variable without using eval?

I’d like to write something like this.

bind :a, 1
p a
=> 1

How could I accompish this? How could a definition of “bind” look
like?

Local variables are registered in Binding and local_variables, but
how
do I get them there? = is no method, but it’s no keyword either?

Regards,
Thomas.

On Jan 6, 2008 8:49 AM, tho_mica_l [email protected] wrote:

Where are variables actually stored? Or rather: how do I create a new
variable without using eval?

Why do you want to do this with a local variable?

Consider using a hash and make your own “binding” table for the
purposes of which you’re speaking.

-austin

Why do you want to do this with a local variable?

First, I’d like to know a little bit more about ruby. And I would
have
found such a thing useful once or twice in the past.

Secondly (the background for my question), I’d like to implement some
ocaml’ish match command (for the moment, as some kind of exercise
only).
I’m not sure yet how this could best be done but I thought it would
be
nice if it could look somewhat like this:

val = Foo(1, 2)

case val
when Foo(:x, :y)
    a = x * y
when Bar(:x)
    a = x
end

But this form would require the variables to be set from Foo#=== which
I
don’t think is possible anyway.

What I managed to do is this:

class Matchtype
  class << self
      def match(other, &block)
          if other.class == self
              block.call(*other.value)
              true
          else
              false
          end
      end
  end

  attr_reader :value

  def initialize(*value)
      @value = value
  end

end

Sample use:

class Foo < Matchtype
end

class Bar < Matchtype
end

x = Foo.new(1, 2)
y = Bar.new(1)

if Foo.match(x) {|a, b| p "Foo", a + b}
elsif Bar.match(x) {|a| p "Bar", a}
end

if Foo.match(y) {|a, b| p "Foo", a + b}
elsif Bar.match(y) {|a| p "Bar", a}
end

But this is quite useless the way it is because the value of the
block
cannot be used and because it’s ugly and …

One could of course do it this way which would come close:

class Boo < Array
end

class Baa < Array
end

z = Boo[1, 2]
case z
when Baa
    p "Nope"
when Boo
    a, b = z
    p "Boo", a + b
end

It would be nice being able to eliminate the “a, b = z” line though.

Ideally, one would also be able to do something like this:

z = Boo[1, :a]
case z
when Boo(0, '')
    p "Nope"
when Boo(1, :a)
    p "Boo", a
end

Any ideas are welcome.

Regards,
Thomas.

On Jan 6, 2008, at 9:34 AM, tho_mica_l wrote:

nice if it could look somewhat like this:

val = Foo(1, 2)

case val
when Foo(:x, :y)
    a = x * y
when Bar(:x)
    a = x
end

invert the var binding: make them instance variables and it falls out
easily:

class Foo
attr :x, :y
def initialize x, y
@x, @y = x, y
end
end
def Foo(*a, &b) Foo.new(*a, &b) end

class Bar < Foo; end
def Bar(*a, &b) Bar.new(*a, &b) end

val = Foo 1, 2

a =
case val
when Foo
val.x * val.y
when Bar
val.x
end

a @ http://codeforpeople.com/

On Jan 7, 2008 12:45 AM, tho_mica_l [email protected] wrote:

(I still would like to know if it’s possible to create a local
variable
though.)

You might have to use #instance_eval.

irb> a = “hello”
=> “hello”
irb> instance_eval( “#{a} = 3” )
=> 3
irb> a
=> “hello”
irb> hello
=> 3

Not much help, but sort of answers the question.

Todd

invert the var binding: make them instance variables and it falls out
easily:

Okay, this idea with the variable binding is pointless in this
context.
(I still would like to know if it’s possible to create a local
variable
though.)

I now defined a subclass of Array with a more clever === method,
which
knows how to match wildcards. This version comes pretty close to what
I
intended.

class Foo < MatchStruct
    fields :a, :b, :c, :d, :e
end

class Bar < MatchStruct
    fields :a, :b
end

x = Foo[1, 2, 3, 4, 5]
a = MatchStruct(x) do
    match Foo[1, :_, 3, :_, 5] do
        ["Foo", *x]
    end
    match Bar[:_, "b"] do
        ["Bar", x.a + x.b]
    end
end
p a

Regards,
Thomas.

You might have to use #instance_eval.

This is about what I try to avoid. Some interpreters make variables
available via some pseudomagic dictionary/hash. Based on ruby’s nature
and my previous experiences I’d assumed ruby would provide such a
solution too but couldn’t find it out myself.

tho_mica_l wrote:

You might have to use #instance_eval.

This is about what I try to avoid. Some interpreters make variables
available via some pseudomagic dictionary/hash. Based on ruby’s nature
and my previous experiences I’d assumed ruby would provide such a
solution too but couldn’t find it out myself.

There is no way in either Ruby 1.8 or Ruby 1.9. The names of variables
and “variable calls” are determined at parse time, both for normal
scopes and for eval. eval can add new variables, but only to the eval
scope, and only in 1.8 (I believe 1.9 provides a separate eval scope for
each eval).

Your only change of dynamically defining things that look like variables
is the attr binding a few people have described.

  • Charlie