David A. Black wrote:
This concept of “context”, though, seems like a bit of a retro-fit;
after all, scope (as reflected in, say, visibility of local variables)
and setting of self (i.e., what’s the default receiver) vary
independently and don’t necessarily fall easily under one master term.
I think that’s what bothers me about this: it strikes me as a hybrid,
ad hoc way to achieve something that is neither really a closure nor
(in my opinion) really in keeping with the usual behavior and purpose
of #instance_eval.
But a closure is just code + context. For example, when you implement a
simple Lisp-like
interpreter, the easiest thing to do with a lambda expression is leave
it be, like so:
(lambda () (+ x x)) => (lambda () (+ x x))
Then when you get a lambda expression in the first position in a list,
you just eval the list
with the current environment. This gets you dynamic scoping, the
problem with which is
that:
(foo) and (let ((x 10)) (foo))
are potentially different (because foo’s value of x is whatever the
local value of x is). If you
don’t want dynamic scoping, you need to store the context in which foo
was defined, so you
turn lambda expressions into closures:
(lambda () (+ x x)) => (closure (lambda () (+ x x))
pointer-to-definition-environment)
Now when you call foo, it’s always in the same context. However, you
could theoretically
write an eval that ignores the context, and just evaluates the code in
the current context.
Proc objects are the same way. Code + context. #call works like a
normal closure
(same as calling the method in Scheme), while #?_eval replaces some of
the context.
I don’t know if there is a Lisp/Scheme idiom for this. I’ve not looked
at any Lisp
object systems. Not to mention that Lisp’s main data structure is the
data structure
used to write Lisp code, so it looks more consistent:
(eval '(some code)) or (some-method-that-evals-code a b '(some code))
versus:
eval <<-END_OF_CODE
some code
END_OF_CODE
or
some_method_that_evals_code a, b, <<-END_OF_CODE
some code
END_OF_CODE
That’s what I don’t like. (I’m not sure if that means I am purist or
just ignorant of some hybrid computer science concept which makes
sense of this
Actually I feel that “self.instance_eval” should be
a no-op, since what it conveys (absent the magic) is: execute what
follows, setting self to what it already is.
In some sense it is. self.instance_eval is a no-op with respect to
Strings passed in.
self.instance_eval is a no-op as long as you’re just talking about a
collection of code. It’s only
not a no-op when you take context into account.
I suppose you could make an argument that there should be separate
classes, one a code
object without context, and one a code object with context (possibly
with the latter a child
of the former). However, I don’t think the one without context would be
as generally useful,
and you’d end up with all sorts of confusion (like, you’d want blocks on
methods to be
closures, but then the only way to get a non-closure block would be to
call a method with
a regular block, so non-closure blocks would have to store closure
blocks or something like
that, and it would essentially mean that the #eval-ing of closures would
be covered by a
more complicated system).
I may have passed over that thread… I’ll look again.
The subject at the top of the thread was: Re: Controlled Block Variables
You actually replied to my first post about it basically saying you
didn’t like the idea of
blocks-as-just-code.
Then nothing after that so maybe you didn’t
read anything else.
Anyhow, this post has gone on way too long with my theoretical-ish
ramblings. I don’t
know how big a deal straight #eval of blocks would be (it’s not as
convenient as blocks
given to #instance_eval and #class_eval, which are very handy). I just
don’t like the
look of here-docs as code very much. 