Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Dynamically scoped functions

11 views
Skip to first unread message

Pascal Costanza

unread,
Apr 23, 2003, 3:36:07 PM4/23/03
to
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

Barry Margolin

unread,
Apr 23, 2003, 4:00:13 PM4/23/03
to
In article <costanza-65382E...@news.netcologne.de>,

Pascal Costanza <cost...@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, barry.m...@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.

Pascal Costanza

unread,
Apr 23, 2003, 6:44:41 PM4/23/03
to
In article <hhCpa.18$G25...@paloalto-snr1.gtei.net>,
Barry Margolin <barry.m...@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.

Barry Margolin

unread,
Apr 23, 2003, 6:59:34 PM4/23/03
to
In article <costanza-A91E02...@news.netcologne.de>,

Pascal Costanza <cost...@web.de> wrote:
>In article <hhCpa.18$G25...@paloalto-snr1.gtei.net>,
> Barry Margolin <barry.m...@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.

Pascal Costanza

unread,
Apr 23, 2003, 7:07:42 PM4/23/03
to
In article <qVEpa.25$G25...@paloalto-snr1.gtei.net>,
Barry Margolin <barry.m...@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,

Jeff Caldwell

unread,
Apr 23, 2003, 8:16:06 PM4/23/03
to
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.

Barry Margolin

unread,
Apr 23, 2003, 9:05:21 PM4/23/03
to
In article <costanza-006F19...@news.netcologne.de>,

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.

Pascal Costanza

unread,
Apr 23, 2003, 10:36:50 PM4/23/03
to
In article <lLGpa.27$G25....@paloalto-snr1.gtei.net>,
Barry Margolin <barry.m...@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 Costanza

unread,
Apr 23, 2003, 10:42:15 PM4/23/03
to
In article <a1Gpa.4067$Jf.19...@news1.news.adelphia.net>,
Jeff Caldwell <jd...@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?

Jeff Caldwell

unread,
Apr 23, 2003, 10:53:00 PM4/23/03
to
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

Francois-Rene Rideau

unread,
Apr 24, 2003, 4:07:28 AM4/24/03
to
Jeff Caldwell <jd...@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

Pascal Costanza

unread,
Apr 24, 2003, 4:27:09 AM4/24/03
to
In article <gkIpa.4134$Jf.20...@news1.news.adelphia.net>,
Jeff Caldwell <jd...@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.

Jeff Caldwell

unread,
Apr 24, 2003, 9:15:56 AM4/24/03
to
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

Erann Gat

unread,
Apr 24, 2003, 12:17:17 PM4/24/03
to
In article <costanza-E0689B...@news.netcologne.de>, Pascal
Costanza <cost...@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.

Kaz Kylheku

unread,
Apr 24, 2003, 1:11:43 PM4/24/03
to
Pascal Costanza <cost...@web.de> wrote in message news:<costanza-65382E...@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.

Paolo Amoroso

unread,
Apr 24, 2003, 2:28:33 PM4/24/03
to
On Thu, 24 Apr 2003 00:16:06 GMT, Jeff Caldwell <jd...@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 <amo...@mclink.it>

Carl Shapiro

unread,
Apr 24, 2003, 3:11:27 PM4/24/03
to
g...@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?

Erann Gat

unread,
Apr 24, 2003, 3:40:17 PM4/24/03
to
In article <ouyn0if...@panix3.panix.com>, Carl Shapiro
<cshapi...@panix.com> wrote:

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.

Thomas F. Burdick

unread,
Apr 24, 2003, 8:05:22 PM4/24/03
to
Pascal Costanza <cost...@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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Alexander Schmolck

unread,
Apr 24, 2003, 8:33:22 PM4/24/03
to
Pascal Costanza <cost...@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.

Pascal Costanza

unread,
Apr 25, 2003, 5:15:13 AM4/25/03
to
Alexander Schmolck wrote:
> Pascal Costanza <cost...@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
mailto:cost...@web.de Institute of Computer Science III
http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

Joe Marshall

unread,
Apr 25, 2003, 9:41:09 AM4/25/03
to

> Alexander Schmolck wrote:
>
> > Do schemers maybe use fluid-let for function rebindings?
>

Pascal Costanza <cost...@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.

Pascal Costanza

unread,
Apr 25, 2003, 10:06:11 AM4/25/03
to
Joe Marshall wrote:

> Pascal Costanza <cost...@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 Costanza

unread,
Apr 25, 2003, 10:11:31 AM4/25/03
to

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 Costanza

unread,
Apr 25, 2003, 10:30:05 AM4/25/03
to
Thomas F. Burdick wrote:
> Pascal Costanza <cost...@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.

Tim Bradshaw

unread,
Apr 25, 2003, 12:41:08 PM4/25/03
to
* 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.

Carl Shapiro

unread,
Apr 25, 2003, 1:20:42 PM4/25/03
to
g...@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?

Erann Gat

unread,
Apr 25, 2003, 1:54:13 PM4/25/03
to
In article <ouy1xzq...@panix3.panix.com>, Carl Shapiro
<cshapi...@panix.com> wrote:

