local vars

Hello again!

# I' couldn't know that writing one line of unqualified humour would
trigger 100 other mails...
# perhaps s.o knows a "clean" (not offending) joke? - I know, thats not
the intention of the list, but I'm sure good humour is nice for everyone!

- Back to Ruby:

Who can I get the value of a local variable inside a method?
(metaprogramming?)

( I know thats not provided for general usage - is there any possibility?)

thank you Opti

As I told you previously, it's

binding.local_variable_get(:variable_name)

binding returns an interface to the current binding. You can capture other binding like this:

def binding_returner
a = 5
binding
end

p binding_returner.local_variable_get(:a)
# => 5

···

On 10/6/21 23:39, Die Optimisten wrote:

Hello again!

# I' couldn't know that writing one line of unqualified humour would
trigger 100 other mails...
# perhaps s.o knows a "clean" (not offending) joke? - I know, thats not
the intention of the list, but I'm sure good humour is nice for everyone!

- Back to Ruby:

Who can I get the value of a local variable inside a method?
(metaprogramming?)

( I know thats not provided for general usage - is there any possibility?)

thank you Opti

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

Hi!
Yes, I want to know if there is a way to access it directly, without
the need of binding.
thank you anyway
Opti

···

Am 13.10.21 um 14:06 schrieb hmdne:

As I told you previously, it's

binding.local_variable_get(:variable_name)

Can you provide an example that shows where's the local variable, and from
where you want to access it?

You cannot “directly” access a local variable (or any other variable) outside of its scope. Doing so would violate the principle of variables having a “scope” in the first place.

Perhaps what you are looking for is actually an instance variable, or a global variable?

Tom.

···

On 13 Oct 2021, at 17:15, Die Optimisten <inform@die-optimisten.net> wrote:

Hi!
Yes, I want to know if there is a way to access it directly, without
the need of binding.
thank you anyway
Opti

Am 13.10.21 um 14:06 schrieb hmdne:

As I told you previously, it's

binding.local_variable_get(:variable_name)

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

You can always generate a binding on the fly. Other than that, I think no. ivars (@ variables) are located in respective objects, cvars (@@) in classes, gvars ($) in Kernel, and local variables are located in a scope, that binding references. And you can't get an access to the scope in other way than by generating a binding (or with eval - which also works in terms of bindings).

···

On 10/13/21 18:15, Die Optimisten wrote:

Hi!
Yes, I want to know if there is a way to access it directly, without
the need of binding.
thank you anyway
Opti

Am 13.10.21 um 14:06 schrieb hmdne:

As I told you previously, it's

binding.local_variable_get(:variable_name)

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

Hello,
as written in the beginning:
def mymeth
x=123
end

I know that's not the usual use of Ruby - maybe it is possible with
metaprogramming;
I don't want to bind every object manually.
So I'm looking for a method like: get_local_var(scope: :mymeth, var: :x)

thank you
Opti

···

Am 13.10.21 um 18:16 schrieb Xavier Noria:

Can you provide an example that shows where's the local variable, and
from where you want to access it?

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

It doesn't work this way. Every call to mymeth generates a new scope which gets discarded unless you generate a binding for it.

···

On 10/13/21 18:50, Die Optimisten wrote:

Hello,
as written in the beginning:
def mymeth
x=123
end

I know that's not the usual use of Ruby - maybe it is possible with metaprogramming;
I don't want to bind every object manually.
So I'm looking for a method like: get_local_var(scope: :mymeth, var: :x)

thank you
Opti

Am 13.10.21 um 18:16 schrieb Xavier Noria:

Can you provide an example that shows where's the local variable, and from where you want to access it?

Unsubscribe:<mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

Consider the following:

def mymeth
   x=rand()
end

Or:

def mymeth
   x=external_api_call()
end

def mymeth
   x=1
   x=2
   x=3
   return “something_else"
end

What would you expect get_local_var(scope: :mymeth, var: :x) to return?
Should it call the method, including triggering any side-effects, and potentially return a different value every time?
Should it return the value of `x` at the start, middle or end of the method?
Should all methods always expose the stack of local variables alongside the “real” return value?

In short: That’s not how it works; you cannot access local variables outside of their scope. The whole point of local variables is that they are local.
If you could access them elsewhere, then they wouldn’t really be “local”.

···

On 13 Oct 2021, at 17:50, Die Optimisten <inform@die-optimisten.net> wrote:

