From: Pascal Costanza
Subject: Dynamically scoped functions
Date: 
Message-ID: <costanza-65382E.21360723042003@news.netcologne.de>
Hi everybody,

I have just recently made the interesting observation that dynamically 
scoped functions can form the basis of a nice generalization of 
aspect-oriented programming and standard method combinations in CLOS. 
Last weekend I have finished a paper on this issue that I have submitted 
to the post-Java workshop at this year's ECOOP (see http://prog.vub.ac.be/~wdmeuter/PostJava/).

I intend to submit this paper to SIGPLAN Notices as well - I think it 
makes a case for Common Lisp.

However, there are some things that make me wonder. For example, why is 
it that dynamically scoped functions have been abandoned in Common Lisp 
in the first place? The introduction of lexical scoping was an important 
step forward, but thankfully dynamically scoped variables had been kept. 
Why not the same for functions? Or am I really the first to discover 
this connection?

Any kind of feedback is appreciated. If you want to read the paper, see 
the above link, or contact me...


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie

From: Barry Margolin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <hhCpa.18$G25.659@paloalto-snr1.gtei.net>
In article <······························@news.netcologne.de>,
Pascal Costanza  <········@web.de> wrote:
>However, there are some things that make me wonder. For example, why is 
>it that dynamically scoped functions have been abandoned in Common Lisp 
>in the first place? The introduction of lexical scoping was an important 
>step forward, but thankfully dynamically scoped variables had been kept. 
>Why not the same for functions? Or am I really the first to discover 
>this connection?

Did the Lisp dialects that Common Lisp was derived from have
dynamically-scoped functions?  Maclisp was the primary ancestor of Common
Lisp, and I don't think it did.  It didn't have any local function bindings
at all, IIRC.

Anyway, dynamic function binding is easy to emulate using dynamic variable
bindings: just define a function that FUNCALLs the value of a special
variable, and bind the variable to the function you're interested.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, a Level(3) Company, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-A91E02.00444124042003@news.netcologne.de>
In article <················@paloalto-snr1.gtei.net>,
 Barry Margolin <··············@level3.com> wrote:

> Did the Lisp dialects that Common Lisp was derived from have
> dynamically-scoped functions?  Maclisp was the primary ancestor of Common
> Lisp, and I don't think it did.  It didn't have any local function bindings
> at all, IIRC.

So does this mean that Common Lisp was the first Lisp that had local 
function bindings? (Or better: The first Lisp-2? In Scheme, there is no 
difference between local function and local variable bindings, of 
course. Or was compatibility to Scheme a reason to include local 
function bindings in Common Lisp?)

> Anyway, dynamic function binding is easy to emulate using dynamic variable
> bindings: just define a function that FUNCALLs the value of a special
> variable, and bind the variable to the function you're interested.

Yes, that's exactly what I describe in my paper. I also add an implicit 
call-next-function definition that allows calling the previous function 
definition.


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Barry Margolin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <qVEpa.25$G25.928@paloalto-snr1.gtei.net>
In article <······························@news.netcologne.de>,
Pascal Costanza  <········@web.de> wrote:
>In article <················@paloalto-snr1.gtei.net>,
> Barry Margolin <··············@level3.com> wrote:
>
>> Did the Lisp dialects that Common Lisp was derived from have
>> dynamically-scoped functions?  Maclisp was the primary ancestor of Common
>> Lisp, and I don't think it did.  It didn't have any local function bindings
>> at all, IIRC.
>
>So does this mean that Common Lisp was the first Lisp that had local 
>function bindings? (Or better: The first Lisp-2? In Scheme, there is no 
>difference between local function and local variable bindings, of 
>course. Or was compatibility to Scheme a reason to include local 
>function bindings in Common Lisp?)

The other major Lisp dialect at the time when CL was being designed was
Interlisp, and I don't whether or not it had them.

I think local functions were included in CL for the same reasons they exist
in many other block-structured languages (e.g. Algol) -- to reduce clutter
in the global namespace and to provide mnemonic names for closures.  This
is also why Scheme has them.  Note that Maclisp didn't really have closures
(it could sometimes fake them), so the second reason wouldn't have applied.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, a Level(3) Company, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-006F19.01074224042003@news.netcologne.de>
In article <················@paloalto-snr1.gtei.net>,
 Barry Margolin <··············@level3.com> wrote:

> >So does this mean that Common Lisp was the first Lisp that had local 
> >function bindings? (Or better: The first Lisp-2? In Scheme, there is no 
> >difference between local function and local variable bindings, of 
> >course. Or was compatibility to Scheme a reason to include local 
> >function bindings in Common Lisp?)
> 
> The other major Lisp dialect at the time when CL was being designed was
> Interlisp, and I don't whether or not it had them.
> 
> I think local functions were included in CL for the same reasons they exist
> in many other block-structured languages (e.g. Algol) -- to reduce clutter
> in the global namespace and to provide mnemonic names for closures.  This
> is also why Scheme has them.  Note that Maclisp didn't really have closures
> (it could sometimes fake them), so the second reason wouldn't have applied.

The second reason I have given is compatibility of Common Lisp to 
Scheme, so your explanation sounds a little confusing to me. I suppose I 
haven't parsed your statement correctly, so could you please explain 
that again?

Thanks a lot,
Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Barry Margolin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <lLGpa.27$G25.1232@paloalto-snr1.gtei.net>
In article <······························@news.netcologne.de>,
Pascal Costanza  <········@web.de> wrote:
>In article <················@paloalto-snr1.gtei.net>,
> Barry Margolin <··············@level3.com> wrote:
>
>> >So does this mean that Common Lisp was the first Lisp that had local 
>> >function bindings? (Or better: The first Lisp-2? In Scheme, there is no 
>> >difference between local function and local variable bindings, of 
>> >course. Or was compatibility to Scheme a reason to include local 
>> >function bindings in Common Lisp?)
>> 
>> The other major Lisp dialect at the time when CL was being designed was
>> Interlisp, and I don't whether or not it had them.
>> 
>> I think local functions were included in CL for the same reasons they exist
>> in many other block-structured languages (e.g. Algol) -- to reduce clutter
>> in the global namespace and to provide mnemonic names for closures.  This
>> is also why Scheme has them.  Note that Maclisp didn't really have closures
>> (it could sometimes fake them), so the second reason wouldn't have applied.
>
>The second reason I have given is compatibility of Common Lisp to 
>Scheme, so your explanation sounds a little confusing to me. I suppose I 
>haven't parsed your statement correctly, so could you please explain 
>that again?

I was only referring to *my* reasons: first reason = reduce namespace
clutter, second reason = provide mnemonic names for closures.  Since
Maclisp didn't have closures, it certainly didn't need to have mnemonic
names for them, which is why it didn't have local functions.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, a Level(3) Company, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-E0689B.04365024042003@news.netcologne.de>
In article <·················@paloalto-snr1.gtei.net>,
 Barry Margolin <··············@level3.com> wrote:

> I was only referring to *my* reasons: first reason = reduce namespace
> clutter, second reason = provide mnemonic names for closures.  Since
> Maclisp didn't have closures, it certainly didn't need to have mnemonic
> names for them, which is why it didn't have local functions.

Ah, right, thanks.

BTW, I have just skimmed over the Interlisp manuals (1974 and 1985 
versions), and they don't seem to mention any facilities for defining 
local functions.

So now, it appears to me that local variable and function definitions 
were introduced alongside the discovery of the importance of lexical 
scoping, and therefore only lexically scoped local definitions were 
considered at that stage. Special variables were added as a special case 
on top of that. Does this sound correct? (At least, this would 
correspond to the reasoning in the lambda papers in which Steele and 
Sussman argue that dynamically scoped variables can be added on top of a 
purely lexically scoped Lisp dialect.)

So essentially, dynamically scoped functions had never been abandoned - 
it just didn't occur to anyone that they could be useful, so they were 
never actually _added_ in the first place? If this is true I really made 
an important observation...


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2404030917170001@192.168.1.51>
In article <······························@news.netcologne.de>, Pascal
Costanza <········@web.de> wrote:

> If this is true I really made 
> an important observation...

Yes, I think you're right.  For one thing, dynamic function binding
subsumes "trace" and "untrace" (and "advise", and maybe even before- and
after- methods too) and makes the resulting functionality thread-safe.

E.
From: Carl Shapiro
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ouyn0ifpv6o.fsf@panix3.panix.com>
···@jpl.nasa.gov (Erann Gat) writes:

> Yes, I think you're right.  For one thing, dynamic function binding
> subsumes "trace" and "untrace" (and "advise", and maybe even before- and
> after- methods too) and makes the resulting functionality thread-safe.

How do you consider advising a function to be thread-unsafe in the
first place?
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2404031240170001@k-137-79-50-101.jpl.nasa.gov>
In article <···············@panix3.panix.com>, Carl Shapiro
<·············@panix.com> wrote:

> ···@jpl.nasa.gov (Erann Gat) writes:
> 
> > Yes, I think you're right.  For one thing, dynamic function binding
> > subsumes "trace" and "untrace" (and "advise", and maybe even before- and
> > after- methods too) and makes the resulting functionality thread-safe.
> 
> How do you consider advising a function to be thread-unsafe in the
> first place?

I'm not sure I understand the question.  Advice is global*.  Anything
global is not thread-safe.

E.

* Advice is vendor-specific, not part of the spec, so there may be
implementations out there with thread-safe advice.  But MCL, the Lisp I
use, is not one of them.
From: Carl Shapiro
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ouy1xzq8ped.fsf@panix3.panix.com>
···@jpl.nasa.gov (Erann Gat) writes:

> I'm not sure I understand the question.  Advice is global*.  Anything
> global is not thread-safe.

Just because something is global does not automatically make it
thread-unsafe.

> * Advice is vendor-specific, not part of the spec, so there may be
> implementations out there with thread-safe advice.  But MCL, the Lisp I
> use, is not one of them.

Under MCL, is the act of advising or un-advising a function potentially
recklessly destructive?
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2504031054130001@k-137-79-50-101.jpl.nasa.gov>
In article <···············@panix3.panix.com>, Carl Shapiro
<·············@panix.com> wrote:

> ···@jpl.nasa.gov (Erann Gat) writes:
> 
> > I'm not sure I understand the question.  Advice is global*.  Anything
> > global is not thread-safe.
> 
> Just because something is global does not automatically make it
> thread-unsafe.

"Thread-unsafe" and "not thread-safe" are not synonymous.  But to be
precise: any global mutable state that is not protected by semaphors is
not thread-safe.

> > * Advice is vendor-specific, not part of the spec, so there may be
> > implementations out there with thread-safe advice.  But MCL, the Lisp I
> > use, is not one of them.
> 
> Under MCL, is the act of advising or un-advising a function potentially
> recklessly destructive?

This idea of "recklessly destructive" seems to have come out of left
field, but the answer is yes.  You can crash the MCL event loop (and thus
crash MCL) by calling advise (and only advise) with the wrong arguments. 
I believe this is true of ACL as well, but I don't have a copy at the
moment so I can't test it.

Note that the question of whether advice can be "recklessly destructive"
actually has nothing to do with threads.  Advice can be "recklessly
destructive" even in a single-threaded Lisp, e.g.: (advise cons
(blow-up-the-world))

E.
From: Steven M. Haflich
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <3EAA1CE2.4080702@alum.mit.edu>
Erann Gat wrote:

> This idea of "recklessly destructive" seems to have come out of left
> field, but the answer is yes.  You can crash the MCL event loop (and thus
> crash MCL) by calling advise (and only advise) with the wrong arguments. 
> I believe this is true of ACL as well, but I don't have a copy at the
> moment so I can't test it.

I'd like to return to the context of this thread, which is dynamic
binding of function names.  It is counterproductive to argue about
what the nature of tracing or advice would be without considering
that there are at least two implementations of advice that have
_very_ different semantics.

One strategy for advice places the advice in a closure over the
original definition, and sets the binding of the function name
to the wrapping closure.  This kind of advice can be implemented
more-or-less portably.

A different strategy for advice side-effects the function object
itself, so that the function object itself executes the advice
when called.

(ACL originally used the former implementation, but recently changed
to the latter.)