> g...@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.

Joe Marshall

unread,
Apr 25, 2003, 2:01:59 PM4/25/03
to
Tim Bradshaw <t...@cley.com> writes:

<pedantic> ... nor would a fluid-let that was carefully written to
present the appropriate bindings in the appropriate
context. </pedantic>

Tim Bradshaw

unread,
Apr 25, 2003, 4:08:01 PM4/25/03
to
* 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


Pekka P. Pirinen

unread,
Apr 25, 2003, 5:28:51 PM4/25/03
to
Pascal Costanza <cost...@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.

Nikodemus Siivola

unread,
Apr 25, 2003, 6:39:21 PM4/25/03
to
Pascal Costanza <cost...@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

Alexander Schmolck

unread,
Apr 25, 2003, 8:44:50 PM4/25/03
to
Pascal Costanza <cost...@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

Steven M. Haflich

unread,
Apr 26, 2003, 1:44:28 AM4/26/03
to
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.

Pascal Costanza

unread,
Apr 26, 2003, 4:48:31 AM4/26/03
to
In article <yfssms6...@black132.ex.ac.uk>,
Alexander Schmolck <a.sch...@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 Costanza

unread,
Apr 26, 2003, 4:49:29 AM4/26/03
to
In article <yfssms6...@black132.ex.ac.uk>,
Alexander Schmolck <a.sch...@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 Costanza

unread,
Apr 26, 2003, 4:53:51 AM4/26/03
to
In article <b8cdep$50vgb$1...@midnight.cs.hut.fi>,
Nikodemus Siivola <tsii...@kekkonen.cs.hut.fi> wrote:

> Pascal Costanza <cost...@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 Costanza

unread,
Apr 26, 2003, 5:07:38 AM4/26/03
to
In article <3EAA1CE2...@alum.mit.edu>,

"Steven M. Haflich" <smh_no_s...@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 ;)

Tim Bradshaw

unread,
Apr 26, 2003, 7:38:32 AM4/26/03
to
* 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

Pascal Costanza

unread,
Apr 26, 2003, 8:35:24 AM4/26/03
to
In article <znmeel...@ccs.neu.edu>, Joe Marshall <j...@ccs.neu.edu>
wrote:

> Pascal Costanza <cost...@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

Pascal Costanza

unread,
Apr 26, 2003, 8:45:25 AM4/26/03
to
In article <costanza-F1732E...@news.netcologne.de>,
Pascal Costanza <cost...@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

Erann Gat

unread,
Apr 26, 2003, 11:34:26 AM4/26/03
to
In article <costanza-F1732E...@news.netcologne.de>, Pascal
Costanza <cost...@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.

Alexander Schmolck

unread,
Apr 26, 2003, 1:24:57 PM4/26/03
to
Pascal Costanza <cost...@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

Pascal Costanza

unread,
Apr 26, 2003, 6:50:42 PM4/26/03
to
In article <yfsn0id...@black132.ex.ac.uk>,
Alexander Schmolck <a.sch...@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 Costanza

unread,
Apr 26, 2003, 6:53:57 PM4/26/03
to
In article <gat-260403...@192.168.1.51>,
g...@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

Thomas F. Burdick

unread,
Apr 26, 2003, 8:49:15 PM4/26/03
to
Pascal Costanza <cost...@web.de> writes:

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! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

Pascal Costanza

unread,
Apr 26, 2003, 9:45:24 PM4/26/03
to
In article <xcvel3o...@famine.OCF.Berkeley.EDU>,

t...@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.

Erann Gat

unread,
Apr 27, 2003, 12:59:56 AM4/27/03
to
In article <costanza-AC15AF...@news.netcologne.de>, Pascal
Costanza <cost...@web.de> 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.

E.

Thomas F. Burdick

unread,
Apr 27, 2003, 2:28:35 PM4/27/03
to
Pascal Costanza <cost...@web.de> writes:

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.

Pascal Costanza

unread,
Apr 27, 2003, 6:05:08 PM4/27/03
to
In article <xcvznmb...@conquest.OCF.Berkeley.EDU>,

t...@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 Costanza

unread,
Apr 27, 2003, 6:15:00 PM4/27/03
to

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.

Nikodemus Siivola

unread,
Apr 27, 2003, 8:53:22 PM4/27/03
to
Pascal Costanza <cost...@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

Gabe Garza

unread,
Apr 27, 2003, 8:51:13 PM4/27/03
to
Nikodemus Siivola <tsii...@kekkonen.cs.hut.fi> writes:

> Pascal Costanza <cost...@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

Erann Gat

unread,
Apr 27, 2003, 8:00:47 PM4/27/03
to
In article <costanza-0E8704...@news.netcologne.de>, Pascal
Costanza <cost...@web.de> wrote:

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.

Nikodemus Siivola

unread,
Apr 27, 2003, 9:20:48 PM4/27/03
to
Gabe Garza <g_g...@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

Gabe Garza