Hello,
as written in the beginning:
def mymeth
   x=123
end

I know that's not the usual use of Ruby - maybe it is possible with metaprogramming;
I don't want to bind every object manually.
So I'm looking for a method like: get_local_var(scope: :mymeth, var: :x)

thank you
Opti

So the question is:
how can I get the binding of an [existing] method (not able to modify it)

-> how do I get all bindings, and detect the type of it (class, obj,
method, etc)?

thank you
Opti

···

Am 13.10.21 um 18:54 schrieb hmdne:

It doesn't work this way. Every call to mymeth generates a new scope
which gets discarded unless you generate a binding for it.

It doesn't work this way. Every call to mymeth generates a new scope
which gets discarded unless you generate a binding for it.

So the question is:
how can I get the binding of an [existing] method (not able to modify it)

You must call `binding` inside that method and save it somewhere

-> how do I get all bindings, and detect the type of it (class, obj,
method, etc)?

You can use ObjectSpace.each_object(Binding).to_a to get every generated binding that hasn't been GC'd yet.

You can call binding.receiver to get a `self` reference of that binding.

You can call binding.eval('__callee__') to get a method name (for binding generated inside classes it will return nil)

···

On 10/13/21 19:03, Die Optimisten wrote:

Am 13.10.21 um 18:54 schrieb hmdne:

Hello,

A nice example!
So - as speaking in C:
it should return the content (object) of the memory-location where x
point to.
I assume
x=1; x=2 uses the same location for x (and does not allocate 2 times).
when referencing a function (rand) it would return the value
assigning to x;
meaning (hopefully) null if not executed yet. - The result of rand()
must be saved somewhere after executing the method.

Is x=1; x=2; x=3; removed by optimization, when not ever using x ?

···

Am 13.10.21 um 19:03 schrieb Tom Lord:

Consider the following:

def mymeth
x=rand()
end

Or:

def mymeth
x=external_api_call()
end

def mymeth
x=1
x=2
x=3
return “something_else"
end

Hey Die, I wonder if you might be interested in becoming a core Ruby dev
over time. ?

Given your deep interest some of these technical details, I bet you could
become a contributor !

I'm not really a C dev, but the code is out there ... I say go for it !!
Ruby could use the help !

:+1:

···

On Wed, Oct 13, 2021 at 1:17 PM Die Optimisten <inform@die-optimisten.net> wrote:

Hello,

A nice example!
So - as speaking in C:
it should return the content (object) of the memory-location where x
point to.
I assume
   x=1; x=2 uses the same location for x (and does not allocate 2 times).
   when referencing a function (rand) it would return the value
assigning to x;
   meaning (hopefully) null if not executed yet. - The result of rand()
must be saved somewhere after executing the method.

Is x=1; x=2; x=3; removed by optimization, when not ever using x ?

Am 13.10.21 um 19:03 schrieb Tom Lord:
> Consider the following:
>
> def mymeth
> x=rand()
> end
>
> Or:
>
> def mymeth
> x=external_api_call()
> end
>
> def mymeth
> x=1
> x=2
> x=3
> return “something_else"
> end
>

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

--
A musician must make music, an artist must paint, a poet must write, if he
is to be ultimately at peace with himself.
- Abraham Maslow

Here's some more evil code that should never be used :slight_smile:

$ cat foo.rb
#!/usr/lib/fullstaq-ruby/versions/3.0-jemalloc/bin/ruby

def meth
  x = 42
end # line 5

# needs to be the "new" debugger
require 'debug'
binding.break do: <<~END
  # break on line 5 and set $foo
  b 5 do: eval $foo = x
END

p [:before, $foo]
meth
p [:after, $foo]

$ ./foo.rb
...(rdbg:binding.break) b 5 do: eval $foo = x
[:before, nil]
...(rdbg:break) eval $foo = x
[:after, 42]

(snipped out the verbosity of the debugger)

···

On 10/13/21, Die Optimisten <inform@die-optimisten.net> wrote:

as written in the beginning:
def mymeth
    x=123
end
I don't want to bind every object manually.

In general, programming languages deal with this problem with a stack.

In general, if you write a C code like this:

int *func1() {
int a = 7;
return &a;
}
int *func2() {
int b = 9;
return &b;
}
int main() {
int *p1, *p2;
p1 = func1();
p2 = func2();
// p1 should == p2
}

