rit@killdeer.Stanford.EDU (Jean-Francois Rit) (08/04/90)
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?
gumby@Cygnus.COM (David Vinayak Wallace) (08/05/90)
Date: Sat, 4 Aug 90 00:19:13 GMT From: rit@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.
pierson@encore.com (Dan L. Pierson) (08/05/90)
In article <1990Aug4.001913.22597@Neon.Stanford.EDU> rit@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: pierson@encore.com
lou@atanasoff.rutgers.edu (Lou Steinberg) (08/07/90)
In article <1990Aug4.001913.22597@Neon.Stanford.EDU> rit@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: lou@cs.rutgers.edu
michaelg@Neon.Stanford.EDU (Michael Greenwald) (08/14/90)
lou@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.
jeff@aiai.ed.ac.uk (Jeff Dalton) (08/15/90)
In article <1990Aug13.201712.19721@Neon.Stanford.EDU> michaelg@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
michaelg@Neon.Stanford.EDU (Michael Greenwald) (08/15/90)
jeff@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.