Implementing Kernel#local_variables

2 views
Skip to first unread message

Xue Yong Zhi

unread,
Jun 10, 2007, 11:19:53 PM6/10/07
to xruby...@googlegroups.com
To implement Kernel#local_variables, I am thinking to change the way we
handle ruby's local variable.

Right now we just use java's local variable to represent a ruby local
variable. So the following code in ruby:

a = 1

becomes this in java:

class XXX extends RubyProgram {
RubyValue run (...) {
RubyValue a = ObjectFactory.fixnum1;
}
}

But by doing this we can not get any information about java's local
variable, actually they are nameless in the compiled code.

So I am considering representing ruby local variable with java's public
field. So the above program will be compiled into:

class XXX extends RubyProgram {
public RubyValue a;

RubyValue run (...) {
a = ObjectFactory.fixnum1;
}
}

If we do this, Kernel#local_variables can be implemented with reflection.

It will take me a few days to finish this change and may not even work out.
Please let me know if you have better ideas.

_________________________________________________________________
Picture this – share your photos and you could win big!
http://www.GETREALPhotoContest.com?ocid=TXT_TAGHM&loc=us

femto gary

unread,
Jun 11, 2007, 10:21:12 AM6/11/07
to xruby...@googlegroups.com
I remeber that from jruby's post, they say that Java's stack
lacks many info where c ruby's stack needs,
I think the best stragety here will be trying to implement
kind of our stack infomation, like in SICP's ch4/ch5.
using public/reflection is not a good idea, it's ugly,
and I think it won't help implementing Binding, caller etc.

> Picture this - share your photos and you could win big!
> http://www.GETREALPhotoContest.com?ocid=TXT_TAGHM&loc=us
>
>
> >
>


--
Best Regards
XRuby http://xruby.com
femto http://hi.baidu.com/femto

Xue Yong Zhi

unread,
Jun 11, 2007, 10:37:00 AM6/11/07
to xruby...@googlegroups.com
An alternative is to have a Scope class(or call it LocalVarManager):

class Scope {
ArrayList local_vars = new ArrayList();

RubyValue getLocalVar(String name);
void setLocalVar(String name, RubyValue value);
}

I think jruby does this, but all local variable access will become java
method call. I am not sure how much performance penalty there will be. And
whatever we use are just internal details, user won't care much about it.

Right now I will try to use 'field' first, if it does not work out well,
will try Scope class later.

>From: "femto gary" <femt...@gmail.com>
>Reply-To: xruby...@googlegroups.com
>To: xruby...@googlegroups.com
>Subject: [xruby-devel] Re: Implementing Kernel#local_variables
>Date: Mon, 11 Jun 2007 22:21:12 +0800
>
>
>I remeber that from jruby's post, they say that Java's stack
>lacks many info where c ruby's stack needs,
>I think the best stragety here will be trying to implement
>kind of our stack infomation, like in SICP's ch4/ch5.
> using public/reflection is not a good idea, it's ugly,
>and I think it won't help implementing Binding, caller etc.

_________________________________________________________________
Like puzzles? Play free games & earn great prizes. Play Clink now.
http://club.live.com/clink.aspx?icid=clink_hotmailtextlink2

femto

unread,
Jun 11, 2007, 10:26:35 PM6/11/07
to xruby-devel
I think the priority we here is to support rails,
do rails use local_variables,Binding etc a lot? If so, then we need
to support that. Otherwise it is not important,or anyway, not that
important.
For public field implementation or scope manager implementation, I
don't care it for now,because
anyway we need to support rails for the first hand, and we can always
optimize later if things turns
out abnormally. And Just a ask, how does c ruby handle this? I believe
c's stack is also different with ruby's stack.
Some thoughts about implementation, if Java's stack can handle this
very easily, we can carry some SICP idea,
the eval/apply circle, and Frame, runtime Env Frame, every method call
new a new Env Frame, whose parent is the
original frame, and then the Binding environment points to that, it
can carry variables/binding info. Just some thoughts,
because I haven't read SICP ch4 and ch5.

On Jun 11, 10:37 pm, "Xue Yong Zhi" <zhixuey...@hotmail.com> wrote:
> An alternative is to have a Scope class(or call it LocalVarManager):
>
> class Scope {
> ArrayList local_vars = new ArrayList();
>
> RubyValue getLocalVar(String name);
> void setLocalVar(String name, RubyValue value);
>
> }
>
> I think jruby does this, but all local variable access will become java
> method call. I am not sure how much performance penalty there will be. And
> whatever we use are just internal details, user won't care much about it.
>
> Right now I will try to use 'field' first, if it does not work out well,
> will try Scope class later.
>

femto gary

unread,
Jun 15, 2007, 8:53:14 AM6/15/07
to xruby-devel
Having a peek around c ruby's code, I can see that:
#define PUSH_FRAME() do { \
struct FRAME _frame; \
_frame.prev = ruby_frame; \
_frame.tmp = 0; \
_frame.node = ruby_current_node; \
_frame.iter = ruby_iter->iter; \
_frame.argc = 0; \
_frame.flags = 0; \
_frame.uniq = frame_unique++; \
ruby_frame = &_frame

#define POP_FRAME() \
ruby_current_node = _frame.node; \
ruby_frame = _frame.prev; \
} while (0)

so c ruby also handle's frame its own way.

Ola Bini

