From: Jean-Francois Rit
Subject: flet, a question of style?
Date: 
Message-ID: <1990Aug4.001913.22597@Neon.Stanford.EDU>
What is a good use of flet?

The way I see it, the advantages of flet over an external defun are:

- cleanliness of code: the local function is defined right where it is only
  needed and that is made clear to the reader.

- Use of lexical context: when the flet is defined in the right place, a lot
  of local variables need not be passed to the function.

The cons are:

- It is local (obviously)
- It is more expensive.

Here is the heart of my question. Is it really so, does it always have to be?
My own limited tests gave me a bit less than 10% in disfavor of flet. I also
noticed that an flet form in the do clause of a MIT loop is not compiled.


(defun with-flet (n m)
  (let ((x (make-array 1)))
    (flet ((titi-flet (p)
	     (loop for i from 0 to n
	       do (setf (aref x 0) (+ p i)))))
      (loop for j from 0 to m
	do (titi-flet j)))))

(defun without-flet (n m)
  (let ((x (make-array 1)))
    (loop for j from 0 to m
      do (titi j n x))))

(defun titi (p n x)
  (loop for i from 0 to n
    do (setf (aref x 0) (+ p i))))


Anyhow, do the programming masters use or advocate the use of flet
like they would for , say, let?
 

From: David Vinayak Wallace
Subject: flet, a question of style?
Date: 
Message-ID: <GUMBY.90Aug4131810@Cygnus.COM>
   Date: Sat, 4 Aug 90 00:19:13 GMT
   From: ···@killdeer.Stanford.EDU (Jean-Francois Rit)

   The way I see it, the advantages of flet over an external defun are:

   - cleanliness of code: the local function is defined right where it is only
     needed and that is made clear to the reader.

Unfortunately in a large system you then end up with a rats-nest of
nested functions.  The package system (poorly) addresses this issue.

   - Use of lexical context: when the flet is defined in the right place, a lot
     of local variables need not be passed to the function.

Not only that but it allows you to side-effect variables in its
lexical environment, which is really handy.

   - It is more expensive.

There's no reason why it need be.  In the case where the lexical
function is not passed down the stack it can be open-coded.  

And if you know that the function will be passed down but never up,
then it can share the environment of its enclosing function.
Unfortunately you can't do this on register-window machines like the
SPARC.  On those machines downward funarg can be somewhat expensive.
From: Dan L. Pierson
Subject: Re: flet, a question of style?
Date: 
Message-ID: <PIERSON.90Aug4182016@xenna.encore.com>
In article <·····················@Neon.Stanford.EDU> ···@killdeer.Stanford.EDU (Jean-Francois Rit) writes:

(about a FLET being more expensive than a DEFUN)

   Here is the heart of my question. Is it really so, does it always
   have to be?  My own limited tests gave me a bit less than 10% in
   disfavor of flet. I also noticed that an flet form in the do clause
   of a MIT loop is not compiled.

What Lisp system did you measure?  With what OPTIMIZE settings?  It's
not obvious that calling a FLET should be more expensive, if it's
inlined it should be less.

The failure to compile the FLET in the LOOP sounds like a compiler bug
to me.

--

                                            dan

In real life: Dan Pierson, Encore Computer Corporation, Research
UUCP: {talcott,linus,necis,decvax}!encore!pierson
Internet: ·······@encore.com
From: Lou Steinberg
Subject: Re: flet, a question of style?
Date: 
Message-ID: <Aug.7.09.30.32.1990.2457@atanasoff.rutgers.edu>
In article <·····················@Neon.Stanford.EDU> ···@killdeer.Stanford.EDU (Jean-Francois Rit) writes:

> What is a good use of flet? [...]  The cons are: [...]

One aspect that hasn't come up yet in responses (at least those I've
seen) is the fact that many Lisp programming environments do not
support local function definitions (i.e. defined via labels and flet)
nearly as well as they do global definitions.  

This shows up in at least two ways.  The first is that often you can't
break, trace, or advise a local function.  The reason is that the
break/trace function can easily access a global function from the
symbol that is it's name, and can then wrap that definition in
break/trace code.  For it to find a local definition requires it to
wade through the code of the enclosing function.  Not that it can't be
done, but it is significantly more complex and/or less portable, and
thus less often supported.

(By the way, this problem is even worse for anonymous lambdas - at
least the local functions have a name, if only locally.)