unread,
Apr 28, 2003, 3:11:39 AM4/28/03
to
Nikodemus Siivola <tsii...@kekkonen.cs.hut.fi> writes:

> Gabe Garza <g_g...@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

Pascal Costanza

unread,
Apr 28, 2003, 7:54:49 AM4/28/03
to
Nikodemus Siivola wrote:
> Gabe Garza <g_g...@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
mailto:cost...@web.de Institute of Computer Science III
http://www.pascalcostanza.de Römerstr. 164, D-53117 Bonn (Germany)

Nikodemus Siivola

unread,
Apr 28, 2003, 8:03:33 AM4/28/03
to
Gabe Garza <g_g...@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

Pascal Costanza

unread,
Apr 28, 2003, 8:14:38 AM4/28/03
to
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 Costanza

unread,
Apr 28, 2003, 8:21:10 AM4/28/03
to
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.

Tim Bradshaw

unread,
Apr 28, 2003, 7:44:38 AM4/28/03
to
* 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

Pascal Costanza

unread,
Apr 28, 2003, 8:35:57 AM4/28/03
to
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 Costanza

unread,
Apr 28, 2003, 8:42:31 AM4/28/03
to
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)))
...)

Joe Marshall

unread,
Apr 28, 2003, 10:16:21 AM4/28/03
to
Pascal Costanza <cost...@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.

Erann Gat

unread,
Apr 28, 2003, 11:46:10 AM4/28/03
to
In article <b8j6bq$14cg$1...@f1node01.rhrz.uni-bonn.de>, Pascal Costanza
<cost...@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.

Kent M Pitman

unread,
May 6, 2003, 1:49:36 AM5/6/03
to
Pascal Costanza <cost...@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.

Pascal Costanza

unread,
May 6, 2003, 2:48:41 AM5/6/03
to
Kent M Pitman wrote:
> Pascal Costanza <cost...@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.

Kent M Pitman

unread,
May 6, 2003, 3:38:09 AM5/6/03
to
Pascal Costanza <cost...@web.de> writes:

> Kent M Pitman wrote:
> > Pascal Costanza <cost...@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.

Pascal Costanza

unread,
May 6, 2003, 4:42:06 AM5/6/03
to
Kent M Pitman wrote:
> Pascal Costanza <cost...@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))

_ XL1201 _ Sebek _ Budo _ Kafka @hotmail.com Franz Kafka

unread,
May 6, 2003, 10:26:33 AM5/6/03
to

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.


Pascal Costanza

unread,
May 6, 2003, 10:47:42 AM5/6/03
to
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

Erann Gat

unread,
May 6, 2003, 1:15:46 PM5/6/03
to
In article <sfwel3c...@shell01.TheWorld.com>, Kent M Pitman
<pit...@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.

Ed L Cashin

unread,
May 6, 2003, 10:20:09 PM5/6/03
to
g...@jpl.nasa.gov (Erann Gat) writes:

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/

Jeff Caldwell

unread,
May 6, 2003, 10:41:09 PM5/6/03
to
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:
...

Erann Gat

unread,
May 6, 2003, 11:12:31 PM5/6/03
to
In article <873cjrm...@cs.uga.edu>, Ed L Cashin <eca...@uga.edu> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
>
> > In article <sfwel3c...@shell01.TheWorld.com>, Kent M Pitman
> > <pit...@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.

Ed L Cashin

unread,
May 7, 2003, 1:14:15 AM5/7/03
to
g...@jpl.nasa.gov (Erann Gat) writes:

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.

Erann Gat

unread,
May 7, 2003, 2:40:56 AM5/7/03
to
In article <87znlzl...@cs.uga.edu>, Ed L Cashin <eca...@uga.edu> wrote:

> g...@jpl.nasa.gov (Erann Gat) writes:
>
> > In article <873cjrm...@cs.uga.edu>, Ed L Cashin <eca...@uga.edu> wrote:
> >
> >> g...@jpl.nasa.gov (Erann Gat) writes:
> >>
> >> > In article <sfwel3c...@shell01.TheWorld.com>, Kent M Pitman
> >> > <pit...@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.

Pascal Costanza

unread,
May 7, 2003, 7:39:23 AM5/7/03
to
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 Costanza

unread,
May 7, 2003, 8:08:35 AM5/7/03
to
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

unread,
May 7, 2003, 8:16:17 AM5/7/03
to
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.

Ed L Cashin

unread,
May 7, 2003, 11:26:22 AM5/7/03
to
g...@jpl.nasa.gov (Erann Gat) writes:

> In article <87znlzl...@cs.uga.edu>, Ed L Cashin <eca...@uga.edu> wrote:
>
>> g...@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.

Pascal Costanza

unread,
May 7, 2003, 11:55:20 AM5/7/03
to
Ed L Cashin wrote:
> g...@jpl.nasa.gov (Erann Gat) writes:
>
>>In article <87znlzl...@cs.uga.edu>, Ed L Cashin <eca...@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!

Jeff Caldwell

unread,
May 7, 2003, 6:42:22 PM5/7/03
to
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
...

0 new messages