Within ANS semantics these two strategies differ only in that
prior execution of (function foo) will not see subsequently-applied
advice in the first streategy, but will see advice in the latter.
(Ditto mutatis mutandis for retraction of advice.)

But the difference become visible in other ways once dynamic
binding of function names is defined.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-F1732E.11073826042003@news.netcologne.de>
In article <················@alum.mit.edu>,
 "Steven M. Haflich" <·················@alum.mit.edu> wrote:

> One strategy for advice places the advice in a closure over the
> original definition, and sets the binding of the function name
> to the wrapping closure.  This kind of advice can be implemented
> more-or-less portably.

...and that's why I chose it, of course.

> A different strategy for advice side-effects the function object
> itself, so that the function object itself executes the advice
> when called.
> 
> (ACL originally used the former implementation, but recently changed
> to the latter.)

That's better.

> Within ANS semantics these two strategies differ only in that
> prior execution of (function foo) will not see subsequently-applied
> advice in the first streategy, but will see advice in the latter.
> (Ditto mutatis mutandis for retraction of advice.)
> 
> But the difference become visible in other ways once dynamic
> binding of function names is defined.

Yes. What I really would like to have, but can't implement portably [1], 
is that a dflet rebinds a function object with dynamic extent so that it 
covers also previously executed (function ...) forms. However, this 
shouldn't happen globally in the case of multithreading, but only for 
the current thread, so that a funcall on the object returned by a 
previous (function ...) form would execute the dynamically rebound 
version in the current thread, but not in other threads. If that's too 
costly I would at least like to see [2] the option to choose from, say, 
"thread-safe-dflet" for the case I have just described, and the other 
dflet for the simpler case that doesn't capture (function ...) 
executions.

Would this make sense?


Pascal



[1] nor at all yet, since I don't have an idea how I would approach it

[2] in an ideal world ;)

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2604030834260001@192.168.1.51>
In article <······························@news.netcologne.de>, Pascal
Costanza <········@web.de> wrote:

> Yes. What I really would like to have, but can't implement portably [1], 
> is that a dflet rebinds a function object with dynamic extent so that it 
> covers also previously executed (function ...) forms.

Why do you need that?  Why is it not enough to define a dynamic function
to simply do (funcall '#:some-gensym args) and then dynamically rebind
#:some-gensym?  (Someone (I think it was Barry) suggested this earlier.) 
It seems to me that does exactly what you want and can be implemented
portably.

E.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-AC15AF.00535727042003@news.netcologne.de>
In article <····················@192.168.1.51>,
 ···@jpl.nasa.gov (Erann Gat) wrote:

> > Yes. What I really would like to have, but can't implement portably [1], 
> > is that a dflet rebinds a function object with dynamic extent so that it 
> > covers also previously executed (function ...) forms.
> 
> Why do you need that?  Why is it not enough to define a dynamic function
> to simply do (funcall '#:some-gensym args) and then dynamically rebind
> #:some-gensym?  (Someone (I think it was Barry) suggested this earlier.) 
> It seems to me that does exactly what you want and can be implemented
> portably.

This works for functions that are defined as dynamically scoped from the 
outset. However, if you define a function as usual with defun, and later 
on change it to a dynamically scoped one you might miss the function 
objects that have been captured in between.

Of course, this could be interpreted as nitpicking...


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Thomas F. Burdick
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <xcvel3owyr8.fsf@famine.OCF.Berkeley.EDU>
Pascal Costanza <········@web.de> writes:

> In article <····················@192.168.1.51>,
>  ···@jpl.nasa.gov (Erann Gat) wrote:
> 
> > > Yes. What I really would like to have, but can't implement portably [1], 
> > > is that a dflet rebinds a function object with dynamic extent so that it 
> > > covers also previously executed (function ...) forms.
> > 
> > Why do you need that?  Why is it not enough to define a dynamic function
> > to simply do (funcall '#:some-gensym args) and then dynamically rebind
> > #:some-gensym?  (Someone (I think it was Barry) suggested this earlier.) 
> > It seems to me that does exactly what you want and can be implemented
> > portably.
> 
> This works for functions that are defined as dynamically scoped from the 
> outset. However, if you define a function as usual with defun, and later 
> on change it to a dynamically scoped one you might miss the function 
> objects that have been captured in between.
> 
> Of course, this could be interpreted as nitpicking...

And not only nitpicking, but I think the wrong semantics for Common
Lisp.  We're all comfortable with the way that dynamic scope and
lexical scope work with variables -- I'd say that, unless you have a
really good reason why it should be different, you should preserve
that for functions.  So, if a function is not globally special, a
local special declaration doesn't affect code that thinks it's
lexical.  Functions that are globally declaimed special behave
specially.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-CBD206.03452427042003@news.netcologne.de>
In article <···············@famine.OCF.Berkeley.EDU>,
 ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> > This works for functions that are defined as dynamically scoped from the 
> > outset. However, if you define a function as usual with defun, and later 
> > on change it to a dynamically scoped one you might miss the function 
> > objects that have been captured in between.
> > 
> > Of course, this could be interpreted as nitpicking...
> 
> And not only nitpicking, but I think the wrong semantics for Common
> Lisp.  We're all comfortable with the way that dynamic scope and
> lexical scope work with variables -- I'd say that, unless you have a
> really good reason why it should be different, you should preserve
> that for functions.  So, if a function is not globally special, a
> local special declaration doesn't affect code that thinks it's
> lexical.  Functions that are globally declaimed special behave
> specially.

I disagree, at least in the context of my paper which is to show the 
usefulness of dynamically scoped functions for aspect-oriented 
programming. In the context of AOP, it is important to be able to affect 
functions that have not been specifically prepared for being affected. 
(This is the "obliviousness" property.) So consider the following 
example:

(defun f (x) (* x x))

Later on you can say (redefdynfun f) in order to turn this into a 
dynamically scoped function. You can achieve the same effect by 
redefining it more explicitly as follows:

;; the old definition still exists, but now:
(defdynfun f (x) (* x x))

So this means that (redefdynfun f) just saves you to retype the complete 
function definition. This is _not_ the same as a (declare (special ...)) 
for local variables.


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Thomas F. Burdick
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <xcvznmbvlpo.fsf@conquest.OCF.Berkeley.EDU>
Pascal Costanza <········@web.de> writes:

> In article <···············@famine.OCF.Berkeley.EDU>,
>  ···@famine.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:
> 
> > > This works for functions that are defined as dynamically scoped from the 
> > > outset. However, if you define a function as usual with defun, and later 
> > > on change it to a dynamically scoped one you might miss the function 
> > > objects that have been captured in between.
> > > 
> > > Of course, this could be interpreted as nitpicking...
> > 
> > And not only nitpicking, but I think the wrong semantics for Common
> > Lisp.  We're all comfortable with the way that dynamic scope and
> > lexical scope work with variables -- I'd say that, unless you have a
> > really good reason why it should be different, you should preserve
> > that for functions.  So, if a function is not globally special, a
> > local special declaration doesn't affect code that thinks it's
> > lexical.  Functions that are globally declaimed special behave
> > specially.
> 
> I disagree, at least in the context of my paper which is to show the 
> usefulness of dynamically scoped functions for aspect-oriented 
> programming. In the context of AOP, it is important to be able to affect 
> functions that have not been specifically prepared for being affected. 
> (This is the "obliviousness" property.) So consider the following 
> example:
> 
> (defun f (x) (* x x))
> 
> Later on you can say (redefdynfun f) in order to turn this into a 
> dynamically scoped function. You can achieve the same effect by 
> redefining it more explicitly as follows:
> 
> ;; the old definition still exists, but now:
> (defdynfun f (x) (* x x))
> 
> So this means that (redefdynfun f) just saves you to retype the complete 
> function definition. This is _not_ the same as a (declare (special ...)) 
> for local variables.

But isn't (edefdynfun f) the same as (declaim (special #'f)) [if such
a thing existed]?  IE, old compiled references to #'f don't change to
be dynamic.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-BE84E3.00050828042003@news.netcologne.de>
In article <···············@conquest.OCF.Berkeley.EDU>,
 ···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) wrote:

> But isn't (edefdynfun f) the same as (declaim (special #'f)) [if such
> a thing existed]?  IE, old compiled references to #'f don't change to
> be dynamic.

Yes, that's currently the case. I don't see any way how to implement 
this differently. But I can imagine situations in which I wanted a more 
"encompassing" dynamic scope.

See my next post on this issue for more details.

Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Nikodemus Siivola
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8hu22$4uer7$1@midnight.cs.hut.fi>
Pascal Costanza <········@web.de> wrote:

> Later on you can say (redefdynfun f) in order to turn this into a 
> dynamically scoped function. You can achieve the same effect by 
> redefining it more explicitly as follows:

It's late, so forgive I may be missing something totally obvious here,
but why not do something like this:

 (defmacro with-defun (fname newdef &body body)
   `(unwind-protect
       (progn
          (save-def ,fname)
          (replace-def ,fname ,newdew)
          ,@body)
       (restore-def ,fname)))

 (with-defun (foo #'tmp-foo)
   (foo 'bar))

What did I miss? Why are save-def, replace-def and restore-def
unimplementable?

Cheers,

  -- Nikodemus
From: Gabe Garza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <878ytv78ce.fsf@ix.netcom.com>
Nikodemus Siivola <········@kekkonen.cs.hut.fi> writes:

> Pascal Costanza <········@web.de> wrote:
> 
> > Later on you can say (redefdynfun f) in order to turn this into a 
> > dynamically scoped function. You can achieve the same effect by 
> > redefining it more explicitly as follows:
> 
> It's late, so forgive I may be missing something totally obvious here,
> but why not do something like this:
> 
>  (defmacro with-defun (fname newdef &body body)
>    `(unwind-protect
>        (progn
>           (save-def ,fname)
>           (replace-def ,fname ,newdew)
>           ,@body)
>        (restore-def ,fname)))
> 
>  (with-defun (foo #'tmp-foo)
>    (foo 'bar))
> 
> What did I miss? 

Threads.

Gabe Garza
From: Nikodemus Siivola
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8hvlg$4uer7$2@midnight.cs.hut.fi>
Gabe Garza <·······@ix.netcom.com> wrote:

> Threads.

Ok. Why is the suggested approach more problematic with threads then
Pascal's solution?

Btw: I am quite convinced that something is wrong with my approach.
Something very basic in the semantics of CL is going to say NO. I just
know it. :/

Cheers,

  -- Nikodemus
From: Gabe Garza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <874r4j6qqd.fsf@ix.netcom.com>
Nikodemus Siivola <········@kekkonen.cs.hut.fi> writes:

> Gabe Garza <·······@ix.netcom.com> wrote:
> 
> > Threads.
> 
> Ok. Why is the suggested approach more problematic with threads then
> Pascal's solution?

It's not; but that doesn't mean it isn't a flaw in your approach. ;)

> 
> Btw: I am quite convinced that something is wrong with my approach.
> Something very basic in the semantics of CL is going to say NO. I just
> know it. :/
> 

Well, you'd obviously have to qualify exactly which functions can be
"rebound."  Rebinding functions in the COMMON-LISP package would
obviously be a no-no (for several reasons: you're likely to hose part
of the system; you may be rebinding a function that the compiler
inlines), as would rebinding functions that have are declared inline.
It also won't play with functions introduce by FLET or LABELS.

Other then that, I don't see any other fundamental reason why yours
wouldn't work.  You didn't even need to use SAVE-DEF, REPLACE-DEF,
etc.  in your example code--SYMBOL-FUNCTION would have been nearly as
concise:

(defmacro with-defun (fname newdef &body body)
  (let ((old-definition (gensym "OLD-DEFINITION")))
  `(let (,old-definition)
     (unwind-protect
	 (progn
	   (setf ,old-definition (symbol-function ,fname))
	   (setf (symbol-function ,fname) ,newdef)
	   ,@body)
     (when ,old-definition
       (setf (symbol-function ,fname) ,old-definition))))))

If you want to read about why (I think) this should work, check out
section 3.1.2.1.2.3 (whew!) in the HyperSpec.

Gabe Garza
From: Nikodemus Siivola
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j5al$51kmk$1@midnight.cs.hut.fi>
Gabe Garza <·······@ix.netcom.com> wrote:

> Well, you'd obviously have to qualify exactly which functions can be
> "rebound."  

This was exactly what I was hoping to avoid... But I am beginning to
believe that that cannot be done in general without either a code-walker
or redefined DEFUN: two major pains are inlined functions and functions in
COMMON-LISP package with explicit package notation (ie. cl:princ).

For a weakish obliviousness it would seem enough to redefine DEFUN as a
funcall to a function stored in a special variable, just as Pascal does
for DEFDYNFUN, and then just use DFLET.  Weakish because the "victim" code
cannot be totally oblivious -- it has to use the new DEFUN. Weakish
because this doesn't solve the problem for functions defined in CL.

For stronger obliviousness I suppose COMPILE-FILE and LOAD would have to
be redefined use the redefined DEFUN and create the special bindings for
any CL functions called (and transform cl:foo into cl-dyn:foo, or
something like that).

Am I totally of the wall here?

As always, trivial cases are trivial, and real life is more
complicated. ;)

Cheers,

  -- Nikodemus
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j77k$avo$1@f1node01.rhrz.uni-bonn.de>
Nikodemus Siivola wrote:

> For a weakish obliviousness it would seem enough to redefine DEFUN as a
> funcall to a function stored in a special variable, just as Pascal does
> for DEFDYNFUN, and then just use DFLET.  Weakish because the "victim" code
> cannot be totally oblivious -- it has to use the new DEFUN. Weakish
> because this doesn't solve the problem for functions defined in CL.

No, I don't think this would be too weak, because you can force any 
(source) code to use a redefined defun via a shadowing-import.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j5vi$14ce$1@f1node01.rhrz.uni-bonn.de>
Gabe Garza wrote:

> You didn't even need to use SAVE-DEF, REPLACE-DEF,
> etc.  in your example code--SYMBOL-FUNCTION would have been nearly as
> concise:

A minor note: Function names in Common Lisp are not necessarily symbols, 
but in the case of (setf f) they are lists. So you are better off with 
fdefinition instead of symbol-function.

Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Tim Bradshaw
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ey37k9eu9qx.fsf@cley.com>
* Nikodemus Siivola wrote:
> Ok. Why is the suggested approach more problematic with threads then
> Pascal's solution?

The suggested approach won't work with threads, because you clobber
the global value of the function, thus all other threads will see the
bound value too, which is generally extremely undesirable.

One fix people propose for this is to have code which runs on a thread
switch which arranges to swap back the `real' version of any locally
bound functions.  This approach doesn't work because it assumes a
bogus model of threading, in particular one in which a multithreaded
program is simulated by time-slicing on top of a serial machine. On a
machine with more than one CPU (which is almost any machine costing
more than a couple of thousand dollars now) there may be no thread
switches.

A correct fix is to globally replace the function by a small wrapper
which looks for the real function by searching a per-thread binding
stack.  This can easily be implemented using a special variable.
Outline code looks something like:

(defun foo (&rest args)
  ;; Obviously I'd do this with a macro
  (let ((found (assoc 'foo *function-bindings*)))
    (if found 
        (apply (cdr found) args)
        (progn
         ... global code of function here ...))))

Then binding a function consists of essentially:

(let ((*function-bindings*
       (cons (cons 'foo #'(lambda ...)) *function-bindings*)))
  ...)

I haven't checked Pascal's implementation, but from private mail I
assume that's what he does.  There are significant optimisations you
can do to prevent the binding stack getting too deep.

--tim
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j7jp$avq$1@f1node01.rhrz.uni-bonn.de>
Tim Bradshaw wrote:

> I haven't checked Pascal's implementation, but from private mail I
> assume that's what he does.  There are significant optimisations you
> can do to prevent the binding stack getting too deep.

Mine is a little bit different in that I use a different special 
variable per function, but apart from that the idea is similar.

(defvar *f* (lambda (...) default-implementation))

(defun f (&rest args)
   (apply *f* args))

(dflet ((f (...) local-implementation))
   ...)

=>

(let ((*f* (lambda (...) local-implementation)))
   ...)


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j4qf$13fi$1@f1node01.rhrz.uni-bonn.de>
Nikodemus Siivola wrote:
> Gabe Garza <·······@ix.netcom.com> wrote:
> 
>>Threads.
> 
> Ok. Why is the suggested approach more problematic with threads then
> Pascal's solution?

It seems to me that your solution is more or less the same as the one 
based on fluid-let in Scheme that I also describe in my paper. If so 
yours would have the same drawbacks.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2604032159560001@192.168.1.51>
In article <······························@news.netcologne.de>, Pascal
Costanza <········@web.de> wrote:

> In article <····················@192.168.1.51>,
>  ···@jpl.nasa.gov (Erann Gat) wrote:
> 
> > > Yes. What I really would like to have, but can't implement portably [1], 
> > > is that a dflet rebinds a function object with dynamic extent so that it 
> > > covers also previously executed (function ...) forms.
> > 
> > Why do you need that?  Why is it not enough to define a dynamic function
> > to simply do (funcall '#:some-gensym args) and then dynamically rebind
> > #:some-gensym?  (Someone (I think it was Barry) suggested this earlier.) 
> > It seems to me that does exactly what you want and can be implemented
> > portably.
> 
> This works for functions that are defined as dynamically scoped from the 
> outset. However, if you define a function as usual with defun, and later 
> on change it to a dynamically scoped one you might miss the function 
> objects that have been captured in between.
> 
> Of course, this could be interpreted as nitpicking...

Maybe, but I think it may be you've missed a subtle point: lexical vs.
dynamic refers to the scoping of *bindings*, not the state of objects. 
"Rebinding a function object" is a non-sensical phrase.  You can talk
about re-binding part of a function object's state (which is what you'd be
doing if you adopted Barry's suggestion), but rebinding the *object
itself* doesn't make sense; it would violate the principle of object
identity.

E.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-0E8704.00150028042003@news.netcologne.de>
In article <····················@192.168.1.51>,
 ···@jpl.nasa.gov (Erann Gat) wrote:

> Maybe, but I think it may be you've missed a subtle point: lexical vs.
> dynamic refers to the scoping of *bindings*, not the state of objects. 
> "Rebinding a function object" is a non-sensical phrase.  You can talk
> about re-binding part of a function object's state (which is what you'd be
> doing if you adopted Barry's suggestion), but rebinding the *object
> itself* doesn't make sense; it would violate the principle of object
> identity.

You're right insofar I have used bad terminology.

Here is a concrete example of what I want:

(defun f (x) (print x))

(setf *some-location* #'f)

(redefdynfun f)

(dflet ((f (x) (call-next-function (1+ x))))
  (funcall *some-location* 5))

I can imagine contexts in which I want this to print 6 instead of 5. 
However, there can also be situations in which printing 5 would be more 
correct. So it might be best to have two versions of dflet, say, 
strong-dflet for the former case and dflet for the latter.

I can't provide strong-dflet because there is no way to implement it 
portably.

I also know that (setf *some-location* 'f) would result in a "stronger" 
dflet in the example above, but I don't think that that's the right 
place to make the decision.

So yes, a strong-dflet would violate object identity to a certain 
degree, but object identity is not a sacred cow IMHO.


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2704031700470001@192.168.1.51>
In article <······························@news.netcologne.de>, Pascal
Costanza <········@web.de> wrote:

> In article <····················@192.168.1.51>,
>  ···@jpl.nasa.gov (Erann Gat) wrote:
> 
> > Maybe, but I think it may be you've missed a subtle point: lexical vs.
> > dynamic refers to the scoping of *bindings*, not the state of objects. 
> > "Rebinding a function object" is a non-sensical phrase.  You can talk
> > about re-binding part of a function object's state (which is what you'd be
> > doing if you adopted Barry's suggestion), but rebinding the *object
> > itself* doesn't make sense; it would violate the principle of object
> > identity.
> 
> You're right insofar I have used bad terminology.
> 
> Here is a concrete example of what I want:
> 
> (defun f (x) (print x))
> 
> (setf *some-location* #'f)
> 
> (redefdynfun f)
> 
> (dflet ((f (x) (call-next-function (1+ x))))
>   (funcall *some-location* 5))
>
> I can imagine contexts in which I want this to print 6 instead of 5. 
> However, there can also be situations in which printing 5 would be more 
> correct. So it might be best to have two versions of dflet, say, 
> strong-dflet for the former case and dflet for the latter.
> 
> I can't provide strong-dflet because there is no way to implement it 
> portably.
> 
> I also know that (setf *some-location* 'f) would result in a "stronger" 
> dflet in the example above, but I don't think that that's the right 
> place to make the decision.
> 
> So yes, a strong-dflet would violate object identity to a certain 
> degree, but object identity is not a sacred cow IMHO.

It is in Lisp.

Why is it so important to you to be able to do a strong-dflet on functions
that have been 1) defined with common-lisp:defun and 2) captured in some
other place?  It's only if both of these conditions hold that you can't
implement strong-dflet portably.

If you just make your own package that shadows defun you can do a portable
implementation that does exactly what you (seem to) want.  You can even do
a properly dynamically scoped (thread-safe) strong-dflet on anonymous
functions.

E.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8j6bq$14cg$1@f1node01.rhrz.uni-bonn.de>
Erann Gat wrote:

>>So yes, a strong-dflet would violate object identity to a certain 
>>degree, but object identity is not a sacred cow IMHO.
> 
> It is in Lisp.

I guess it doesn't need to be even in Lisp. I think my work on the 
dissection of object identity could make sense in Lisp, but I have to 
admit that I haven't checked this yet. 
(http://www.pascalcostanza.de/gilgul.html)

Anyway, this is off topic.

> Why is it so important to you to be able to do a strong-dflet on functions
> that have been 1) defined with common-lisp:defun and 2) captured in some
> other place?  It's only if both of these conditions hold that you can't
> implement strong-dflet portably.
> 
> If you just make your own package that shadows defun you can do a portable
> implementation that does exactly what you (seem to) want.  You can even do
> a properly dynamically scoped (thread-safe) strong-dflet on anonymous
> functions.

Yes, you're right. I have shortly thought about redefining defun at 
first but switched to the solution proposed in my paper very soon 
afterwards. I haven't thought about this possibility again in the 
context of a possible strong-dflet. Thanks for giving me this hint.


Pascal


-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-2804030846100001@192.168.1.51>
In article <·············@f1node01.rhrz.uni-bonn.de>, Pascal Costanza
<········@web.de> wrote:

> Erann Gat wrote:
> 
> >>So yes, a strong-dflet would violate object identity to a certain 
> >>degree, but object identity is not a sacred cow IMHO.
> > 
> > It is in Lisp.
> 
> I guess it doesn't need to be even in Lisp. I think my work on the 
> dissection of object identity could make sense in Lisp, but I have to 
> admit that I haven't checked this yet. 
> (http://www.pascalcostanza.de/gilgul.html)
> 
> Anyway, this is off topic.

For this thread perhaps, not for this newsgroup.

> > Why is it so important to you to be able to do a strong-dflet on functions
> > that have been 1) defined with common-lisp:defun and 2) captured in some
> > other place?  It's only if both of these conditions hold that you can't
> > implement strong-dflet portably.
> > 
> > If you just make your own package that shadows defun you can do a portable
> > implementation that does exactly what you (seem to) want.  You can even do
> > a properly dynamically scoped (thread-safe) strong-dflet on anonymous
> > functions.
> 
> Yes, you're right. I have shortly thought about redefining defun at 
> first but switched to the solution proposed in my paper very soon 
> afterwards. I haven't thought about this possibility again in the 
> context of a possible strong-dflet. Thanks for giving me this hint.

No problem.  BTW, I think this is a really great piece of work you've done.

E.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-5021FD.14452526042003@news.netcologne.de>
In article <······························@news.netcologne.de>,
 Pascal Costanza <········@web.de> wrote:

> I would at least like to see the option to choose from, say, 
> "thread-safe-dflet" for the case I have just described, and the other 
> dflet for the simpler case that doesn't capture (function ...) 
> executions.

The name "thread-safe-dflet" is nonsense - it should be "full-dflet", or 
something like that.


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Thomas F. Burdick
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <xcvllxz1lx9.fsf@conquest.OCF.Berkeley.EDU>
Pascal Costanza <········@web.de> writes:

> So essentially, dynamically scoped functions had never been abandoned - 
> it just didn't occur to anyone that they could be useful, so they were 
> never actually _added_ in the first place? If this is true I really made 
> an important observation...

The Emacs lisp flet and labels forms don't correspond to CL flet and
labels -- one is dynamic binding, the other lexical.  So there is at
least one Lisp dialect (Elisp with (require 'cl)) that has dynamically
scoped functions.  Also, with any Lisp dialect that has LETF, you can
LETF the function slot of a symbol.

I think you're not the first to discover that dynamically scoped
bindings are useful for the function slot (viz elisp), but maybe
outside the Elisp community.

-- 
           /|_     .-----------------------.                        
         ,'  .\  / | No to Imperialist war |                        
     ,--'    _,'   | Wage class war!       |                        
    /       /      `-----------------------'                        
   (   -.  |                               
   |     ) |                               
  (`-.  '--.)                              
   `. )----'                               
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8bgpf$11rs$1@f1node01.rhrz.uni-bonn.de>
Thomas F. Burdick wrote:
> Pascal Costanza <········@web.de> writes:
> 
>>So essentially, dynamically scoped functions had never been abandoned - 
>>it just didn't occur to anyone that they could be useful, so they were 
>>never actually _added_ in the first place? If this is true I really made 
>>an important observation...
> 
> The Emacs lisp flet and labels forms don't correspond to CL flet and
> labels -- one is dynamic binding, the other lexical.  So there is at
> least one Lisp dialect (Elisp with (require 'cl)) that has dynamically
> scoped functions.  Also, with any Lisp dialect that has LETF, you can
> LETF the function slot of a symbol.
> 
> I think you're not the first to discover that dynamically scoped
> bindings are useful for the function slot (viz elisp), but maybe
> outside the Elisp community.

OK, thanks for this information. You are right, I am obviously not the 
first one to discover the usefulness of dynamic scoping for functions, 
and I am grateful to the all the people who pointed out previous uses. 
However, I am at least the first one to state that the achievements of 
the AOP community can be reduced to dynamically scoped functions, with 
some slight additions.

There was an important paper in the AOP community written by Robert 
Filman and Daniel Friedman called "Aspect-Oriented Programming is 
Quantification and Obliviousness" (see 
http://arc.cs.odu.edu:8080/dp9/getrecord/oai_dc/oai:RIACS:00000046 and 
also 
http://arc.cs.odu.edu:8080/dp9/getrecord/oai_dc/oai:RIACS:00000048). So, 
to summarize this for Lisp: The quantification property can be 
implemented with macros and the obliviousness property can be 
implemented with dynamically scoped functions.

The minor additions I have made in my paper are:
- defdfun and makdfun provide a "structured" way to define functions as 
dynamically scoped ones.
- dflet allows you to redefine a function, and at the same time you can 
call the old definition via call-next-function. This call-next-function 
is the bit that makes dynamically scoped functions really useful for AOP.

Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Nikodemus Siivola
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8cdep$50vgb$1@midnight.cs.hut.fi>
Pascal Costanza <········@web.de> wrote:

> However, I am at least the first one to state that the achievements of 
> the AOP community can be reduced to dynamically scoped functions, with 
> some slight additions.

Brave man! You obviously aren't afraid of being called a smug lisp
weenie... ,) But seriously: I truly enjoyed your article.

Esthetics: 

 MAKDFUN *is* an eyesore. But MAKE-DFUN wouldn't be any better, since
 it implicate the creation of a new function, not the transformation
 of the old one.

 And I'd prefer DEF-DFUN to DEFDFUN: the latter is too visually similar to
 DEFUN to my poor eyes.

 Also, when trying to speak these out is sound like "DEFDEFUN". This might
 not happen to native speakers, but it does to me.

Idle chatter:

 Rethink the DFUN term -- there is ample potential for aural confusion
 with DEFUN there. How about SFUN, DYNFUN, or DYFUN?

 MAKDFUN could then be REBIND-AS-***. A bit longer, but nothing compared
 to MULTIPLE-VALUE-BIND. Alternatively DYNBIND, or REBIND-SPECIAL? The
 latter would go great with DEF-SPECIAL-FUN. 

Pardon the pun. ,)=

Cheers,

  -- Nikodemus
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-A10DF7.10535126042003@news.netcologne.de>
In article <··············@midnight.cs.hut.fi>,
 Nikodemus Siivola <········@kekkonen.cs.hut.fi> wrote:

> Pascal Costanza <········@web.de> wrote:
> 
> > However, I am at least the first one to state that the achievements of 
> > the AOP community can be reduced to dynamically scoped functions, with 
> > some slight additions.
> 
> Brave man! You obviously aren't afraid of being called a smug lisp
> weenie... ,)

King for a day, fool for a lifetime... ;)

> But seriously: I truly enjoyed your article.

Thanks a lot.

> Esthetics: 
> 
>  MAKDFUN *is* an eyesore.

See my other post on this. Your suggestions also helped a lot.


Thanks,
Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Pekka P. Pirinen
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <u4r4mfer0.fsf@globalgraphics.com>
Pascal Costanza <········@web.de> writes:
> So now, it appears to me that local variable and function definitions 
> were introduced alongside the discovery of the importance of lexical 
> scoping, and therefore only lexically scoped local definitions were 
> considered at that stage.

Well, lambda parameters are local variables, so local variables
existed from the beginning, and PROG introduced local bindings inside
functions very early on, but they were dynamically scoped in early
Lisps.  You are probably right that FLET/LABELS came along with ideas
of block structure and lexical scope being adopted in Lisps.

> Special variables were added as a special case on top of that. Does
> this sound correct? (At least, this would correspond to the
> reasoning in the lambda papers in which Steele and Sussman argue
> that dynamically scoped variables can be added on top of a purely
> lexically scoped Lisp dialect.)

They needed to address that because dynamically-scoped variables were
the norm in Lisp.  (They weren't called "special" then.)  However,
limited lexical closures (the FUNARG device) and lexical scope for
local variables in compiled code had existed since before LISP 1.5.
So lexical variables were really introduced into basically
dynamically-scoped implementations piecemeal.  The lambda papers
inspired later dialects (especially Scheme) to do it the other way
around.
-- 
Pekka P. Pirinen
The gap between theory and practice is bigger in practice than in theory.
From: Jeff Caldwell
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <a1Gpa.4067$Jf.1982511@news1.news.adelphia.net>
Pascal,

I really enjoyed the paper and have copied the code. Your work came 
along at the perfect time. It is interesting that you propose the new 
feature and provide an implementation of it. That's the joy of Lisp, 
that couldn't be done in a C++ or a Java, could it?

Your work is important to me because I've been playing around with 
prototyping simple GUI applications using:

1) instances of a data structure describing the pages, the navigation 
through them, the fields, text, and layout, the database access 
routines, and simple validation logic for each page

2) a template describing constants such as menus, navigations, side 
bars, and so forth for each page

3) definitions of classes, methods, macros, and functions to support it all

4) generation functions to emit code to support the GUI application

I have a set of generation functions for html and plan to write a few 
others, for demo purposes, probably Lisp, C++, and possibly Java.  I 
have hit the point where I was wondering how to call the appropriate 
generation routines depending upon the target language. I considered 
writing an interpreter, like the ones in Lisp In Small Pieces, for each 
target language.  I considered loading the generation file appropriate 
to the target language immediately prior to the generation.  I never 
considered case statements inside the generation functions. I couldn't 
find a satisfying approach.

Now I have a nice implementation of dynamic functions to try. Thanks!

While I was writing these programs, I first thought "I need more 
separation of data from programs than I see in Araneida or CL-HTTP". I 
looked at sample code from those or some other Lisp-based web servers 
and saw code very roughly like:

(p (b "This is bold") (a-href "http://click.net" "Clicki")))

and said "That ties the representation too closely to html. I can't get 
back inside the s-expressions to pull out the data to be able to present 
it in other languages."  I started by building data structures, maybe 
lists, maybe structures, maybe lists of CLOS instances. I then wrote 
code to pass over the structures, read the data, and emit code in the 
chosen target language.

I noticed that was dumb, I was coding up a structure and writing a macro 
to stuff the structure then turning around and pulling things back out 
of the structure. I realized I could simply use s-expressions in the 
first and last place to hold the data, thus eliminating the intermediate 
structures. I ended up with s-expressions that look like:

(p (b "This is bold") (a-href "http://click.net" "Clicki")))

Darn. Those guys were smart, after all, and it took me time and work to 
realize it.[1]  Seeing that was one of those beautiful Lisp moments when 
an important feature of Lisp's design comes crashing in on me.  Those 
s-expressions aren't code, they're data.

I subsequently realized that instead of writing code to pour through the 
s-expressions and emit the target language, using the car's to tag the 
data type of the s-expression, I could just defun or defmacro a "p", a 
"b", and an "a-href" and have a separate version of each for every 
target language. Those s-expressions aren't data, they're code.

I ended up with the need to have multiple sets of functions and macros 
with each set containing the same function names but different bodies 
depending upon my desired target language.  That was yesterday, 
literally. Today, you post your paper on dynamic functions.

Thanks, Pascal!

Jeff

[1]
I'm could not have done the same things with their s-expressions that I 
can do with mine. Redefining their "p" for my purposes probably would 
break the rest of their application. Using a fully-featured web server 
to generate a C++ GUI doesn't seem wise. I had to rewrite it all anyway.


Pascal Costanza wrote:
> Hi everybody,
> 
> I have just recently made the interesting observation that dynamically 
> scoped functions can form the basis of a nice generalization of 
> aspect-oriented programming and standard method combinations in CLOS. 
> Last weekend I have finished a paper on this issue that I have submitted 
> to the post-Java workshop at this year's ECOOP (see http://prog.vub.ac.be/~wdmeuter/PostJava/).
> 
> I intend to submit this paper to SIGPLAN Notices as well - I think it 
> makes a case for Common Lisp.
> 
> However, there are some things that make me wonder. For example, why is 
> it that dynamically scoped functions have been abandoned in Common Lisp 
> in the first place? The introduction of lexical scoping was an important 
> step forward, but thankfully dynamically scoped variables had been kept. 
> Why not the same for functions? Or am I really the first to discover 
> this connection?
> 
> Any kind of feedback is appreciated. If you want to read the paper, see 
> the above link, or contact me...
> 
> 
> Pascal
> 
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-447F40.04421524042003@news.netcologne.de>
In article <·····················@news1.news.adelphia.net>,
 Jeff Caldwell <·····@yahoo.com> wrote:

> Pascal,
> 
> I really enjoyed the paper and have copied the code. Your work came 
> along at the perfect time. It is interesting that you propose the new 
> feature and provide an implementation of it. That's the joy of Lisp, 
> that couldn't be done in a C++ or a Java, could it?

No, definitely not.

[...]
> I ended up with the need to have multiple sets of functions and macros 
> with each set containing the same function names but different bodies 
> depending upon my desired target language.  That was yesterday, 
> literally. Today, you post your paper on dynamic functions.
> 
> Thanks, Pascal!

Wow, that's what I call immediate feedback. :-)

I am very happy that this turned out to be useful to you.

You seem to indicate that dynamically scoped macros could also be 
useful, but they are in fact not in my paper. Am I interpreting your 
statements correctly? If so, what have you done about it?


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Jeff Caldwell
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gkIpa.4134$Jf.2025813@news1.news.adelphia.net>
What I've implemented so far uses both functions and macros. I'll need 
to sort through a refactoring using your code to see how it all fits 
together. I'll let you know what I learn.

Jeff


Pascal Costanza wrote:
> You seem to indicate that dynamically scoped macros could also be 
> useful, but they are in fact not in my paper. Am I interpreting your 
> statements correctly? If so, what have you done about it?
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-40AAF0.10270924042003@news.netcologne.de>
In article <·····················@news1.news.adelphia.net>,
 Jeff Caldwell <·····@yahoo.com> wrote:

> What I've implemented so far uses both functions and macros. I'll need 
> to sort through a refactoring using your code to see how it all fits 
> together. I'll let you know what I learn.

Forget what I have said about "dynamically scoped macros", that's 
nonsense. Macros are purely compile-time abstractions, so one can't add 
any kind of "stronger dynamicity" to them.

Things would be different if we would turn macros into first-class 
runtime abstractions, but I guess it's not clear how to do that in the 
first place...

So this means that you can only use dynamically scoped functions for 
overriding your base functions if your macro definitions are always the 
same.

Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Francois-Rene Rideau
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <87el3stj27.fsf@Samaris.tunes.org>
Jeff Caldwell <·····@yahoo.com> writes:
> (p (b "This is bold") (a-href "http://click.net" "Clicki")))
Yuck. Use Scribble instead :-)
	http://www.cliki.net/Scribble

> I ended up with the need to have multiple sets of functions and macros
> with each set containing the same function names but different bodies
> depending upon my desired target language.
That's also how Scribe does things.
	http://www-sop.inria.fr/mimosa/fp/Scribe/

[ Fran�ois-Ren� �VB Rideau | Reflection&Cybernethics | http://fare.tunes.org ]
[  TUNES project for a Free Reflective Computing System  | http://tunes.org  ]
In a five year period we can get one superb programming language.
Only we can't control when the five year period will begin. -- Alan Perlis
From: Jeff Caldwell
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gsRpa.4259$Jf.2157964@news1.news.adelphia.net>
I am using Scribble. In fact, I started with it. The "tour around the 
block" I described in my first post included that initial use of 
Scribble.  I know about the "yuck" factor - that was my initial 
reaction, too. I really tried to get away from it then found myself 
right back with it, to my great surprise.

The language-specific definitions are something like:

[<!-- main content area of page -->
<table width="100%" border="0" cellspacing="0" cellpadding="5">
   <tr>
     <td>,(generate-current-content)</td>
   </tr>
</table>]

Text between [ and ] is processed by Scribble. generate-current-content 
is (greatly abbreviated):

(defun generate-current-content ()
     (ht:concat-collected-strings
      (ht:collect-string
        [<center><h2>,(title *current-page*)</h2></center>])
      (ht:collect-string "<table width=100%>")
      (loop for field in (fields *current-page*)
        do (case (field-type field)
             ('button (ht:collect-string (html-for-button-field field)))
	    ('checkbox
               (ht:collect-string (html-for-checkbox-field field)))
	    ...
	    ('form (ht:collect-string (html-for-form-field field)))
	    (otherwise (error "invalid field type ~a" (field-type field)))))
      (ht:collect-string "</table>"))))

where field instances contains enough slots to describe one field. 
Fields get created with macros such as:

(defmacro make-radio-field (label sql-table name value checked)
   `(make-instance 'field
		  :field-type 'radio
		  :label ,label
		  :name ,name
		  :value ,value
		  :checked ,checked
		  :sql-table ,sql-table))

Another generate-current-content can be written for a different target 
language.  Then I thought it better to eliminate the need for the field 
instance. I was just stuffing things into the field and then pulling 
them back out. So I thought simply to keep the original form, something 
like:

(radio-field-group :name "yes-no"
   (radio-field :label "Yes" :value "y")
   (radio-field :label "No" :value "n"))

and walk through that form as data in generate-current-content, rather 
than stepping through a list of field instances.  Having things in field 
doesn't buy me anything.  That's why I said I was back to (p (b "This is 
bold")).

I realized I could eliminate generate-current-content if 
radio-field-group was a function call or macro (there I'm fuzzy on which 
is right for which circumstance, which is why I need time to answer 
Pascal's question) instead of simply a type tag.

If radio-field-group is a function, then it needs to generate html when 
I want html and LaTex when I want LaTex.  That's why Pascal's ideas for 
dynamic functions appealed to me.

So I'm definitely using Scribble, and I'm definitely using the 
at-first-ugly (p (b "This is bold")) forms.

If you (anyone) have made it this far in my post and have something to 
teach me, please jump on in. I'm hoping to learn something from this.

(Thanks for the link to Scribe, by the way. I'd seen it before but 
needed reminding.)


Jeff

Francois-Rene Rideau wrote:
> Jeff Caldwell <·····@yahoo.com> writes:
> 
>>(p (b "This is bold") (a-href "http://click.net" "Clicki")))
> 
> Yuck. Use Scribble instead :-)
> 	http://www.cliki.net/Scribble
> 
> 
>>I ended up with the need to have multiple sets of functions and macros
>>with each set containing the same function names but different bodies
>>depending upon my desired target language.
> 
> That's also how Scribe does things.
> 	http://www-sop.inria.fr/mimosa/fp/Scribe/
> 
> [ Fran�ois-Ren� �VB Rideau | Reflection&Cybernethics | http://fare.tunes.org ]
> [  TUNES project for a Free Reflective Computing System  | http://tunes.org  ]
> In a five year period we can get one superb programming language.
> Only we can't control when the five year period will begin. -- Alan Perlis
From: Paolo Amoroso
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <WKinPtf1ECm8Kp=9JPiEoLMj2sJL@4ax.com>
On Thu, 24 Apr 2003 00:16:06 GMT, Jeff Caldwell <·····@yahoo.com> wrote:

> Your work is important to me because I've been playing around with 
> prototyping simple GUI applications using:
> 
> 1) instances of a data structure describing the pages, the navigation 
> through them, the fields, text, and layout, the database access 
> routines, and simple validation logic for each page
[...]

I have just skimmed the Picasso GUI development environment papers, and I
seem to understand that it might provide some useful ideas along the lines
of your work:

  http://s2k-ftp.cs.berkeley.edu:8000/picasso/


Paolo
-- 
Paolo Amoroso <·······@mclink.it>
From: Kaz Kylheku
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <cf333042.0304240911.7d8e2cd3@posting.google.com>
Pascal Costanza <········@web.de> wrote in message news:<······························@news.netcologne.de>...
> However, there are some things that make me wonder. For example, why is 
> it that dynamically scoped functions have been abandoned in Common Lisp 
> in the first place? 

They haven't. Common Lisp manifests dynamically scoped functions in
the form of error handlers and restarts! Distributed condition
handling is a kind of AOP, so your observations are on the mark. Some
code identifies a situation in which it obtains advice on how to
proceed from some other code which is effectively instrumenting it.
This leads to a separation of concerns: the identification of a
situation, and the strategy for responding to it.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8bfmm$11ro$1@f1node01.rhrz.uni-bonn.de>
Kaz Kylheku wrote:
> Pascal Costanza <········@web.de> wrote in message news:<······························@news.netcologne.de>...
> 
>>However, there are some things that make me wonder. For example, why is 
>>it that dynamically scoped functions have been abandoned in Common Lisp 
>>in the first place? 
> 
> They haven't. Common Lisp manifests dynamically scoped functions in
> the form of error handlers and restarts! Distributed condition
> handling is a kind of AOP, so your observations are on the mark. Some
> code identifies a situation in which it obtains advice on how to
> proceed from some other code which is effectively instrumenting it.
> This leads to a separation of concerns: the identification of a
> situation, and the strategy for responding to it.

Yes, you're right. The important difference is that with conditions, you 
need to anticipate the locations that are to be instrumented whereas 
with dynamic functions you can rebind any function.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Alexander Schmolck
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <yfsadefwh4d.fsf@black132.ex.ac.uk>
Pascal Costanza <········@web.de> writes:

> Why not the same for functions? Or am I really the first to discover 
> this connection?

Interestingly enough, shortly before I read your post, I've been wondering
what the most straightforward way to get dynamically scoped functions in CL
would be. So thanks!

One reason why I thought this might be handy is for writing test code (to
dynamically shadow troublesome world-state dependent functions used for IO,
time/date, random number generation etc.).

Do schemers maybe use fluid-let for function rebindings?

'as

p.s. makddfun or so is really a bit of an eyesore.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8aubb$12v2$1@f1node01.rhrz.uni-bonn.de>
Alexander Schmolck wrote:
> Pascal Costanza <········@web.de> writes:
> 
>>Why not the same for functions? Or am I really the first to discover 
>>this connection?
> 
> Interestingly enough, shortly before I read your post, I've been wondering
> what the most straightforward way to get dynamically scoped functions in CL
> would be. So thanks!
> 
> One reason why I thought this might be handy is for writing test code (to
> dynamically shadow troublesome world-state dependent functions used for IO,
> time/date, random number generation etc.).

Yes, these are among the typical proposed applications of AOP.

> Do schemers maybe use fluid-let for function rebindings?

fluid-let can be used for single-threaded applications but this would 
break in multi-threaded ones, as I describe in my paper. (Essentially, 
fluid-let is implemented by side-effecting global variables, instead of 
passing a dynamic environment around.)

Someone has already pointed out to me that I was comparing apples and 
oranges in a sense. In Scheme, parameter objects implement "full" 
dynamic scoping as we know it in Common Lisp. I will update my paper 
soon to reflect this.

> 'as
> 
> p.s. makddfun or so is really a bit of an eyesore.

Do you mean the name or the semantics? I like makdfun because it's 
short. It also has the same number of characters as defdfun. The other 
alternative would have been to name those macros define-dynamic-function 
and make-dynamic-function, which would still be not quite correct. I 
don't think the term "dynamic function" would be correct but it should 
in fact be "dynamically-scoped-function" (yuck). Furthermore, 
make-dynamic-function would not be correct because it would resemble 
make-instance, etc., and the semantics are quite different.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Joe Marshall
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <znmeelu2.fsf@ccs.neu.edu>
> Alexander Schmolck wrote:
> 
> > Do schemers maybe use fluid-let for function rebindings?
> 

Pascal Costanza <········@web.de> writes:
> fluid-let can be used for single-threaded applications but this would
> break in multi-threaded ones, as I describe in my paper. (Essentially,
> fluid-let is implemented by side-effecting global variables, instead
> of passing a dynamic environment around.)

That's not necessarily true.  A `shallow bound' fluid-let would not
exhibit this problem, nor would a `deep bound' fluid-let that swapped
the bindings on a stack switch.  Both of these mechanisms are
available in MIT Scheme (although I don't think you can switch between
them at runtime).

Since MIT Scheme has function caching (like UUO-links), fluid-letting
a procedure can cause a tremendous amount of computation to be done.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b8bfcn$11rm$1@f1node01.rhrz.uni-bonn.de>
Joe Marshall wrote:

> Pascal Costanza <········@web.de> writes:
> 
>>fluid-let can be used for single-threaded applications but this would
>>break in multi-threaded ones, as I describe in my paper. (Essentially,
>>fluid-let is implemented by side-effecting global variables, instead
>>of passing a dynamic environment around.)
> 
> That's not necessarily true.  A `shallow bound' fluid-let would not
> exhibit this problem, nor would a `deep bound' fluid-let that swapped
> the bindings on a stack switch.  Both of these mechanisms are
> available in MIT Scheme (although I don't think you can switch between
> them at runtime).

OK, I was talking about MzScheme here that in fact uses the scheme (ha!) 
I describe. Thanks for correcting me.

> Since MIT Scheme has function caching (like UUO-links), fluid-letting
> a procedure can cause a tremendous amount of computation to be done.

Yes, I haven't considered efficiency. But that's not important to me 
anyway...


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Tim Bradshaw
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ey3znmefs2j.fsf@cley.com>
* Joe Marshall wrote:

> That's not necessarily true.  A `shallow bound' fluid-let would not
> exhibit this problem, nor would a `deep bound' fluid-let that swapped
> the bindings on a stack switch.  

If there are stack switches.
From: Joe Marshall
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <vfx2a220.fsf@ccs.neu.edu>
Tim Bradshaw <···@cley.com> writes:

> * Joe Marshall wrote:
> 
> > That's not necessarily true.  A `shallow bound' fluid-let would not
> > exhibit this problem, nor would a `deep bound' fluid-let that swapped
> > the bindings on a stack switch.  
> 
> If there are stack switches.

<pedantic> ... nor would a fluid-let that was carefully written to
present the appropriate bindings in the appropriate
context. </pedantic>
From: Tim Bradshaw
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ey33ck6wdb2.fsf@cley.com>
* Joe Marshall wrote:
> <pedantic> ... nor would a fluid-let that was carefully written to
> present the appropriate bindings in the appropriate
> context. </pedantic>

Is using the evil *ML syntax in CLL no longer punishable by death by a
thousand tedious rants?  Enquiring minds want to know!

--tim
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-79A6C4.14352426042003@news.netcologne.de>
In article <············@ccs.neu.edu>, Joe Marshall <···@ccs.neu.edu> 
wrote:

> Pascal Costanza <········@web.de> writes:
> > fluid-let can be used for single-threaded applications but this would
> > break in multi-threaded ones, as I describe in my paper. (Essentially,
> > fluid-let is implemented by side-effecting global variables, instead
> > of passing a dynamic environment around.)
> 
> That's not necessarily true.  A `shallow bound' fluid-let would not
> exhibit this problem, nor would a `deep bound' fluid-let that swapped
> the bindings on a stack switch.  Both of these mechanisms are
> available in MIT Scheme (although I don't think you can switch between
> them at runtime).

I have briefly checked the web pages about MIT Scheme, and I have only 
found more or less the same description for fluid-let that is also given 
the MzScheme docs. Both descriptions explicitly state that the behavior 
of fluid-let is achieved by side-effecting global variables.

Are these "shallow bound" and "deep bound" fluid-lets add-ons? Where do 
I find descriptions about them?


Thanks,
Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Joe Marshall
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <he8iaeru.fsf@ccs.neu.edu>
Pascal Costanza <········@web.de> writes:

> I have briefly checked the web pages about MIT Scheme, and I have only 
> found more or less the same description for fluid-let that is also given 
> the MzScheme docs. Both descriptions explicitly state that the behavior 
> of fluid-let is achieved by side-effecting global variables.

That's the effect, not the implementation.

> Are these "shallow bound" and "deep bound" fluid-lets add-ons? Where do 
> I find descriptions about them?

If you peruse the source code, you will see that fluid bindings in MIT
Scheme are done by installing a reference trap in the cell that holds
the binding.  The actual value is stored in a per-thread area.
From: Alexander Schmolck
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <yfssms6ulx9.fsf@black132.ex.ac.uk>
Pascal Costanza <········@web.de> writes:
> > Do schemers maybe use fluid-let for function rebindings?
> 
> fluid-let can be used for single-threaded applications but this would break in
> multi-threaded ones, as I describe in my paper. (Essentially, fluid-let is
> implemented by side-effecting global variables, instead of passing a dynamic
> environment around.)

I think I know how fluid-let works (and about the thread issues, but I think
they don't matter in this context as they equally apply to variable (rather
than function) rebinding). What I don't know with what usage scenarios in mind
fluid-lets were written and what actual usage they found. For all I know,
people might already frequently be using fluid-let for dynamically scoped
functions.

So this question was really just intended as an possible avenue of
investigation concerning your question "has anyone thought of this before?"
(of course what your paper proposes is much more general).

At least for the particular application I was thinking of (rebinding pesky
functions during testing) it wouldn't seem that unlikely to me. In fact it is
not entirely clear to me that this wouldn't work smoother in scheme, which
allows you to redefine anything you want, AFAIK. In CL one would likely be
troubled by the fact that quite a few of the candiates reside in cl:, right?

> Someone has already pointed out to me that I was comparing apples and oranges
> in a sense. In Scheme, parameter objects implement "full" dynamic scoping as
> we know it in Common Lisp. I will update my paper soon to reflect this.

I don't quite understand, do you maybe have an example for the difference
you're referring to handy?

> 
> 
> > 'as
> > p.s. makddfun or so is really a bit of an eyesore.
> 
> 
> Do you mean the name or the semantics? I like makdfun because it's short.

Well, this is of course a matter of taste, but: the name. To close to Fortran
for my liking (cryptic, unpronouncable, ugly). I can't really see why it has
to be short either. I mean, it is likely to be only used sparsely, and in
situations where horizontal space is not already at a premium. This, of
course, isn't true for dflet (which also introduces further indentation), so
here a short name seems more called for (dflet is also less cryptic than
makdfun).

how about, for example: dyn[amically]-rebind (or dynamicalize)?

Post- or prefixing something like 'dyn[-]' or 'special' for all the names
might also be a possibility.

I don't really mind that much, but I think that something fairly esoteric
(most people who stumble across lisp code using it might not have read your
paper about the funkiness of dynamic functions) that changes the semantics of
its argument quite drastically, as makdfun does, should have a name that draws
more attention to what it's doing.

> also has the same number of characters as defdfun. The other alternative would

Um, why is that important? I there a reason that defdfuns and rebindings
should line up?

> have been to name those macros define-dynamic-function and
> make-dynamic-function, which would still be not quite correct. I don't think
> the term "dynamic function" would be correct but it should in fact be
> "dynamically-scoped-function" (yuck). Furthermore, make-dynamic-function would
> not be correct because it would resemble make-instance, etc., and the
> semantics are quite different.

yes, above all make-dynamic-function sounds more like it would create
something new, I think the name should emphasize the change of the argument's
semantics.

> 
> 
> Pascal

'as
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-8AB54F.10483126042003@news.netcologne.de>
In article <···············@black132.ex.ac.uk>,
 Alexander Schmolck <··········@gmx.net> wrote:

> > Someone has already pointed out to me that I was comparing apples and 
> > oranges
> > in a sense. In Scheme, parameter objects implement "full" dynamic scoping 
> > as
> > we know it in Common Lisp. I will update my paper soon to reflect this.
> 
> I don't quite understand, do you maybe have an example for the difference
> you're referring to handy?

Yes, I just quote from an email I have received about this:

"A parameter is a specific value created with the `make-parameter'
function -- the result can be applied to no arguments to retrieve the
value, or one arg to set it, and `parameterize' is used to rebind the
value, much like `fluid-let'.  The major difference is that parameters
have thread-specific values -- when a thread is created, it inherits
current parameter values, and modifying them affects just that thread.
Therefore, using parameters is just the same as using dynamic CL
variables where each thread has its own dynamic value.

Lastly, and this is the important point, as soon as you have some way
to express dynamic values, and when functions are simple values, you
inevitably get the ability to do what you talk about.  Your example
translates to this MzScheme code:

  (define f (make-parameter print))
  (define (g x) ((f) x))
  (let ((h (lambda (x) (g x))))
    (parameterize ((f (lambda (x) (print (+ 1 x)))))
      (h 5)))
"


> > > p.s. makddfun or so is really a bit of an eyesore.
> > 
> > Do you mean the name or the semantics? I like makdfun because it's short.
> 
> Well, this is of course a matter of taste, but: the name. To close to Fortran
> for my liking (cryptic, unpronouncable, ugly). I can't really see why it has
> to be short either. I mean, it is likely to be only used sparsely, and in
> situations where horizontal space is not already at a premium. This, of
> course, isn't true for dflet (which also introduces further indentation), so
> here a short name seems more called for (dflet is also less cryptic than
> makdfun).

Thanks for insisting. I have brainstormed a little about the names, and 
I have come up with theses names:

defdynamic instead of defdfun
redefdynamic instead of makdfun

They go well with defgeneric - that's why I have chosen makdfun in the 
first place because we already have makunbound and so on. I like to keep 
with traditional naming schemes.

Now, dflet has become less straightforward because the term "dynamic 
function" or "dfun" doesn't appear anymore in the other macros. I am 
thinking about dlet, dynlet and dynalet. What would you prefer?


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Alexander Schmolck
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <yfsn0iduq6u.fsf@black132.ex.ac.uk>
Pascal Costanza <········@web.de> writes:

> > I don't quite understand, do you maybe have an example for the difference
> > you're referring to handy?
> 
> Yes, I just quote from an email I have received about this:
> 
> "A parameter is a specific value created with the `make-parameter'

Ah, I see you're refering to some non-standard construct (draft srfi39, if
anyone is interested <http://srfi.schemers.org/srfi-39/srfi-39.html>).

> Thanks for insisting. I have brainstormed a little about the names, and 
> I have come up with theses names:
> 
> defdynamic instead of defdfun
> redefdynamic instead of makdfun

Yes these are much better!

> 
> They go well with defgeneric - that's why I have chosen makdfun in the 
> first place because we already have makunbound and so on. I like to keep 
> with traditional naming schemes.
> 
> Now, dflet has become less straightforward because the term "dynamic 
> function" or "dfun" doesn't appear anymore in the other macros. I am 
> thinking about dlet, dynlet and dynalet. What would you prefer?

I'd go for dlet.

'as
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-044882.00504227042003@news.netcologne.de>
In article <···············@black132.ex.ac.uk>,
 Alexander Schmolck <··········@gmx.net> wrote:

> > defdynamic instead of defdfun
> > redefdynamic instead of makdfun
> 
> Yes these are much better!

I've been told that unfortunately, defdynamic already exist for 
something else in ISLISP. So I will now go for defdynfun, redefdynfun 
and dflet. That's also clearer.

Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <costanza-0763D2.10492926042003@news.netcologne.de>
In article <···············@black132.ex.ac.uk>,
 Alexander Schmolck <··········@gmx.net> wrote:

> > also has the same number of characters as defdfun. The other alternative 
> > would
> 
> Um, why is that important? I there a reason that defdfuns and rebindings
> should line up?

No, but it was a nice side effect. I had the idea that this might help 
when refactoring code, but I haven't actually checked.


Pascal

-- 
"If I could explain it, I wouldn't be able to do it."
A.M.McKenzie
From: Tim Bradshaw
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <ey3vfx1xzd3.fsf@cley.com>
* Alexander Schmolck wrote:
> I think I know how fluid-let works (and about the thread issues, but I think
> they don't matter in this context as they equally apply to variable (rather
> than function) rebinding). What I don't know with what usage scenarios in mind
> fluid-lets were written and what actual usage they found. For all I know,
> people might already frequently be using fluid-let for dynamically scoped
> functions.

The issue is whether you can write FLUID-LET - or in general any
dynamic binding construct - on top of a system which doesn't have one
in a thread-safe way.  Some lisp applications (notably CLIM) define
something called LETF which is the ultimate generalisation of this:
LETF is meant to be to SETF as LET is to SETQ.  So you should be able
to say:

   (letf (((symbol-function 'x) #'foo))
     ...)

This seems like a really cool idea, but I encourage anyone who thinks
this is easy to work out how to do this on a multithreaded
implementation which either doesn't have a convenient thread-switch
hook, or may not have thread switches at all (and note: any native
threaded system running on anything but the very lowest-end machines
will likely not have thread switches).

I suspect that Scheme implementations do FLUID-LET by requiring some
special variable-reference syntax like (fluid x) which gives the
system a chance to implement things using a thread-local binding stack
behind the scenes (or, alternatively, they just get it wrong).  That's
possibly marginally OK for a kind of cheap version of special
variables, but it's not OK for LETF, where the last thing you want is
to clutter everything with terrible syntactic warts (`Oh, yes, just
change all instances of (f x) to (funcall (fluid f) x)').

--tim
From: Kent M Pitman
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <sfwk7d4tyj3.fsf@shell01.TheWorld.com>
Pascal Costanza <········@web.de> writes:

> I have just recently made the interesting observation that dynamically 
> scoped functions can form the basis of a nice generalization of 
> aspect-oriented programming and standard method combinations in CLOS. 
> Last weekend I have finished a paper on this issue that I have submitted 
> to the post-Java workshop at this year's ECOOP 
> (see http://prog.vub.ac.be/~wdmeuter/PostJava/).

I was "away" when this topic was introduced.

There is a difference between dynamically scoped functions as a 
functionality and dynamically scoped functions as a syntactic device.
CL has the former, but not the latter.  That is to say, it's 
straightforward to add the ability to define a given function 
dynamically. e.g.,

 (defvar *foo* nil)

 (defun foo (&rest args)
   (if *foo* (apply *foo* args)
       (error "The function FOO is not locally defined.")))

 (defun foobar () (foo 3 4))

 (defun bar ()
   (cons (ignore-errors (foobar))
         (let ((*foo* #'*))
           (list (foobar)
                 (let ((*foo* #'+))
                   (foobar))))))

 (bar) => (NIL 12 7)

If you don't like the above syntax, you can add something nicer yourself.
Consider:

 (defun dynamic-function-trampoline (name function args)
   (if function 
       (apply function args)
     (error "The function ~S is not locally defined." name)))

 (defmacro define-dynamic-function (name &rest bvl-and-forms)
   (let ((specvar (intern (format nil "*~A Dynamic-Function*" name))))
     `(progn (defparameter ,specvar 
               ,(if bvl-and-forms
                    `#'(lambda ,@bvl-and-forms)
                    `nil))
             (eval-when (:execute :compile-toplevel :load-toplevel)
               (setf (get ',name 'dynamic-function) ',specvar))
             (defun ,name (&rest args)
               (dynamic-function-trampoline ',name ,specvar args))
             ',name)))

 (defmacro dynamic-flet (bindings &body forms)
   `(let ,(mapcar #'(lambda (binding)
                      (destructuring-bind (name bvl &body forms) binding
                        `(,(or (get name 'dynamic-function)
                               (error "~S is not a declared dynamic function name." 
                                      name))
                          #'(lambda ,bvl ,@forms))))
                  bindings)
        ,@forms))

And then you do:

 (define-dynamic-function foo (x y)
   (list x y))

 (defun foobar () (foo 3 4))

 (defun bar ()
   (cons (ignore-errors (foobar))
         (dynamic-flet ((foo (x y) (* x y)))
           (list (foobar)
                 (dynamic-flet ((foo (x y) (+ x y)))
                   (foobar))))))

 (bar) => ((3 4) 12 7)

Note also that you get good error checking if you do

 (dynamic-flet ((zap () 3)) (zap))
 ;; Error: ZAP is not a declared dynamic function name.
  
> I intend to submit this paper to SIGPLAN Notices as well - I think it 
> makes a case for Common Lisp.
> 
> However, there are some things that make me wonder. For example, why is 
> it that dynamically scoped functions have been abandoned in Common Lisp 
> in the first place? 

Because this is just a notation, and it's one people are prone to use
erroneously.  The most common reason it's requested is to redefine
system functions (e.g., for tracing).  Had we added this
functionality, we would have forbid it on system functions, since system
functions need to be optimizable.  

Also, conceptually, the reason there is a problem for system functions
is that there becomes fundamentally a question of the clash between
the unstoppable force and the impenetrable barrier--that is, the maker
of a given function has an interest in having you not redefine it.
You have an interest in overriding that.  Who should win?  By using
the above protocol, you get not only the capability of redefining, but
the clear understanding for everyone that anything defined by
DEFINE-DYNAMIC-FUNCTION should be expected to be redefinable
dynamically, while for other functions that you do not define this
way, you can reasonably assume they will not be dynamically redefined.
It's much easier to read programs when you know what to expect.

> The introduction of lexical scoping was an important 
> step forward, but thankfully dynamically scoped variables had been kept. 
> Why not the same for functions?

You can add this functionality for your own functions straightforwardly.

Standard disclaimer: I tested the above code only very lightly.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b97lsd$130c$1@f1node01.rhrz.uni-bonn.de>
Kent M Pitman wrote:
> Pascal Costanza <········@web.de> writes:
> 
> 
>>I have just recently made the interesting observation that dynamically 
>>scoped functions can form the basis of a nice generalization of 
>>aspect-oriented programming and standard method combinations in CLOS. 
>>Last weekend I have finished a paper on this issue that I have submitted 
>>to the post-Java workshop at this year's ECOOP 
>>(see http://prog.vub.ac.be/~wdmeuter/PostJava/).
[...]

> Standard disclaimer: I tested the above code only very lightly.

You haven't read my paper - it already contains working code. But thanks 
anyway.

Furthermore, the code in my paper allows you to call the previous 
definition via call-next-function. No big deal to implement, but I think 
that this is the essential bit that makes DSF useful - and it shows that 
DSF are a generalization of AOP.

Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Kent M Pitman
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <sfwel3cfrtq.fsf@shell01.TheWorld.com>
Pascal Costanza <········@web.de> writes:

> Kent M Pitman wrote:
> > Pascal Costanza <········@web.de> writes:
> >
> >> I have just recently made the interesting observation that
> >> dynamically scoped functions can form the basis of a nice
> >> generalization of aspect-oriented programming and standard method
> >> combinations in CLOS. Last weekend I have finished a paper on this
> >> issue that I have submitted to the post-Java workshop at this
> >> year's ECOOP (see http://prog.vub.ac.be/~wdmeuter/PostJava/).
> [...]
> 
> > Standard disclaimer: I tested the above code only very lightly.
> 
> You haven't read my paper 

Indeed.  Some day when I have more time.

> - it already contains working code. But thanks anyway.

Then I didn't understand what the whole point of this thread was.  If
you already knew how to implement the functionality, why were you
complaining that it was absent? 

 | For example, why is it that dynamically scoped functions have been
 | abandoned in Common Lisp in the first place? The introduction of
 | lexical scoping was an important step forward, but thankfully
 | dynamically scoped variables had been kept.  Why not the same for
 | functions? Or am I really the first to discover this connection?

Functionality that can be implemented in user code is not 'abandoned'.

Also, you can't abandon something that was never in the language in the
first place.

> Furthermore, the code in my paper allows you to call the previous
> definition via call-next-function. No big deal to implement, but I
> think that this is the essential bit that makes DSF useful - and it
> shows that DSF are a generalization of AOP.

It's about a 2-line change to the code I suggested.
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-0605031015460001@k-137-79-50-101.jpl.nasa.gov>
In article <···············@shell01.TheWorld.com>, Kent M Pitman
<······@world.std.com> wrote:

> > - it already contains working code. But thanks anyway.
> 
> Then I didn't understand what the whole point of this thread was.  If
> you already knew how to implement the functionality, why were you
> complaining that it was absent? 

I don't think he was complaining that it was absent, he was pointing out
that this Aspect-Oriented Programming thing that the Java people are
getting so excited about is an all-but-trivial hack in Lisp.

E.
From: Ed L Cashin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <873cjrmrae.fsf@cs.uga.edu>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <···············@shell01.TheWorld.com>, Kent M Pitman
> <······@world.std.com> wrote:
>
>> > - it already contains working code. But thanks anyway.
>> 
>> Then I didn't understand what the whole point of this thread was.  If
>> you already knew how to implement the functionality, why were you
>> complaining that it was absent? 
>
> I don't think he was complaining that it was absent, he was pointing out
> that this Aspect-Oriented Programming thing that the Java people are
> getting so excited about is an all-but-trivial hack in Lisp.

I'd be surprised if there's really nothing to it in the eyes of a
lisper.  Gregor Kiczales was one of the people involved in the
creation of CLOS and has also been one of the forerunners of aspect
oriented programming.

  http://www.cs.ubc.ca/~gregor/


-- 
--Ed L Cashin     PGP public key: http://noserose.net/e/pgp/
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-0605032012310001@192.168.1.51>
In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:

> ···@jpl.nasa.gov (Erann Gat) writes:
> 
> > In article <···············@shell01.TheWorld.com>, Kent M Pitman
> > <······@world.std.com> wrote:
> >
> >> > - it already contains working code. But thanks anyway.
> >> 
> >> Then I didn't understand what the whole point of this thread was.  If
> >> you already knew how to implement the functionality, why were you
> >> complaining that it was absent? 
> >
> > I don't think he was complaining that it was absent, he was pointing out
> > that this Aspect-Oriented Programming thing that the Java people are
> > getting so excited about is an all-but-trivial hack in Lisp.
> 
> I'd be surprised if there's really nothing to it in the eyes of a
> lisper.

"Nothing to it" and "built in to the language" are not quite the same thing.

E.
From: Ed L Cashin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <87znlzl4ns.fsf@cs.uga.edu>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:
>
>> ···@jpl.nasa.gov (Erann Gat) writes:
>> 
>> > In article <···············@shell01.TheWorld.com>, Kent M Pitman
>> > <······@world.std.com> wrote:
>> >
>> >> > - it already contains working code. But thanks anyway.
>> >> 
>> >> Then I didn't understand what the whole point of this thread was.  If
>> >> you already knew how to implement the functionality, why were you
>> >> complaining that it was absent? 
>> >
>> > I don't think he was complaining that it was absent, he was pointing out
>> > that this Aspect-Oriented Programming thing that the Java people are
>> > getting so excited about is an all-but-trivial hack in Lisp.
>> 
>> I'd be surprised if there's really nothing to it in the eyes of a
>> lisper.
>
> "Nothing to it" and "built in to the language" are not quite the same thing.

I suspected that maybe some of the AOP stuff was already covered by
existing lisp facilities, so I (as tactfully as possible) asked Gregor
Kiczales whether lisp already had the things in it that are in AOP,
and he said no.  

So that's one lisper, anyway, who doesn't consider AOP to be an
all-but-trivial hack nor something built into lisp.

-- 
--Ed L Cashin     PGP public key: http://noserose.net/e/pgp/
From: Erann Gat
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <gat-0605032340560001@192.168.1.51>
In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:

> ···@jpl.nasa.gov (Erann Gat) writes:
> 
> > In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:
> >
> >> ···@jpl.nasa.gov (Erann Gat) writes:
> >> 
> >> > In article <···············@shell01.TheWorld.com>, Kent M Pitman
> >> > <······@world.std.com> wrote:
> >> >
> >> >> > - it already contains working code. But thanks anyway.
> >> >> 
> >> >> Then I didn't understand what the whole point of this thread was.  If
> >> >> you already knew how to implement the functionality, why were you
> >> >> complaining that it was absent? 
> >> >
> >> > I don't think he was complaining that it was absent, he was pointing out
> >> > that this Aspect-Oriented Programming thing that the Java people are
> >> > getting so excited about is an all-but-trivial hack in Lisp.
> >> 
> >> I'd be surprised if there's really nothing to it in the eyes of a
> >> lisper.
> >
> > "Nothing to it" and "built in to the language" are not quite the same thing.
> 
> I suspected that maybe some of the AOP stuff was already covered by
> existing lisp facilities, so I (as tactfully as possible) asked Gregor
> Kiczales whether lisp already had the things in it that are in AOP,
> and he said no.  

Did he elaborate?

> So that's one lisper, anyway, who doesn't consider AOP to be an
> all-but-trivial hack nor something built into lisp.

Just to be clear, I'm not taking a position on whether Pascal is right or
wrong (I don't know enough about AOP to do that), all I'm saying is that
this (that dyanamic function binding subsumes AOP) is the point Pascal is
making in his paper.

E.
From: Ed L Cashin
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <87el3alqw1.fsf@cs.uga.edu>
···@jpl.nasa.gov (Erann Gat) writes:

> In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:
>
>> ···@jpl.nasa.gov (Erann Gat) writes:
...
>> > "Nothing to it" and "built in to the language" are not quite the same thing.
>> 
>> I suspected that maybe some of the AOP stuff was already covered by
>> existing lisp facilities, so I (as tactfully as possible) asked Gregor
>> Kiczales whether lisp already had the things in it that are in AOP,
>> and he said no.  
>
> Did he elaborate?

I asked him about Open Implementation and whether CLOS and the MOP had
already "gotten it right", and he said no, he didn't think so, that it
was a step.  "In many ways AOP was developed to give the additional
kinds of control needed to do OI in big systems."

Then he referred me to his student Yvonne Coady's FSE 2001 paper
available on his web page.  (He seemed kind of busy!  ;)

...
> Just to be clear, I'm not taking a position on whether Pascal is right or
> wrong (I don't know enough about AOP to do that), all I'm saying is that
> this (that dyanamic function binding subsumes AOP) is the point Pascal is
> making in his paper.

Sorry.  You caught me getting sloppy in the attribution of ideas.

-- 
--Ed L Cashin     PGP public key: http://noserose.net/e/pgp/
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b9ba99$u3a$1@f1node01.rhrz.uni-bonn.de>
Ed L Cashin wrote:
> ···@jpl.nasa.gov (Erann Gat) writes:
> 
>>In article <··············@cs.uga.edu>, Ed L Cashin <·······@uga.edu> wrote:
>>
>>>I suspected that maybe some of the AOP stuff was already covered by
>>>existing lisp facilities, so I (as tactfully as possible) asked Gregor
>>>Kiczales whether lisp already had the things in it that are in AOP,
>>>and he said no.  
>>
>>Did he elaborate?
> 
> I asked him about Open Implementation and whether CLOS and the MOP had
> already "gotten it right", and he said no, he didn't think so, that it
> was a step.  "In many ways AOP was developed to give the additional
> kinds of control needed to do OI in big systems."
> 
> Then he referred me to his student Yvonne Coady's FSE 2001 paper
> available on his web page.  (He seemed kind of busy!  ;)

Thanks a lot for this excellent hint. I have skipped briefly through 
that paper, and it gives some real world examples for aspects that 
reason about the dynamic control flow of a program. It's probably 
worthwhile to try to reimplement the examples using DSF, and see whether 
they turn out to be easier to understand.

Interestingly enough, they talk about dynamically scoped variables in 
the related works section, but obviously haven't made the quantum leap. 
(phew! ;)

Again, thanks!

Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b9atei$p8k$1@f1node01.rhrz.uni-bonn.de>
Ed L Cashin wrote:

> I suspected that maybe some of the AOP stuff was already covered by
> existing lisp facilities, so I (as tactfully as possible) asked Gregor
> Kiczales whether lisp already had the things in it that are in AOP,
> and he said no.

You should have insisted more.

But yes, there are things in AOP that have not been in CLOS/MOP. I am 
not so sure whether these things are really important, especially when 
seen in the light that other "old-time lispers" like Scott McKay say 
that they even try to avoid method combinations nowadays.

However, I want to make sure that I don't sound too overly negative: An 
important achievemont of the AOP community definitely is that they have 
found some good terminology to talk about things, like join points and 
pointcuts.

> So that's one lisper, anyway, who doesn't consider AOP to be an
> all-but-trivial hack nor something built into lisp.

Again, in programming language design it is not so much important 
whether something is trivial or not to implement, but whether you find 
good abstraction of common patterns.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Jeff Caldwell
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <9n_ta.12773$Jf.6614825@news1.news.adelphia.net>
It would be a help to me to understand how Kiczales' join points and 
weavers are accounted for in Pascal's paper on AOP and dynamic functions.

http://www.cs.ubc.ca/~gregor/kiczales-ECOOP1997-AOP.pdf

Ed L Cashin wrote:
...

>>I don't think he was complaining that it was absent, he was pointing out
>>that this Aspect-Oriented Programming thing that the Java people are
>>getting so excited about is an all-but-trivial hack in Lisp.
> 
> 
> I'd be surprised if there's really nothing to it in the eyes of a
> lisper.  Gregor Kiczales was one of the people involved in the
> creation of CLOS and has also been one of the forerunners of aspect
> oriented programming.
> 
>   http://www.cs.ubc.ca/~gregor/
> 
> 
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b9at04$p8i$1@f1node01.rhrz.uni-bonn.de>
Jeff Caldwell wrote:
> It would be a help to me to understand how Kiczales' join points and 
> weavers are accounted for in Pascal's paper on AOP and dynamic functions.
> 
> http://www.cs.ubc.ca/~gregor/kiczales-ECOOP1997-AOP.pdf

Joint points and pointcuts have been introduced in AspectJ as a way to 
reason about methods that are to be wrapped by before/after/around 
methods (or advice, as they are called in AspectJ). The simplest 
pointcuts are (1) either lists of single methods ("setX, setY, setZ"), 
or (2) all methods of a class (expressed by wildcards such as "*"). 
There are more complex pointcuts like (3) "all set methods", also 
expressed by wildcards ("set*"). (It's important to note here that no 
meta information about methods are, or could be, used. Pointcuts like 
this only reason about the actual method names, and nothing more.)

An aspect weaver is a kind of compiler that takes aspect specifications 
and Java sources and generates new Java sources with all the aspects 
woven in. The first AspectJ compilers worked like that, but in the 
meantime they have changed their approach.

In Common Lisp, concepts like join points and pointcuts can be expressed 
in terms of the MOP. Here is an example that expresses more or less the 
idea of the * wildcard in AspectJ:

(defclass myclass ()
   ((f :accessor f :initform 0)))

(defvar *v* (make-instance 'myclass))

(loop for method in (specializer-direct-methods (find-class 'myclass))
       when (typep method 'standard-writer-method)
       do (eval `(defmethod
                   ,(generic-function-name
                   (method-generic-function method)) :after
                   ,(method-lambda-list method)
                   (print 'fire))))

(setf (f *v*) 5)

FIRE
: 5

(f *v*)

: 5

(setf (f *v*) 7)

: FIRE
: 7

(f *v*)

: 7


It's easy to turn this into something based on DSF - this is why I was 
not particularly interested in talking about pointcuts in my paper.

In order to understand what Gregor Kiczales sees as advantages of AOP 
over CLOS+MOP, it might be instructive to read one of his earliest 
articles about AOP at http://doi.acm.org/10.1145/242224.242420

Essentially, he claims that CLOS was too dynamic and it's better and 
easier to understand method combinations when they are all processed at 
compile time and can't be changed afterwards. At least that's how I 
understand his view. (My understanding is partially supported by the 
statement that "EuLisp has a MOP which does some things more cleanly 
than the CLOS MOP" [1]. The main difference between EuLisp and CLOS/MOP 
is that EuLisp does all the processing of method combinations at load time.)


Pascal


[1] see http://www2.parc.com/csl/groups/sda/projects/mops/existing-mops.html

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Jeff Caldwell
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <iZfua.13289$Jf.6917286@news1.news.adelphia.net>
Pascal,

Thank you very much. It will be a few days before I have time to look at 
this and write some examples.

Jeff

Pascal Costanza wrote:
> Jeff Caldwell wrote:
> 
>> It would be a help to me to understand how Kiczales' join points and 
>> weavers are accounted for in Pascal's paper on AOP and dynamic functions.
...

> Joint points and pointcuts have been introduced in AspectJ as a way to 
> reason about methods that are to be wrapped by before/after/around 
...

> 
> Pascal
...
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b9ar9b$pkg$1@f1node01.rhrz.uni-bonn.de>
Ed L Cashin wrote:

>>I don't think he was complaining that it was absent, he was pointing out
>>that this Aspect-Oriented Programming thing that the Java people are
>>getting so excited about is an all-but-trivial hack in Lisp.
> 
> I'd be surprised if there's really nothing to it in the eyes of a
> lisper.  Gregor Kiczales was one of the people involved in the
> creation of CLOS and has also been one of the forerunners of aspect
> oriented programming.
> 
>   http://www.cs.ubc.ca/~gregor/

My paper has two messages:

(1) Dynamically scoped functions (DSF) are a generalization of AOP.

(2) It's easy to implement AOP-style DSF in Common Lisp.

I haven't found any hints in the literature that anybody has seen the 
connection between DSF and AOP yet. The connection between AOP and CLOS 
are the standard method combinations of CLOS that can be seen as 
precursors of some of the features of AspectJ. But neither CLOS nor 
AspectJ provide AOP in the form of DSF. So, in a sense, DSF are also a 
generalization of standard method combinations.

Gregor Kiczales was involved in the design of CLOS and of the MOP, and 
continued to work on his ideas in the context of Java. But that doesn't 
mean that any AOP approach in Common Lisp needs to have a relation to CLOS.

I my paper, I also hint towards how DSF can probably be implemented in 
other languages than Common Lisp - for example C++ and Haskell.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b97sh1$u9a$1@f1node01.rhrz.uni-bonn.de>
Kent M Pitman wrote:
> Pascal Costanza <········@web.de> writes:

>>
>>You haven't read my paper 
> 
> Indeed.  Some day when I have more time.

:)

>>- it already contains working code. But thanks anyway.
> 
> Then I didn't understand what the whole point of this thread was.  If
> you already knew how to implement the functionality, why were you
> complaining that it was absent? 

I wasn't complaining - I was just interested in the historical account. 
(And you have helped a lot in that regard.)

>  | For example, why is it that dynamically scoped functions have been
>  | abandoned in Common Lisp in the first place? The introduction of
>  | lexical scoping was an important step forward, but thankfully
>  | dynamically scoped variables had been kept.  Why not the same for
>  | functions? Or am I really the first to discover this connection?
> 
> Functionality that can be implemented in user code is not 'abandoned'.

Would "left out" be more appropriate? (as in, say, "Scheme has left out 
/ abandoned dynamically scoped variables"?)

> Also, you can't abandon something that was never in the language in the
> first place.

Actually, this was the part that I didn't understand at all in my 
original post. The spec explicitly says that special declarations cannot 
be applied to function bindings. My mental model made me think that 
dynamic scope for local function definitions (flet) must have been in 
the language at some stage. It came as a total surprise to me that flet 
and the like were relatively new at that time.

Had flet been part of older dynamically scoped Lisp dialects, functions 
would of course have also been dynamically scoped. I couldn't imagine 
that flet was _not_ part of older Lisp dialects.

>>Furthermore, the code in my paper allows you to call the previous
>>definition via call-next-function. No big deal to implement, but I
>>think that this is the essential bit that makes DSF useful - and it
>>shows that DSF are a generalization of AOP.
> 
> It's about a 2-line change to the code I suggested.

It's 4 lines in my code. See below.

Pascal


(eval-when (:compile-toplevel :load-toplevel :execute)
   (defvar *dynsyms* (make-hash-table :test #'equal)))

(defun make-dynsym (fname)
   (setf (gethash fname *dynsyms*) (gensym "*DYNSYM*-")))

(defun ensure-dynfun-form (fname &rest rest)
   (let ((dynsym (make-dynsym fname)))
     `(eval-when (:compile-toplevel :load-toplevel :execute)
        (defvar ,dynsym
          ,(if rest
             `(lambda ,@rest)
             `(if (fboundp ',fname)
                (fdefinition ',fname)
                (lambda (&rest args)
                  (cerror "Retry applying ~A to ~A."
                          "Undefined dynamic function ~A called with 
arguments ~A."
                          ',fname args)
                  (apply ',fname args)))))
        (defun ,fname (&rest args)
          (apply ,dynsym args)))))

(defmacro defdynfun (fname args &body body)
   (apply #'ensure-dynfun-form fname args body))

(defmacro redefdynfun (fname)
   (ensure-dynfun-form fname))

(defun getdynsym (fname)
   (let ((dynsym (gethash fname *dynsyms*)))
     (if dynsym dynsym
       (progn (cerror "Make ~A a dynamic function."
                      "Function ~A is not dynamic."
                      fname)
              (eval `(redefdynfun ,fname))
              (getdynsym fname)))))

(defmacro dflet1 ((fname (&rest args) &body funbody) &body dflbody)
   (let ((dynsym (getdynsym fname)))
     (with-gensyms (orgfun orgargs newargs)
       `(let* ((,orgfun ,dynsym)
               (,dynsym (lambda (&rest ,orgargs)
                          (flet ((call-next-function (&rest ,newargs)
                            (apply ,orgfun (if ,newargs ,newargs 
,orgargs))))
                            (destructuring-bind ,args ,orgargs
                              ,@funbody)))))
          (declare (ignorable ,orgfun))
          ,@dflbody))))

(defmacro dflet ((&rest decls) &body body)
   (reduce (lambda (decl result) `(dflet1 ,decl ,result)) decls
           :initial-value `(progn ,@body) :from-end t))

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)
From: Franz Kafka
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <tCPta.4551$RE5.3259@news01.roc.ny.frontiernet.net>
I read your paper but could not see how call-next-function was implemented
unless it was implemented with

(flet (call-next-function ...

but I could not find it in appendix A.

I am just curious about how it would be written.

Thanks.
From: Pascal Costanza
Subject: Re: Dynamically scoped functions
Date: 
Message-ID: <b98hum$1498$1@f1node01.rhrz.uni-bonn.de>
Franz Kafka wrote:
> I read your paper but could not see how call-next-function was implemented
> unless it was implemented with
> 
> (flet (call-next-function ...
> 
> but I could not find it in appendix A.

You have forgotten a paranthesis - it's (flet ((call-next-function ...

This is because flet allows you to define a set of functions, not just 
only one.

> I am just curious about how it would be written.

It's part of the definition for dflet1 - see lines 43-44.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  R�merstr. 164, D-53117 Bonn (Germany)