unread,
Jun 15, 2007, 9:14:20 AM6/15/07
to xruby...@googlegroups.com
femto gary wrote:
> Having a peek around c ruby's code, I can see that:
> #define PUSH_FRAME() do { \
> struct FRAME _frame; \
> _frame.prev = ruby_frame; \
> _frame.tmp = 0; \
> _frame.node = ruby_current_node; \
> _frame.iter = ruby_iter->iter; \
> _frame.argc = 0; \
> _frame.flags = 0; \
> _frame.uniq = frame_unique++; \
> ruby_frame = &_frame
>
> #define POP_FRAME() \
> ruby_current_node = _frame.node; \
> ruby_frame = _frame.prev; \
> } while (0)
>
> so c ruby also handle's frame its own way.
> On 6/12/07, femto <femt...@gmail.com> wrote:
>

The MRI story is a little bit more complicated than that. Frame
information doesn't have anything to do with local variables. MRI uses a
scope for that. A scope also have static scope information in something
called an ivtbl, which the parser sets up. The difference is that the
ivtbl contains the names of local variables for that static scope, and a
scope is a new instance of struct containing values for the same static
scope.

The problem for blocks for example, is that they need to close around
the outer scopes (so scopes need to have parents), but they also need
the frame information where they were created, since the frame contains
the current method name, the current self and other details like that.

I'm sorry to say that Rails uses local variables and closures like this
extensively, also bindings. Some of the more strange block behavior seen
in much Ruby code also depends on this being really right.

I'm currently trying to refactor JRuby's Scope and Frame structures, but
it's quite hard since they information is so involved.


Cheers
Ola Bini

--
Ola Bini (http://ola-bini.blogspot.com)
JRuby Core Developer
Developer, ThoughtWorks Studios (http://studios.thoughtworks.com)

"Yields falsehood when quined" yields falsehood when quined.


Xue Yong Zhi

unread,
Jul 1, 2007, 11:46:52 PM7/1/07
to xruby-devel
Just FYI, this proposed change (use java fields to store ruby local
variables) does not work with recursive function calls. I am thinking
about other solutions now...

dreamhead

unread,
Jul 23, 2007, 3:13:15 AM7/23/07
to xruby...@googlegroups.com
Why not generate code like this?

class XXX extends RubyProgram {
RubyValue run (...) {
RubyArray a = ObjectFactory.fixnum1;
}

public RubyArray getLocalVars() {
return new RubyArray(new RubyString("a"), ...);
}
}

Because we know all local variables when we generate code, so you can
generate the method like this without reflection.

BTW, why does not the change work with recursive functions

Ye Zheng.

2007/7/2, Xue Yong Zhi <xue.yo...@gmail.com>:


--
Everything is simple!

Xue Yong Zhi

unread,
Jul 23, 2007, 11:27:39 AM7/23/07
to xruby...@googlegroups.com

>
>Because we know all local variables when we generate code, so you can
>generate the method like this without reflection.

That is a good suggestion. I will try it when I go back to this issue (may
be next week).

>BTW, why does not the change work with recursive functions
>

If the program is compiled into this:

class FooMethod extends RubyMethod {
public RubyValue a;

RubyValue run (...) {
a = ObjectFactory.fixnum1;
}
}

And we call FooMethod recusivelly, the frames (activation record of a method
call) will share the same set of location variables (all can modify 'a' in
the above example). Each activationrecord should have their own set of local
variables.

_________________________________________________________________
Local listings, incredible imagery, and driving directions - all in one
place! http://maps.live.com/?wip=69&FORM=MGAC01

femto gary

unread,
Jul 23, 2007, 11:40:51 AM7/23/07
to xruby...@googlegroups.com
do dreamhead's meaning by static or by dynamic?
if the information is static, then can't handle cases like eval:

def test(arg)
p local_variables
eval "#{arg}=2"
p local_variables
end
test("y")
###outputs
["arg"]
["arg", "y"]
as you can see, after eval, it will add a local_variable to the frame,
and the local_variable's name can be dynamic.

femto

unread,
Jul 23, 2007, 11:13:04 PM7/23/07
to xruby-devel
I'm thinking about another case,
often in the code there's little invocation to local_variables as well
as eval,
so there may be some optimization here:
if there's no local_variables call, we can just use no named local
variables in java.
if we need to support debug, then we can implment LocalVariableMapping
like in java,
if we need to support local_variables call in debugger, then we need
to implement env
model like mentioned in sicp. (but no fully sicp's env model needed to
be implement,
because in lisp, the calling to lambda always need bind to parent
environment. but ruby's different
from lisp, in ruby, parent method call's local_variables doesn't
exists in sub method calls).

the differnent stragety I mentioned above may be compiled with
different optimization levels, like gcc.
what is your guys' opinions?

dreamhead

unread,
Jul 24, 2007, 5:44:15 AM7/24/07
to xruby...@googlegroups.com
Great! That's what I want to know.
We can preserve a field for this purpose. The code will be like this:

class XXX extends RubyProgram {
RubyValue run (...) {
RubyArray a = ObjectFactory.fixnum1;
}

private RubyArray localVars;

public XXX() {
localVars = new RubyArray();
localVars.add(new RubyString("a"));
...
}

public RubyArray getLocalVars() {
return this.localVars;
}
}

For run method, if we eval something, we can get local vars from it (I
haven't known how to do it), and then add it into our field. Maybe
hash map is a good choice for possible duplication.

2007/7/23, femto gary <femt...@gmail.com>:


>
> do dreamhead's meaning by static or by dynamic?
> if the information is static, then can't handle cases like eval:
>
> def test(arg)
> p local_variables
> eval "#{arg}=2"
> p local_variables
> end
> test("y")
> ###outputs
> ["arg"]
> ["arg", "y"]
> as you can see, after eval, it will add a local_variable to the frame,
> and the local_variable's name can be dynamic.

--
Everything is simple!

Reply all
Reply to author
Forward
0 new messages