Forums | Admin

Discussion Forums: open-discussion

Start New Thread Start New Thread

 

By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-04-30 13:48
I have decided to add this to Ick, provisionally called "letn." I have it working, however I want to conside rthe larger issue of how to make it axiomatic so that it's just another thing in the toolbox for building things like letn.

There's a task for it.

By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-03-12 22:57
"It's looking like there is no way to do this "cleanly" for any definition of "cleanly" that doesn't make me throw up."

That was close to my conclusion. I used a completely different trick for DLSs and Let: I created a wrapper for the current object and created methods for each variable in the let environment, e.g. if you declare let(a => :foo, b => :bar), it wraps whatever is bound to self and declares the methods a, a=, b, and b= in the wrapper. Then it evaluates the block inthe wrapper's environment.

I need to think about this for a while, I am considering the best way to introduce this to Ick while staying in Ick's philosophy.

Simply extending let to handle multiple bindings is close to the philosophy of let as Lisp defines it, but actually not close to the philosophy of Ick just yet. If you added this to let, how would multiple bindings work with Maybe?

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-12 22:20
For interest:

http://rafb.net/p/aDmxiq90.html

Shows the problem in a nutshell. Although a call to #local_variables shows that the variable has been bound after the Proc was created it still can't be referenced.

Evan Webb had the answer w.r.t. VCALL and LVAR nodes.

M.

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-12 22:18
Stupid rubyforge... i spent so long reformatting that damn source code!

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-12 22:16
It's looking like there is no way to do this "cleanly" for any definition of "cleanly" that doesn't make me throw up.

Here's what I came up with (based on Ara Howards local var binding trick and a suggestion from Joel VanderWerf):

def self.evaluates_in_calling_environment_multiple_bind
old_val = Thread.current[:val]
begin
define_method :evaluate do |values,proc|
values.each do |k,v|
var = k
Thread.current[:val] = v
eval( "#{var} = Thread.current[:val]", proc )
end
proc.call
end
ensure
Thread.current[:val] = old_val
end
true
end

Now this actually works it binds the local variables for the proc. However it also fails because the MRI has already compiled the code in the proc and, not finding the local variables you are trying to declare via let( :a => ..., :b => ... ) has turned them into VCALL nodes not LVAR nodes. This means that when the proc is finally called, even though the local variables are now defined, it still tries to make VCALLs and fails because no method a, b, or whatever is defined.

Possible ways around this are to use ruby2ruby to rewrite the original proc and inject the definition of a, b, ... into the source of the proc as if the variables had been defined there. And superimposing a method_missing onto self for the duration of the proc.call that implements a, a=, b, b=.

Neither solution is pretty although if I had to pick one I guess I'd go with ruby2ruby.

On the other hand, is passing the variables positionally that bad after all?

Regards,

Matt


By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-03-11 12:25
Please give it a try: how else will you learn?

Here's what I wrestle with: if you use eval to declare local variables, can we declare them without polluting to current binding? Yes, if we do so inside a lambda. But how do we then put the block inside that lambda?

Maybe the ruby-talk discussion goes into detail about bindings and environment trickery?

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-11 11:56
There has been an interesting discussion with Ara Howard, Joel VanderWerf, and Rober Dober on ruby-talk this last day about using eval to bind local variables.

I'm still trying to get my head around everything that's needed but if you don't beat me to it I might try and see if I can implement something using their trickery.


By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-03-11 03:44
Definitely not an easy problem. The DSLs and Let article describes a system where we bind them as methods of a new object and then do an instance_eval in the environment of the new object. Oh yes, and the new object also delegates to the existing self, so it appears as if they are simply bound.

I really would like a simpler solution.

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-10 17:56
Lord knows what has happened to my can "we can to be able"... jeez.

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-10 17:54
Ah, yes, I see what you mean. So we can to be able to do something like:

let( :p => Person.find( ... ), :d => Department.find( ... ), :b => Budget.find( ... ) ) { ... }

although, at this point, duplicating p, d, & b as block parameters doesn't make much sense. However my next move, binding local variables p, d, and b before the proc.call (without passing a value) faltered when I realised there is no programmatic way to bind a local var.

Hrmmm.

M.

By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-03-10 17:19
"if I write:

let( e1, e2, e3 )

I expect to declare:

{ |local_e1,local_e2,local_e3| ... }"

This is very obvious and easy to implement. The problem I have with its design is that e1, e2, and e3 might be complicated expressions:

let(
Person.find(:first, ...),
Department.find(:all, ...).select { ... },
Budget.find(:first, ... }) do |p, d, b|
...
end

Then I personally find it hard to match up person with p, department with d, and budget with b. Lisp's let does a nicer job:

(let (
(p (find 'first Person ...))
(d (find 'all Department ...))
(b (find 'first Budget ...)))
...)

I would prefer some sort of syntax that matches up the expressions with the variables rather than having us keep track of them by name, that's what I was trying to say.

By: Matt Mower
RE: let with multiple variables [ reply ]  
2008-03-10 14:12
I had a very brief look at that article but it's pretty involved so when I got the part about Let I couldn't really follow it.

I guess my confusing is that if I write:

let( e1, e2, e3 )

I expect to declare:

{ |local_e1,local_e2,local_e3| ... }

so I'm not clear where you are matching up "values with variable names".

It may be that a whole level of this discussion has flown over my head because I haven't done the required reading. But maybe there is a way you can summarize in 25 words or less?

M.


By: Reginald Braithwaite
RE: let with multiple variables [ reply ]  
2008-03-09 22:00
Matt:

What you suggest is easy to implement, but unwieldy since you have to match the values up with teh variable names.

I tried to fix this problem in:

http://weblog.raganwald.com/2007/03/approach-to-composing-domain-specific.html

However, that solution does a lot of mucking with the evaluation environment (evaluation chaining), so it has its issues as well.

I'd love to see something where the values and the names are close together, just like let in Scheme. The trick is, the expressions must be evaluated in the calling environment while leaving the body to be evaluated in the calling or value environment as the programmer dictates.

By: Matt Mower
let with multiple variables [ reply ]  
2008-03-09 21:32
I really like the let() form but it doesn't, currently, permit you to pass more than one expression, e.g.

let( expr1, expr2 ) { |a,b| ... expr of a & b ... }

is this deliberate? I guess one could use:

let( expr1 ) { |a| let( expr2) { |b| ... expr of a & b ... } }

but the form passing two variables seems much cleaner. Maybe it just didn't come up before?

Regards,

Matt