Why is that so, you may ask. Well - this is a very bad pattern, even compiler informs you of it:

test.c: In function ‘func1’:
test.c:3:10: warning: function returns address of local variable [-Wreturn-local-addr]
3 | return &a;
> ^~
test.c: In function ‘func2’:
test.c:7:10: warning: function returns address of local variable [-Wreturn-local-addr]
7 | return &b;
>

Why? Actually what used to be a is now overwritten when func2 is called. In fact, in C local variables are located on this stack. If you were to allocate something you would want to return, you would allocate it on the heap using malloc.

It's quite different in Ruby - here you can save a stack by saving a binding instance or a proc (which also contains a parent binding - you can call eg. proc{}.binding to extract it). Ruby implements all this in a very different way, because it's a high level language with support for closures - I suggest you learn about it: Closure (computer programming) - Wikipedia

While C does the memory management quite automatically with regards to a stack, and you must free objects on the heap, Ruby employs something called a GC, which once upon a time finds which objects are abandoned and removes them from memory.

Let's take a different code, which would highlight differences about how Ruby works, this time with procs, not bindings, but bindings will work as well:

[1] pry(main)> def gen_proc
[1] pry(main)* z = rand
[1] pry(main)* proc { z }
[1] pry(main)* end
=> :gen_proc
[2] pry(main)> p1 = gen_proc
=> #<Proc:0x000055b504b15620 (pry):3>
[3] pry(main)> p2 = gen_proc
=> #<Proc:0x000055b504bc2e10 (pry):3>
[4] pry(main)> p3 = gen_proc
=> #<Proc:0x000055b504b51af8 (pry):3>
[5] pry(main)> p1.call
=> 0.34886341505360474
[6] pry(main)> p2.call
=> 0.06557228535986404
[7] pry(main)> p3.call
=> 0.6650679529981015
[8] pry(main)> p1.call
=> 0.34886341505360474
[9] pry(main)> p2.call
=> 0.06557228535986404
[10] pry(main)> p3.call
=> 0.6650679529981015
[11] pry(main)>

See how eg. p3.call always returns the same value. This is closures at work. Do note, that all 3 individual values of z won't get deallocated by the GC if p1, p2 or p3 are still referenced. It is not that `gen_proc` holds anything, but the 3 respective stacks do, stack is referenced by a binding and binding by a proc.

···

On 10/13/21 19:17, Die Optimisten wrote:

Hello,

A nice example!
So - as speaking in C:
it should return the content (object) of the memory-location where x
point to.
I assume
x=1; x=2 uses the same location for x (and does not allocate 2 times).
when referencing a function (rand) it would return the value
assigning to x;
meaning (hopefully) null if not executed yet. - The result of rand()
must be saved somewhere after executing the method.

Is x=1; x=2; x=3; removed by optimization, when not ever using x ?

Am 13.10.21 um 19:03 schrieb Tom Lord:

Consider the following:

def mymeth
x=rand()
end

Or:

def mymeth
x=external_api_call()
end

def mymeth
x=1
x=2
x=3
return “something_else"
end

Unsubscribe: <mailto:ruby-talk-request@ruby-lang.org?subject=unsubscribe>
<ruby-talk list: member options login page>

Die Optimisten wrote:

A nice example!
So - as speaking in C:
it should return the content (object) of the memory-location where x
point to.

In C, a local variable/pointer would be allocated on the stack or in a register (optimizer decides).
If the function was never called it would have never been allocated.
If the function was exited then the stack may have been overwritten (unreliable).
If the function was called and you were in function nested underneath it, you might be able to access it on the stack.

There is no reason to assume that. In ruby, a variable is a reference to an
object; the storage attaches to the object, not to the variable.

Consider:
x = 10
y = x
y = 20

martin

···

On Wed, Oct 13, 2021 at 10:17 AM Die Optimisten <inform@die-optimisten.net> wrote:

I assume
   x=1; x=2 uses the same location for x (and does not allocate 2 times).

Likewise :slight_smile:

$ cat bar.rb
#!/usr/lib/fullstaq-ruby/versions/3.0-jemalloc/bin/ruby
require 'rensei'
$bindings = {}

def meth
  x = rand
end

p meth, $bindings
puts