The other way this poorer-support of local definitions shows up is in
the incremental-load-compile facility that many lisps (or lisp/emacs
combinations) support.  It is useful to be able to modify one
function, then load (and maybe compile) the modified definition
without reloading/recompiling the whole program.  I don't know of any
lisp that allows you to do this with a local definition.  In fact, if
you were to go to the extreme and make all functions local except a
single top level "main" function, as is normal in Pascal and such
languages, then if you change anything you have to reload/recompile
the whole program.  (This is why even languages where local
definitions are the normal case will allow non-local definitions as
part of a separate-compilation facility.)
-- 
					Lou Steinberg

uucp:   {pretty much any major site}!rutgers!aramis.rutgers.edu!lou 
arpa:   ···@cs.rutgers.edu
From: Michael Greenwald
Subject: Re: flet, a question of style?
Date: 
Message-ID: <1990Aug13.201712.19721@Neon.Stanford.EDU>
···@atanasoff.rutgers.edu (Lou Steinberg) writes:

>The other way this poorer-support of local definitions shows up is in
>the incremental-load-compile facility that many lisps (or lisp/emacs
>combinations) support.  It is useful to be able to modify one
>function, then load (and maybe compile) the modified definition
>without reloading/recompiling the whole program.  I don't know of any
>lisp that allows you to do this with a local definition.  

Symbolics Common Lisp allows you to do this indirectly.  You can
ADVISE a local function ('(:INTERNAL FOO 0) is the function spec for
the first function defined by FLET, LABELS, or LAMBDA inside FOO.  You
can use (:INTERNAL FOO 0 localname) if the function has a local name).
If you compile the :AROUND advice, and never actually call the
original code, you've essentially replaced the original local
definition.  Of course, you don't get access to lexically apparent
variables, so ADVISE is probably not what you meant,

If you >do< want to access the local variables of the parent, then it
would be hard to see how to easily implement the local compilation
without explicitly passing in the parents environment.  

I guess my real question is: how often would you >want< to modify and
compile an internal definition without its parent?  The cost of
modifying the parent, also, can't be that large unless something is
>really< strange about your program.
From: Jeff Dalton
Subject: Re: flet, a question of style?
Date: 
Message-ID: <3201@skye.ed.ac.uk>
In article <······················@Neon.Stanford.EDU> ········@Neon.Stanford.EDU (Michael Greenwald) writes:

>I guess my real question is: how often would you >want< to modify and
>compile an internal definition without its parent?  The cost of
>modifying the parent, also, can't be that large unless something is
>>really< strange about your program.

If there was better support for it in Common Lisp implementations,
I might want to write "modules" like this (perhaps with the aid of
some macros):


    (let (...)             ; private variables

      (labels (...)        ; private functions

        (defun ...)        ; public functions
        ... ))

So the "parent" might be quite large.

-- Jeff
From: Michael Greenwald
Subject: Re: flet, a question of style?
Date: 
Message-ID: <1990Aug14.235816.11255@Neon.Stanford.EDU>
····@aiai.ed.ac.uk (Jeff Dalton) writes:

>If there was better support for it in Common Lisp implementations,
>I might want to write "modules" like this (perhaps with the aid of
>some macros):


>    (let (...)             ; private variables

>      (labels (...)        ; private functions

>        (defun ...)        ; public functions
>        ... ))

>So the "parent" might be quite large.