eval <<~END
  def meth
    begin
      #{
        Rensei.unparse(
          RubyVM::AbstractSyntaxTree.of(
            method(:meth)
          )
        )
      }
    ensure
      $bindings[[self, __method__]] = binding
    end
  end
END

p meth, $bindings
p $bindings[[self, :meth]].local_variable_get(:x)
p $bindings[[self, :meth]].local_variable_get(:x)
p $bindings[[self, :meth]].local_variable_get(:x)
puts

p meth, $bindings
p $bindings[[self, :meth]].local_variable_get(:x)
p $bindings[[self, :meth]].local_variable_get(:x)
p $bindings[[self, :meth]].local_variable_get(:x)
puts

module Mod
  def self.meth
    y = rand
  end
end

p Mod.meth, $bindings
puts

eval <<~END
  def Mod.meth
    begin
      #{
        Rensei.unparse(
          RubyVM::AbstractSyntaxTree.of(
Mod.method(:meth)
          )
        )
      }
    ensure
      $bindings[[self, __method__]] = binding
    end
  end
END

p Mod.meth, $bindings
p $bindings[[Mod, :meth]].local_variable_get(:y)
p $bindings[[Mod, :meth]].local_variable_get(:y)
p $bindings[[Mod, :meth]].local_variable_get(:y)
puts

p Mod.meth, $bindings
p $bindings[[Mod, :meth]].local_variable_get(:y)
p $bindings[[Mod, :meth]].local_variable_get(:y)
p $bindings[[Mod, :meth]].local_variable_get(:y)
puts

$ ./bar.rb
0.9643116068264609
{}

0.02842814636779123
{[main, :meth]=>#<Binding:0x00007bd237e84e70>}
0.02842814636779123
0.02842814636779123
0.02842814636779123

0.6696453472343303
{[main, :meth]=>#<Binding:0x00007bd237e84830>}
0.6696453472343303
0.6696453472343303
0.6696453472343303

0.9617944924642181
{[main, :meth]=>#<Binding:0x00007bd237e84830>}

0.6628385990769972
{[main, :meth]=>#<Binding:0x00007bd237e84830>, [Mod,
:meth]=>#<Binding:0x00007bd237e93718>}
0.6628385990769972
0.6628385990769972
0.6628385990769972

0.3539253468317246
{[main, :meth]=>#<Binding:0x00007bd237e84830>, [Mod,
:meth]=>#<Binding:0x00007bd237e93150>}
0.3539253468317246
0.3539253468317246
0.3539253468317246

···

On 10/13/21, Die Optimisten <inform@die-optimisten.net> wrote:

as written in the beginning:
def mymeth
    x=123
end
I don't want to bind every object manually.

Here's some more evil code that should never be used :slight_smile:

Oh!
we could do an experts-competition who writes the best
'never-should-be-used' code ;))

hm I agree, seems development of a new language is concluded so far - at
least for the next months...

If s.o. is interested in doing such a thing, please let me know!

Opti

···

Am 15.10.21 um 02:04 schrieb Frank J. Cameron:

On 10/13/21, Die Optimisten <inform@die-optimisten.net> wrote:

as written in the beginning:
def mymeth
     x=123
end
I don't want to bind every object manually.

Here's some more evil code that should never be used :slight_smile:

Likewise :slight_smile:

$ cat bar.rb
#!/usr/lib/fullstaq-ruby/versions/3.0-jemalloc/bin/ruby
require 'rensei'
$bindings = {}

[...]

I havew to add:
i meant "if s.o. is interested in developing a new language/fork/...,
please let me know!"
(Also 'never-should-be-used' code is very interesting, too! :slight_smile:
Opti

···

Am 15.10.21 um 09:25 schrieb Die Optimisten:

Oh!
we could do an experts-competition who writes the best
'never-should-be-used' code ;))

hm I agree, seems development of a new language is concluded so far - at
least for the next months...

If s.o. is interested in doing such a thing, please let me know!

Opti

Am 15.10.21 um 02:04 schrieb Frank J. Cameron:

On 10/13/21, Die Optimisten <inform@die-optimisten.net> wrote:

as written in the beginning:
def mymeth
x=123
end
I don't want to bind every object manually.

Here's some more evil code that should never be used :slight_smile:

Likewise :slight_smile:

$ cat bar.rb
#!/usr/lib/fullstaq-ruby/versions/3.0-jemalloc/bin/ruby
require 'rensei'
$bindings = {}

[...]