It's possible I'm not understanding you clearly.  Why isn't what you
describe simply a single instance of a class?  The private variables
are slots, the private functions are GENERIC-LABELS (or in pre-CLOS
flavors, DEFUN-IN-FLAVOR's) and the DEFUNs are DEFMETHODs?  It was
certainly the case that you did not have to recompile the
DEFUN-IN-FLAVORs every time you recompiled a defmethod.  I assume
(hope) that GENERIC-LABELS is similar.
From: David Vinayak Wallace
Subject: (not (equalp 'flet objects))
Date: 
Message-ID: <GUMBY.90Aug14184121@Cygnus.COM>
   Date: Tue, 14 Aug 90 23:58:16 GMT
   From: ········@Neon.Stanford.EDU (Michael Greenwald)

   ····@aiai.ed.ac.uk (Jeff Dalton) writes:

   >If there was better support for it in Common Lisp implementations,
   >I might want to write "modules" like this (perhaps with the aid of
   >some macros):


   >    (let (...)             ; private variables

   >      (labels (...)        ; private functions

   >        (defun ...)        ; public functions
   >        ... ))

   >So the "parent" might be quite large.

   It's possible I'm not understanding you clearly.  Why isn't what you
   describe simply a single instance of a class?  The private variables
   are slots, the private functions are GENERIC-LABELS (or in pre-CLOS
   flavors, DEFUN-IN-FLAVOR's) and the DEFUNs are DEFMETHODs?  It was
   certainly the case that you did not have to recompile the
   DEFUN-IN-FLAVORs every time you recompiled a defmethod.  I assume
   (hope) that GENERIC-LABELS is similar.

Because the generic functions would have to recieve the single
instance of an argument, while under Jeff's scheme (and in Scheme) the
sole discriminator is the name.  Of course in scheme, unlike cl, the
defun-ed/define-ed names would not be apparent outside the bounding
let.
From: Michael Greenwald
Subject: Re: (not (equalp 'flet objects))
Date: 
Message-ID: <1990Aug15.221853.12292@Neon.Stanford.EDU>
·····@Cygnus.COM (David Vinayak Wallace) writes:

>   Date: Tue, 14 Aug 90 23:58:16 GMT
>   From: ········@Neon.Stanford.EDU (Michael Greenwald)

>   ····@aiai.ed.ac.uk (Jeff Dalton) writes:

>   >If there was better support for it in Common Lisp implementations,
>   >I might want to write "modules" like this (perhaps with the aid of
>   >some macros):


>   >    (let (...)             ; private variables

>   >      (labels (...)        ; private functions

>   >        (defun ...)        ; public functions
>   >        ... ))

>   >So the "parent" might be quite large.

>   It's possible I'm not understanding you clearly.  Why isn't what you
>   describe simply a single instance of a class?  The private variables
>   are slots, the private functions are GENERIC-LABELS (or in pre-CLOS
>   flavors, DEFUN-IN-FLAVOR's) and the DEFUNs are DEFMETHODs?  It was
>   certainly the case that you did not have to recompile the
>   DEFUN-IN-FLAVORs every time you recompiled a defmethod.  I assume
>   (hope) that GENERIC-LABELS is similar.

>Because the generic functions would have to recieve the single
>instance of an argument, while under Jeff's scheme (and in Scheme) the
>sole discriminator is the name.  Of course in scheme, unlike cl, the
>defun-ed/define-ed names would not be apparent outside the bounding
>let.


I thought of that, but I decided "Nah, he couldn't have meant that"
since he said "(perhaps with the aid of some macros)".  Since there's
a single instance of this class, it wouldn't be hard to write the
macrology he wants like 

(defmacro <his name 1> (&rest arglist)
  `(<generic function name 1> *single-instance* . ,arglist))

so he must want to do something more complicated that I don't understand.

With this macrology <his name 1> is the sole discriminator.  In Scheme
you're doing the same thing - the name is bound to a closure: the
function and the environment (in our case, the instance).  In Scheme
the language does it under the covers, in CL you have to do it explicitly.

Here's the outline of what I mean in SCLese (i.e. flavors, and not
CLOS.  I assume that the translation is straightforward).  
(DEFFLAVOR is DEFCLASS, DEFUN-IN-FLAVOR I think is like
GENERIC-LABELS, DEFMETHOD is the same in CLOS and New Flavors, and
STRING-APPEND is sort of this:

(DEFUN STRING-APPEND (STRING1 &REST STRINGS)
  (IF STRINGS
      (CONCATENATE 'STRING (STRING STRING1) (APPLY #'STRING-APPEND STRINGS))
      (STRING STRING1)))
)

;; inside the *module-package*
(defun cons-name (type name)
  (intern (concatenate (string type) *module-separator* name)
	  *module-package*))

(defmacro defmodule (name bindings)
  `(progn
     (flavor:defflavor ,name ,bindings ())
     (defvar ,(cons-name "INSTANCE" name) (make-instance ',name))))

(defmacro define-private-function ((f module) arglist &body body)
  `(flavor:defun-in-flavor (,f ,module) ,arglist
     ,@body))

(defmacro define-public-function ((f module) arglist &body body)
  `(progn
     (defmethod (,(cons-name module f) ,module) ,arglist
       ,@body)
     ,(list 'defmacro f '(&rest arglist)
        `(apply #',(cons-name module f) ,(cons-name "INSTANCE" module)
	        arglist))))

You can do the same thing passing around an explicit environment
instead of the instance, but accessing slots is probably faster than
any home grown environment you'd construct.  It's ugly, but I think
it's what he wants.  

But my real question (which was elided in your response) was: Why is
this such a problem anyway?  In PASCAL (the original example?) you'd
have to recompile the parent in order to determine the environment for
the public (or private) function.  Why is this such a terrible penalty
in CL?  (Are there Scheme implementations where the compiler wouldn't
recompile the whole lexical environment?).

In short, classes provide a way to do modules without recompiling.
But is the requirement of recompilation of the whole module the only
"lack of support" in CL?  If so, why is this more of a problem in CL
than in other languages?  If this isn't the only problem you were
alluding to, then I missed (or misunderstood) your (Jeff's) original
complaint.
From: Jeff Dalton
Subject: Re: (not (equalp 'flet objects))
Date: 
Message-ID: <3215@skye.ed.ac.uk>
I suggested writing a "module" like this:

    (let (...)             ; private variables
      (labels (...)        ; private functions

        (defun ...)        ; public functions
        ... ))

The entire form can be quite large, and so it would be a pain if,
to recompile any of it, I had to recompile all of it.

In article <······················@Neon.Stanford.EDU> ········@Neon.Stanford.EDU (Michael Greenwald) writes:
>·····@Cygnus.COM (David Vinayak Wallace) writes:

[This is about my module example above.]

>>   It's possible I'm not understanding you clearly.  Why isn't what you
>>   describe simply a single instance of a class?  The private variables
>>   are slots, the private functions are GENERIC-LABELS (or in pre-CLOS
>>   flavors, DEFUN-IN-FLAVOR's) and the DEFUNs are DEFMETHODs?

>>Because the generic functions would have to recieve the single
>>instance of an argument, while under Jeff's scheme (and in Scheme) the
>>sole discriminator is the name.  Of course in scheme, unlike cl, the
>>defun-ed/define-ed names would not be apparent outside the bounding
>>let.

>I thought of that, but I decided "Nah, he couldn't have meant that"
>since he said "(perhaps with the aid of some macros)".  Since there's
>a single instance of this class, it wouldn't be hard to write the
>macrology he wants like 
>
>(defmacro <his name 1> (&rest arglist)
>  `(<generic function name 1> *single-instance* . ,arglist))
>
>so he must want to do something more complicated that I don't understand.

No, I want something *simpler*.

Perhaps I should have been clearer about the role of macros.
I meant the expansion would have the form I suggested above,
not that the macros would produce something that had roughly
similar (or better!) semantics.

Of course, there might be better solutions that make use of
CLOS in one way or another.  However there isn't an equivalent
to DEFUN-IN-FLAVOR (though I suppose something sufficiently
like it might be constructed).  GENERIC-LABLES might well
have the same problems as LABELS.

Nonetheless, I think you're right that something using classes
and methods, with suitable syntactic sugar, might be the way to go.

>With this macrology <his name 1> is the sole discriminator.  In Scheme
>you're doing the same thing - the name is bound to a closure: the
>function and the environment (in our case, the instance).  In Scheme
>the language does it under the covers, in CL you have to do it explicitly.

But CL has closures too.  I can do more or less the same thing in CL
that I can in Scheme, can't I?  (Unless you have in mind the first-class
environments some Schemes have.)

>You can do the same thing passing around an explicit environment
>instead of the instance, but accessing slots is probably faster than
>any home grown environment you'd construct.  It's ugly, but I think
>it's what he wants.  

My suggestion was to use the normal lexical environments provided
by the CL implementation.  Access to a variable from within a closure
should be faster than slot access.

>In short, classes provide a way to do modules without recompiling.
>But is the requirement of recompilation of the whole module the only
>"lack of support" in CL?  If so, why is this more of a problem in CL
>than in other languages?  If this isn't the only problem you were
>alluding to, then I missed (or misunderstood) your (Jeff's) original
>complaint.

Just because something is a problem in other languages too doesn't
mean it isn't one in CL too.  My only role in this discussion,
however, was to suggest, in response to an observation that the
parent wouldn't be very large, that it might be larger than one
might guess.