From: Vladimir Zolotykh
Subject: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <3E4249A7.9080307@eurocom.od.ua>
I wonder whether there is a way to make sure the list is a correct
LAMBDA expression

For example, giving something like  the following

   (lambda (s)
     (when s
       (misc:parse-postgres-array s :strings t)))

this hypothetical function might say 'this is correct
lambda-expression, you could safely funcall it'. I need this
function in the code like the following

   (etypecase x
     (null value)
     (string (format nil x value))
     ((or symbol cons) (funcall x value)))

Now I'm using just CONS, but this seems not safe enough.

-- 
Vladimir Zolotykh

From: Larry Clapp
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <ckjt1b.7l3.ln@theclapp.ddts.net>
In article <················@eurocom.od.ua>, Vladimir Zolotykh wrote:
> I wonder whether there is a way to make sure the list is a correct
> LAMBDA expression
> 
> For example, giving something like  the following
> 
>    (lambda (s)
>      (when s
>        (misc:parse-postgres-array s :strings t)))
> 
> this hypothetical function might say 'this is correct
> lambda-expression, you could safely funcall it'. I need this
> function in the code like the following
> 
>    (etypecase x
>      (null value)
>      (string (format nil x value))
>      ((or symbol cons) (funcall x value)))
> 
> Now I'm using just CONS, but this seems not safe enough.

functionp?

From the hyperspec:

 (functionp 'append) =>  false
 (functionp #'append) =>  true
 (functionp (symbol-function 'append)) =>  true
 (flet ((f () 1)) (functionp #'f)) =>  true
 (functionp (compile nil '(lambda () 259))) =>  true
 (functionp nil) =>  false
 (functionp 12) =>  false
 (functionp '(lambda (x) (* x x))) =>  false
 (functionp #'(lambda (x) (* x x))) =>  true

-- 
Larry Clapp / ·····@theclapp.org
Use Lisp from Vim: VILisp: http://vim.sourceforge.net/script.php?script_id=221


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----==  Over 80,000 Newsgroups - 16 Different Servers! =-----
From: Vladimir Zolotykh
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <3E426ECB.7050605@eurocom.od.ua>
Larry Clapp wrote:

> functionp?

I would use FUNCTIONP if I had a function object.
But I have just a list (LAMBDA ....). So FUNCTIONP is
useless here I suppose.


-- 
Vladimir Zolotykh
From: Larry Clapp
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <ivvt1b.t5a.ln@theclapp.ddts.net>
In article <················@eurocom.od.ua>, Vladimir Zolotykh wrote:
> Larry Clapp wrote:
>> functionp?
> 
> I would use FUNCTIONP if I had a function object.  But I have just a
> list (LAMBDA ....). So FUNCTIONP is useless here I suppose.

coerce, then?

    (let ((l '(lambda (x) (+ x 10))))
      (values 
	(functionp l)
	(functionp (coerce l 'function))
	(compiled-function-p l)
	(compiled-function-p (coerce l 'function))))
    => NIL
    => T
    => NIL
    => T

I suspect some implementations would vary on that last T, though.

-- 
Larry Clapp / ·····@theclapp.org
Use Lisp from Vim: VILisp: http://vim.sourceforge.net/script.php?script_id=221


-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----==  Over 80,000 Newsgroups - 16 Different Servers! =-----
From: Pascal Costanza
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <b1tsjo$rfe$1@f1node01.rhrz.uni-bonn.de>
Vladimir Zolotykh wrote:
> Larry Clapp wrote:
> 
>> functionp?
> 
> 
> I would use FUNCTIONP if I had a function object.
> But I have just a list (LAMBDA ....). So FUNCTIONP is
> useless here I suppose.

Your original post suggests that you have a function object, not a list.

(lambda (x) (1+ x)) creates a function object that can be funcalled.

'(lambda (x) (1+ x)) is just a list.

Here is a Common Lisp session:

 > (functionp (lambda (x) (1+ x)))
T

 > (functionp '(lambda (x) (1+ x)))
NIL

 > (funcall (lambda (x) (1+ x)) 5)
6

 > (funcall '(lambda (x) (1+ x)) 5)

Error: Argument to apply/funcall is not a function: (LAMBDA (X) (1+ X)).


I hope this helps.


Pascal

-- 
Pascal Costanza               University of Bonn
···············@web.de        Institute of Computer Science III
http://www.pascalcostanza.de  Ro"merstr. 164, D-53117 Bonn (Germany)
From: Vladimir Zolotykh
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <3E428249.6040609@eurocom.od.ua>
Pascal Costanza wrote:

>  > (functionp (lambda (x) (1+ x)))
> T


(lamda (x) (1+ x)) becomes a functional object when gets evaluated.
Right ? But in my code it isn't evaluated until it is passed to FUNCALL,
at least I think so. I may well do EVAL, but it seems not a good style.





-- 
Vladimir Zolotykh
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <bMv0a.9$ik5.343@paloalto-snr1.gtei.net>
In article <················@eurocom.od.ua>,
Vladimir Zolotykh  <······@eurocom.od.ua> wrote:
>Pascal Costanza wrote:
>
>>  > (functionp (lambda (x) (1+ x)))
>> T
>
>
>(lamda (x) (1+ x)) becomes a functional object when gets evaluated.
>Right ? But in my code it isn't evaluated until it is passed to FUNCALL,
>at least I think so. I may well do EVAL, but it seems not a good style.

Better style would be to use COERCE, although they're functionally
equivalent in this case (COERCE's behavior is defined in terms of what EVAL
does).

Going back to your original question, there's no standard way to check that
a lambda expression has correct syntax, other than coercing it to a
function and trying to call it.  You can put an error handler around this
to catch the error, although that could be error-prone -- the lambda
expression might be valid, but it could call something that signals the
error you're handling.

You could check that the list starts with LAMBDA and the second element is
a list.  However, hard-coding this check into your program means that if
the implementation provides extensions to lambda expression syntax (which
quite a few probably do) your program won't pass them through.

-- 
Barry Margolin, ······@genuity.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kaz Kylheku
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <cf333042.0302060825.34e987c5@posting.google.com>
Vladimir Zolotykh <······@eurocom.od.ua> wrote in message news:<················@eurocom.od.ua>...
> I wonder whether there is a way to make sure the list is a correct
> LAMBDA expression

How about these steps:

  1. Is there a LAMBDA symbol in the first position of the list?
  2. Does EVAL or COMPILE on the form signal any conditions?

Assuming that by ``correct'' you mean something like ``well-formed'',
rather than, ``when I call it, it implements the design specification
and never blows up''. :)

> For example, giving something like  the following
> 
>    (lambda (s)
>      (when s
>        (misc:parse-postgres-array s :strings t)))
> 
> this hypothetical function might say 'this is correct
> lambda-expression, you could safely funcall it'.

This is false; you cannot funcall a lambda expression; it's just a
list.

> I need this
> function in the code like the following
> 
>    (etypecase x
>      (null value)
>      (string (format nil x value))
>      ((or symbol cons) (funcall x value)))

Again: you can't FUNCALL a CONS! This won't work even if x is a lambda
expression, because a lambda expression is just a list. Before you can
funcall, you must EVAL the lambda expression, which invokes the LAMBDA
macro that will pass the expression to the FUNCTION operator to
produce a closure. Alternately, you can use the COMPILE function to
produce the closure out of the lambda expression. The result of either
of these two is an object that you can then funcall.

> Now I'm using just CONS, but this seems not safe enough.

You're darn right! ;)
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <Juw0a.11$ik5.302@paloalto-snr1.gtei.net>
In article <····························@posting.google.com>,
Kaz Kylheku <···@ashi.footprints.net> wrote:
>Again: you can't FUNCALL a CONS!

As a reminder: in CLTL1 you could.  This was changed in ANSI CL.  But many
implementations permit it for backward compatibility.

-- 
Barry Margolin, ······@genuity.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Hannah Schroeter
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <b1ua6u$eo7$5@c3po.schlund.de>
Hello!

Barry Margolin  <······@genuity.net> wrote:
>In article <····························@posting.google.com>,
>Kaz Kylheku <···@ashi.footprints.net> wrote:
>>Again: you can't FUNCALL a CONS!

>As a reminder: in CLTL1 you could.  This was changed in ANSI CL.  But many
>implementations permit it for backward compatibility.

Oh yeah. You CAN funcall a symbol, but you can't even
(funcall '(setf foo) bar baz), even if you have defined
a function (setf foo).

Kind regards,

Hannah.
From: Nils Goesche
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <lylm0t88bk.fsf@cartan.de>
······@schlund.de (Hannah Schroeter) writes:

> Barry Margolin  <······@genuity.net> wrote:
> >In article <····························@posting.google.com>,
> >Kaz Kylheku <···@ashi.footprints.net> wrote:
> >>Again: you can't FUNCALL a CONS!
> 
> >As a reminder: in CLTL1 you could.  This was changed in ANSI CL.
> >But many implementations permit it for backward compatibility.
> 
> Oh yeah. You CAN funcall a symbol, but you can't even
> (funcall '(setf foo) bar baz), even if you have defined a function
> (setf foo).

So do (funcall #'(setf foo) bar baz).

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <QLz0a.18$ik5.484@paloalto-snr1.gtei.net>
In article <··············@cartan.de>, Nils Goesche  <······@cartan.de> wrote:
>······@schlund.de (Hannah Schroeter) writes:
>
>> Barry Margolin  <······@genuity.net> wrote:
>> >In article <····························@posting.google.com>,
>> >Kaz Kylheku <···@ashi.footprints.net> wrote:
>> >>Again: you can't FUNCALL a CONS!
>> 
>> >As a reminder: in CLTL1 you could.  This was changed in ANSI CL.
>> >But many implementations permit it for backward compatibility.
>> 
>> Oh yeah. You CAN funcall a symbol, but you can't even
>> (funcall '(setf foo) bar baz), even if you have defined a function
>> (setf foo).
>
>So do (funcall #'(setf foo) bar baz).

We probably should have allowed it, though, for the same reason that we
allowed funcalling a symbol: if you redefine the function, you want to get
the new version.  It doesn't make a difference if you call it literally
like the above expression, but it does if you save the function someplace,
e.g.

(setq *function-to-call* #'(setf foo))
(defun (setf foo) ...)
(funcall *function-to-call* ...)

*function-to-call* retains the previous function definition, so this will
call the wrong version.

-- 
Barry Margolin, ······@genuity.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Steven M. Haflich
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <3E4331A7.4020005@alum.mit.edu>
Barry Margolin wrote:

>>>Oh yeah. You CAN funcall a symbol, but you can't even
>>>(funcall '(setf foo) bar baz), even if you have defined a function
>>>(setf foo).

> We probably should have allowed it, though, for the same reason that we
> allowed funcalling a symbol ...

I disagree.

Dereferencing the global function binding of a function name that is
a symbol is a fast, inexpensive operation.  The main reason is that
the symbol is a unique first-class object, so the binding can be
stored in a slot.

Dereferencing the global function bound to a function name that is a
list is not necessarily a fast operation, primarily because there are
an infinite number of potential objects that must dereference to that
particular binding, and further, the binding resolution of any of those
objects can change arbitrarily without the binding changing (:-) if the
list is mutated:

   (let ((name (list 'setf 'foo)))
     (eq (fdefinition name)
         (progn (setf (cadr name) 'bar)
                (fdefinition name))))

That is, the bindings of (setf foo) and (setf bar) do not change, but
the function designated by the object (a cons) in the above example
changes because the cadr of that cons changes.

We don't want to encourage programming idioms that have awkward
or hard-to-understand performance characteristics.
From: Joe Marshall
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <4r7gxhm9.fsf@ccs.neu.edu>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> We don't want to encourage programming idioms that have awkward
> or hard-to-understand performance characteristics.

Like APPEND
From: Tim Bradshaw
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <ey3d6m4cd9f.fsf@cley.com>
* Joe Marshall wrote:
> "Steven M. Haflich" <·················@alum.mit.edu> writes:
>> We don't want to encourage programming idioms that have awkward
>> or hard-to-understand performance characteristics.

> Like APPEND

Awkward and hard-to-understand if you don't understand linked lists or
something, I guess.

--tim
From: Joe Marshall
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <n0l8w07k.fsf@ccs.neu.edu>
Tim Bradshaw <···@cley.com> writes:

> * Joe Marshall wrote:
> > "Steven M. Haflich" <·················@alum.mit.edu> writes:
> >> We don't want to encourage programming idioms that have awkward
> >> or hard-to-understand performance characteristics.
> 
> > Like APPEND
> 
> Awkward and hard-to-understand if you don't understand linked lists or
> something, I guess.

I was thinking the hard-to-understand performance characteristics.
I don't know how many times I've seen novice programmers accumulate
lists from the right-hand side by using APPEND and thus turning a
linear process into a quadratic one.
From: Tim Bradshaw
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <ey34r7gcbvm.fsf@cley.com>
* Joe Marshall wrote:

> I was thinking the hard-to-understand performance characteristics.

yes, that's what I meant.

> I don't know how many times I've seen novice programmers accumulate
> lists from the right-hand side by using APPEND and thus turning a
> linear process into a quadratic one.

Yes, me too.  But I don't think this is a problem with APPEND: people
need to understand how linked lists work and in particular that they
are not arrays.  Once they do that then they stop making this mistake.

--tim
From: Kent M Pitman
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <sfwvfzwf265.fsf@shell01.TheWorld.com>
Joe Marshall <···@ccs.neu.edu> writes:

> "Steven M. Haflich" <·················@alum.mit.edu> writes:
> 
> > We don't want to encourage programming idioms that have awkward
> > or hard-to-understand performance characteristics.
> 
> Like APPEND

Well, indeed, this is the canonical example.

In the very early days of X3J13, we wrote a charter which said:

  1.  X3J13 is chartered to produce an American National Standard
  for Common Lisp.  It will codify existing practice, provide
  extensions [amendment: change the word "extensions" to
  "additional features".]  to facilitate portability of code among
  diverse implementations, and establish normative Common Lisp
  programming practice.


Full text: http://world.std.com/~pitman/CL/x3j13-86-020.html

Someone (my memory says it was John McCarthy, who attended some of
those early meetings, but I might be misremembering) questioned what
"establish normative CL programming practice" meant, and people
suggested just what is being talked about now--that the language
shouldn't offer operators which appear to be good to use, but that
then stab you in the back.  We should offer things we expect people to
use.  The discussion immediately turned to a lively debate of the
presence of APPEND.  I have no specific recollection of how APPEND
survived the very legitimate criticisms, but my guess is that the 
overriding argument was the same one that rescued EQUAL and SUBST
and FIXNUM, which is that they were traditional and people would
expect them.

I'm told that the Bread & Circus grocery store in Cambridge, MA once
took chocolate off the shelves because it contained caffeine.  The
story goes that a few weeks later it was back with big signs posted
both apologizing and promising never to do that again.  

Some kinds of morality decisions are best left to the end user...
From: Larry Hunter
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <m33cmvoipx.fsf@huge.uchsc.edu>
>> We don't want to encourage programming idioms that have awkward
>> or hard-to-understand performance characteristics.

>Like APPEND

Or, as two independent and reasonably experienced lisp programmers in
my lab discovered this week, CONCATENATE and SUBSEQ

(which bit because they must return new, not shared, structure). 

Larry

-- 

Lawrence Hunter, Ph.D.
Director, Center for Computational Pharmacology
Associate Professor of Pharmacology, PMB & Computer Science

phone  +1 303 315 1094           UCHSC, Campus Box C236    
fax    +1 303 315 1098           School of Medicine rm 2817b   
cell   +1 303 324 0355           4200 E. 9th Ave.                 
email: ············@uchsc.edu    Denver, CO 80262       
PGP key on public keyservers     http://compbio.uchsc.edu/hunter   
From: ··········@worldonline.dk
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <80n0l83xx9.fsf@localhost.localdomain>
"Steven M. Haflich" <·················@alum.mit.edu> writes:

> Barry Margolin wrote:
> 
> >>>Oh yeah. You CAN funcall a symbol, but you can't even
> >>>(funcall '(setf foo) bar baz), even if you have defined a function
> >>>(setf foo).
> 
> > We probably should have allowed it, though, for the same reason that we
> > allowed funcalling a symbol ...
> 
> I disagree.
> 
> Dereferencing the global function binding of a function name that is
> a symbol is a fast, inexpensive operation.  The main reason is that
> the symbol is a unique first-class object, so the binding can be
> stored in a slot.
> 
> Dereferencing the global function bound to a function name that is a
> list is not necessarily a fast operation, primarily because there are
> an infinite number of potential objects that must dereference to that
> particular binding, and further, the binding resolution of any of those
> objects can change arbitrarily without the binding changing (:-) if the
> list is mutated:
> 
>    (let ((name (list 'setf 'foo)))
>      (eq (fdefinition name)
>          (progn (setf (cadr name) 'bar)
>                 (fdefinition name))))
> 
> That is, the bindings of (setf foo) and (setf bar) do not change, but
> the function designated by the object (a cons) in the above example
> changes because the cadr of that cons changes.
>

So?

    (let ((name 'foo))
      (eq (fdefinition name)
          (progn (setf name 'bar)
                 (fdefinition name))))
 
 That is, the bindings of 'foo and 'bar do not change, but
 the function designated by the object (a symbol) in the above example
 changes because the object changes.

A function name is not just any old list.  Its a list of 2 elements
with a car of 'setf and the cadr a symbol.  You can have a ``setf
function name'' slot for symbols, in which case the function name
'(setf foo) is as unique as 'foo.  You access it when 'foo appears as
the cadr of a 2 element list with a car of 'setf in a situation where
it is appropriate to regard it as a function name. (eg as an arg to
fdefinition, or as the car of a list).

Regards,
Peter
From: Steven M. Haflich
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <3E4449C1.20206@franz.com>
··········@worldonline.dk wrote:

> So?
> 
>     (let ((name 'foo))
>       (eq (fdefinition name)
>           (progn (setf name 'bar)
>                  (fdefinition name))))
>  
>  That is, the bindings of 'foo and 'bar do not change, but
>  the function designated by the object (a symbol) in the above example
>  changes because the object changes.
> 
> A function name is not just any old list.  Its a list of 2 elements
> with a car of 'setf and the cadr a symbol.  You can have a ``setf
> function name'' slot for symbols, in which case the function name
> '(setf foo) is as unique as 'foo.  You access it when 'foo appears as
> the cadr of a 2 element list with a car of 'setf in a situation where
> it is appropriate to regard it as a function name. (eg as an arg to
> fdefinition, or as the car of a list).

I think you miss the point.

Most Lisp namespaces are many-to-one maps of names onto values.
("Many-to-one" means that each name is bound onto a single value, but
multiple names may be bound to the same value.)  In your example above
"name" does not name a function binding.  "foo" and "bar" do, but "name"
is simply the name of a variable binding.

In any case, my point was that there is a significant difference between
atomic symbol names for function bindings and setf function names, which
are lists:  Each possible atomic symbol binding name that is a symbol is
eql distinct from every other such name.  Symbols are either eql or not
eql, and each one has a global function binding, and there is only one
object that names any particular binding.  But for setf function names,
there are an infinite number of non-eql conses which name the same binding,
and further, the binding such a cons names can change over time.

The performance characteristics of these two sets of functi9on binding names
is very different.  I would not want to have to make funcall work for
setf names, at least if the name is not a manifest constant.
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <aOY0a.27$2Q1.1500@paloalto-snr1.gtei.net>
In article <··············@franz.com>,
Steven M. Haflich <·················@franz.com> wrote:
>In any case, my point was that there is a significant difference between
>atomic symbol names for function bindings and setf function names, which
>are lists:  Each possible atomic symbol binding name that is a symbol is
>eql distinct from every other such name.  Symbols are either eql or not
>eql, and each one has a global function binding, and there is only one
>object that names any particular binding.  But for setf function names,
>there are an infinite number of non-eql conses which name the same binding,
>and further, the binding such a cons names can change over time.
>
>The performance characteristics of these two sets of functi9on binding names
>is very different.  I would not want to have to make funcall work for
>setf names, at least if the name is not a manifest constant.

The (SETF <symbol>) list isn't the identifier, the symbol in its cadr is.
Just have a global "setf function" cell analogous to the global function
cell.  The only performance impact is the constant extra overhead of
accessing the cadr.

P.S. to Steven -- Please see the last line of my signature regarding
discourtesy copies.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: ··········@worldonline.dk
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <804r7fp6i2.fsf@localhost.localdomain>
"Steven M. Haflich" <·················@franz.com> writes:

> ··········@worldonline.dk wrote:
> 
> > So?
> >     (let ((name 'foo))
> 
> >       (eq (fdefinition name)
> >           (progn (setf name 'bar)
> >                  (fdefinition name))))
> >   That is, the bindings of 'foo and 'bar do not change, but
> 
> >  the function designated by the object (a symbol) in the above example
> >  changes because the object changes.
> > A function name is not just any old list.  Its a list of 2 elements
> 
> > with a car of 'setf and the cadr a symbol.  You can have a ``setf
> > function name'' slot for symbols, in which case the function name
> > '(setf foo) is as unique as 'foo.  You access it when 'foo appears as
> > the cadr of a 2 element list with a car of 'setf in a situation where
> > it is appropriate to regard it as a function name. (eg as an arg to
> > fdefinition, or as the car of a list).
> 
> I think you miss the point.

I don't think so.  I understand what you are saying, but it is
irrelevant to the issue.

> 
> Most Lisp namespaces are many-to-one maps of names onto values.
> ("Many-to-one" means that each name is bound onto a single value, but
> multiple names may be bound to the same value.)  In your example above
> "name" does not name a function binding.  "foo" and "bar" do, but "name"
> is simply the name of a variable binding.
> 
> In any case, my point was that there is a significant difference between
> atomic symbol names for function bindings and setf function names, which
> are lists:  Each possible atomic symbol binding name that is a symbol is
> eql distinct from every other such name.  Symbols are either eql or not
> eql, and each one has a global function binding, and there is only one
> object that names any particular binding.  

You miss my point.  I _know_ this, and use it in my argument to show
that setf function names, since they are _not_ just any old list, but
a specific, predictable type of list, can use this feature of symbols.

> But for setf function names,
> there are an infinite number of non-eql conses which name the same binding,
> and further, the binding such a cons names can change over time.
> 

I am suggesting that the cons _not_ have any binding at all. (I
consider the very idea of binding a cons ridiculous).  The symbol _in_
the cons, which in function names always occurs in the same
predictable place, namely the cadr of the cons, 'has the binding',
precisely as a traditional symbol function name does.  This binding is
implemented with a new slot for 'setf function names' so will not
interfere with the symbol's regular/traditional binding.

> The performance characteristics of these two sets of functi9on binding names
> is very different.  I would not want to have to make funcall work for
> setf names, at least if the name is not a manifest constant.

There is (1) a _very_ small performance cost of implementing this, and
(2) it is trivially easy to implement.

Regards,
Peter
From: Duane Rettig
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <4lm0qcnzr.fsf@beta.franz.com>
··········@worldonline.dk writes:

> "Steven M. Haflich" <·················@franz.com> writes:


> > But for setf function names,
> > there are an infinite number of non-eql conses which name the same binding,
> > and further, the binding such a cons names can change over time.
> > 
> 
> I am suggesting that the cons _not_ have any binding at all. (I
> consider the very idea of binding a cons ridiculous).  The symbol _in_
> the cons, which in function names always occurs in the same
> predictable place, namely the cadr of the cons, 'has the binding',
> precisely as a traditional symbol function name does.  This binding is
> implemented with a new slot for 'setf function names' so will not
> interfere with the symbol's regular/traditional binding.

OK, Barry has suggested the same idea.

> > The performance characteristics of these two sets of function binding names
> > is very different.  I would not want to have to make funcall work for
> > setf names, at least if the name is not a manifest constant.
> 
> There is (1) a _very_ small performance cost of implementing this, and
> (2) it is trivially easy to implement.

This is very interesting.  And in your trivial implementation, what
performance characteristics did you actually measure against otherwise
similar other lisps?

Sorry, that question is slightly rhetorical, because I actually doubt
that you actually have done such an implementation, or if you have,
that you have performed such tests (or, if you have, that you'd be
willing to release those results :-)

I have no doubts that point #2 is true.  However, let me give you three
reasons why point #1 is definitely _not_ true:

1. The cadr:  Most Common Lisp function calls start with a symbol,
grab the function object (the first memory reference) and then sometimes
access the start-address through the function object (second chained
memory reference).  Although this extra chained reference (i.e. the
results of the first reference must be available before the second
access can actually be scheduled), this is usually an acceptable set
of instruction sequence, because there are other non-chained movements
going on during the sequence (such as the setting of the count register).
This is also approximately the time position-independent C code takes,
so it has proved to be an acceptable calling overhead.

However, the taking of the CADR of (setf foo) requires two _extra_
chained references, before you even get to the symbol.   This creates
two large holes in the pipeline which other activity can't fill.

2. The symbol size: Every symbol would have to have yet another slot
in it, which could possibly (due to alignment) cause _two_ extra
words per symbol.  This is "only" a size issue, I know, but some
users are sensitive to size, and have you counted lately how many
symbols are in whatever CL you use?

3. Amortized cost:  Funcall (and any other function-calling functionality
which can't see manifestly whether the function name is a symbol
or a cons) must now perform an extra test every time it operates.
furthermore, in safe code that test would have to include a check
that the car of the function name is 'setf.  You're now slowing down
funcall, as well as each of the setf-function calls.


Whenever we're talking about the CL function call, it's important
not to trivialize what in other code would be small performance
impacts.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Wood
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <80vfztvkqn.fsf@localhost.localdomain>
Duane Rettig <·····@franz.com> writes:

> ··········@worldonline.dk writes:
> 
> > "Steven M. Haflich" <·················@franz.com> writes:
> 
> 
> > > But for setf function names, there are an infinite number of
> > > non-eql conses which name the same binding, and further, the
> > > binding such a cons names can change over time.
> > > 
> > 
> > I am suggesting that the cons _not_ have any binding at all. (I
> > consider the very idea of binding a cons ridiculous).  The symbol
> > _in_ the cons, which in function names always occurs in the same
> > predictable place, namely the cadr of the cons, 'has the binding',
> > precisely as a traditional symbol function name does.  This
> > binding is implemented with a new slot for 'setf function names'
> > so will not interfere with the symbol's regular/traditional
> > binding.
> 
> OK, Barry has suggested the same idea.
> 
> > > The performance characteristics of these two sets of function
> > > binding names is very different.  I would not want to have to
> > > make funcall work for setf names, at least if the name is not a
> > > manifest constant.
> > 
> > There is (1) a _very_ small performance cost of implementing this,
> > and (2) it is trivially easy to implement.
> 
> This is very interesting. What performance characteristics did you
> actually measure against otherwise similar other lisps?

Maybe I should have said (1) a very small cost _in my lisp_.  However,
for the sake of argument ...

> 
> Sorry, that question is slightly rhetorical, because I actually doubt
> that you actually have done such an implementation, or if you have,
> that you have performed such tests (or, if you have, that you'd be
> willing to release those results :-)
>

On what do your base your doubts, Duane Rettig?  

I most certainly _have_ implemented this!  Although, for funcall, it
was 'by mistake' :-), and I removed it (for funcall) when I realised
that it was not ANS compliant. I am working on upgrading GCL to
conform to the ANSI CL specification.  When I was doing 'setf function
names I assumed that funcall would also take a function name, and
adapted it to do so.  It was such a trivial and obvious change that I
didn't bother to check until later, at which point I removed it.
However, in my implementation, setf function names work as described
for those functions which do take a function name.  This version of
GCL has not been released and maybe never will be - certainly not
tomorrow :-)

I don't have formal tests of my statement that it has a small
performance cost.  On my system, it falls _under_ the clock
resolution, which admittedly is not very fine.  I can no longer test
funcall this way since I removed this feature as non-compliant, but
#'fdefinition does the same check.  #'symbol-function (obviously) does
not do the check so maybe the following test can tell us something:

[Please note that I am _completely_ uninterested in a macho pissing
match about whose implementation can run the test fastest - I am only
interested in wether the check is having a  significant performance
effect.] 

;;simple test to compare access times for #'fdefinition and
;;#'symbol-function

(defvar *test-fn* (lambda  (a b) (setf (car b) a)))

(setf (fdefinition 'foo) *test-fn*)
(setf (fdefinition '(setf foo)) *test-fn*)

(defvar *b* '(alpha beta))

(defun test-access (n fnname) 
  (do ((start 0 (1+ start))) 
      ((> start n))
    (funcall (if (consp fnname) 
                 (fdefinition fnname) ;Duane say this takes longer ...  
                 (symbol-function fnname)) ;than this 
             (gensym) *b*)))

;;results - most of the actual time is being taken by #'gensym !

> *b*

(ALPHA BETA)

> (si::gbc t)

T

> (time (test-access 1000 'foo))

real time : 0.050 secs
run time  : 0.050 secs
NIL

> (si::gbc t)

T

> *b*                             

(#:G3083 BETA)

> (time (test-access 1000 '(setf foo)))

real time : 0.050 secs
run time  : 0.050 secs
NIL

> *b*

(#:G4084 BETA)

> 
> I have no doubts that point #2 is true.  However, let me give you
> three reasons why point #1 is definitely _not_ true:
> 
> 1. The cadr: Most Common Lisp function calls start with a symbol,
> grab the function object (the first memory reference) and then
> sometimes access the start-address through the function object
> (second chained memory reference).  Although this extra chained
> reference (i.e. the results of the first reference must be available
> before the second access can actually be scheduled), this is usually
> an acceptable set of instruction sequence, because there are other
> non-chained movements going on during the sequence (such as the
> setting of the count register).  This is also approximately the time
> position-independent C code takes, so it has proved to be an
> acceptable calling overhead.
> 
> However, the taking of the CADR of (setf foo) requires two _extra_
> chained references, before you even get to the symbol.   This creates
> two large holes in the pipeline which other activity can't fill.

This conversation started with a complaint that it is not possible to
funcall a setf function name.  If the user is doing funcall, they are
already adding in extra overhead.  That suggests that something as
small as 'two extra chained references' is not going to be the straw
that breaks the camels back.

> 
> 2. The symbol size: Every symbol would have to have yet another slot
> in it, which could possibly (due to alignment) cause _two_ extra
> words per symbol.  This is "only" a size issue, I know, but some
> users are sensitive to size, and have you counted lately how many
> symbols are in whatever CL you use?

Yes, and I did worry about this.  I decided the tradeoff is acceptable
in implementing setf function names this way, in comparison with the
added complexity and general godammned kludginess of 'binding a
cons'. (Or are you suggesting there is another way?).  My executable
is still a hell of a lot smaller than some other CLs

> 
> 3. Amortized cost: Funcall (and any other function-calling
> functionality which can't see manifestly whether the function name
> is a symbol or a cons) must now perform an extra test every time it
> operates.  furthermore, in safe code that test would have to include
> a check that the car of the function name is 'setf. 

In fact you need to also check that the cons does not have more than
two elements and that the second element is a symbol.

> You're now
> slowing down funcall, as well as each of the setf-function calls.

You don't _have_ to run the test in the common case.

What does your CL say to: (funcall '(not a function) 'bah) ?

I hope it signals an error (even in unsafe code).  So (_somewhere_ -
an internal eval?) you are already checking to see if funcall is being
called with a function object (or a symbol with a filled function
slot) as an argument.  In most cases, this will still be true so the
traditional case is not being slowed down.  (ie, invoke the object if
it is a function object, or the object in the function slot if its a
symbol, otherwise go on to the next <sarcasm> extremely expensive
</sarcasm> test:

if t_cons object && car object == 'setf && (etc) 

I think it will be relatively rare to get this far.  I agree with
Barry that funcall should have accepted function names, since the ugly
damn things have been added anyway (for the sake of CLOS - and you
bother about image size? bah!)

> 
> 
> Whenever we're talking about the CL function call, it's important
> not to trivialize what in other code would be small performance
> impacts.

I agree. But costs must be weighed holistically. In CL, a setf
function name is allowed in a function position (car of list).  So
instead of being on the defensive here, I'd like to ask you some
questions about your CL:

(1) Is your CL compliant here?  
(2) If so, how does your CL find the function object to invoke?  
(3) Are you 'binding a cons' <Raspberry>?
(4) Is it really 'cheaper' than my method, or have you moved the cost
somewhere else?
(5) If so, where?

I would be very interested to hear what your CL does.  I believe your
only valid point is the one about size.  It was certainly that issue
that worried me when I was implementing setf function names this way.
However I consider the larger size an acceptable price to pay for a
clean 'traditional', 'symbolic', implementation.

Regards,
Peter
From: Duane Rettig
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <48ywobo9h.fsf@beta.franz.com>
Peter Wood <··········@worldonline.dk> writes:

> Duane Rettig <·····@franz.com> writes:
> 
> > ··········@worldonline.dk writes:
> > 
> > > "Steven M. Haflich" <·················@franz.com> writes:
> > 
> > 
> > > > But for setf function names, there are an infinite number of
> > > > non-eql conses which name the same binding, and further, the
> > > > binding such a cons names can change over time.
> > > > 
> > > 
> > > I am suggesting that the cons _not_ have any binding at all. (I
> > > consider the very idea of binding a cons ridiculous).  The symbol
> > > _in_ the cons, which in function names always occurs in the same
> > > predictable place, namely the cadr of the cons, 'has the binding',
> > > precisely as a traditional symbol function name does.  This
> > > binding is implemented with a new slot for 'setf function names'
> > > so will not interfere with the symbol's regular/traditional
> > > binding.
> > 
> > OK, Barry has suggested the same idea.
> > 
> > > > The performance characteristics of these two sets of function
> > > > binding names is very different.  I would not want to have to
> > > > make funcall work for setf names, at least if the name is not a
> > > > manifest constant.
> > > 
> > > There is (1) a _very_ small performance cost of implementing this,
> > > and (2) it is trivially easy to implement.
> > 
> > This is very interesting. What performance characteristics did you
> > actually measure against otherwise similar other lisps?
> 
> Maybe I should have said (1) a very small cost _in my lisp_.  However,
> for the sake of argument ...

OK, that's fine.  But see below about lisps and their speed
relative to C.

> > Sorry, that question is slightly rhetorical, because I actually doubt
> > that you actually have done such an implementation, or if you have,
> > that you have performed such tests (or, if you have, that you'd be
> > willing to release those results :-)
> >
> 
> On what do your base your doubts, Duane Rettig?  

It doesn't matter; my doubts seem to have been well-founded.
You may well have implemented it, but you certainly did not
test the performance characteristics of your implementation
adequately.

> I most certainly _have_ implemented this!  Although, for funcall, it
> was 'by mistake' :-), and I removed it (for funcall) when I realised
> that it was not ANS compliant.

Correct [for the benefit of other readers, the spec calls out for
fdefinition to receive a function name (which would include both the
symbol 'foo and list '(setf foo)), but funcall receives a function
designator, which includes the symbol 'foo, the function object #'foo,
the function object #'(setf foo), but _not_ the list '(setf foo)]
It looks from later discussion that you have at least one other spec
issue to correct, as well.

> I am working on upgrading GCL to
> conform to the ANSI CL specification.  When I was doing 'setf function
> names I assumed that funcall would also take a function name, and
> adapted it to do so.  It was such a trivial and obvious change that I
> didn't bother to check until later, at which point I removed it.
> However, in my implementation, setf function names work as described
> for those functions which do take a function name.  This version of
> GCL has not been released and maybe never will be - certainly not
> tomorrow :-)
> 
> I don't have formal tests of my statement that it has a small
> performance cost.  On my system, it falls _under_ the clock
> resolution, which admittedly is not very fine.

Not only is the resolution not very fine, but it gives you absolutely
no indication of what percentage of the function calling sequence
you're dealing with.  If your application happens to have many very
short, well-optimized lisp functions, and millions of these functions
are being called over a short period, then the execution of those
functions themselves will also fall under the clock resolution, but
the ratio of those functions' execution to their call may greatly
affect how the total time in the application turns out.  Thus, to get
good timings on a function-calling-sequence, you must squeeze as much
out of the function as possible, and call it as many times as practical.

>  I can no longer test
> funcall this way since I removed this feature as non-compliant,

I submit that you have the best chance to test the feature, by
temporarily reinstating it for the timing test.  I base this on
the apparent decision you have made to add the setf cell to the
symbol, as you described above.  I wouldn't think it would be too
hard a change to make temporarily.

> but
> #'fdefinition does the same check.  #'symbol-function (obviously) does
> not do the check so maybe the following test can tell us something:

Maybe, but I'm dubious about how much it can really tell us, once
we actually get the test correct.

> [Please note that I am _completely_ uninterested in a macho pissing
> match about whose implementation can run the test fastest - I am only
> interested in wether the check is having a  significant performance
> effect.] 

Neither am I interested in any showdowns between implementations.
I have not checked out GCL speed, and I am not very concerned as
to whether it is slower than Allegro CL.  However, my premise
that these few instructions do make a difference is predicated
on the assumption that the lisp be at least in the ballpark of
C execution times (many current CL implementations get to
within 20% of C speeds).  Obviously, if some lisp implementation
is 1/10 the speed of C (which might make it 1/8 the speed of
one of the fast CL implementations), then of course these extra
couple of instructions would make 1/8 the difference in that lisp
relative to the faster ones.  Note again that I have no idea where
GCL stands in the performance range; I am instead making an
argument that the only way one can argue effectively that the
extra instructions don't matter is if the rest of the lisp is
very much slower...

> ;;simple test to compare access times for #'fdefinition and
> ;;#'symbol-function

 [test elided, to be replaced below ...]

> ;;results - most of the actual time is being taken by #'gensym !

Interesting; you have diagnosed part of the problem with your test
yourself!  This is like trying to measure the thickness of a piece
of paper by placing it on top of your desk, and then using a
yardstick to measure the height of your desk with and without the
paper.  What you need to do instead is to get a stack of 1000 sheets
(the more the better), and then measure _just_ that stack and
divide by 1000. (I chose 1000 because it is a reasonable size stack
of paper; in your test, you have a thousand sheets, alright, but
you're also stacking a thousand desks as well! :-)

> > (time (test-access 1000 'foo))
> 
> real time : 0.050 secs
> run time  : 0.050 secs
> NIL

Whenever you get times this close to the clock resolution, it
should be an indication that you have a bad test, and you must
at least up the count quite a bit.

Please note again that I am dubious about the efficacy of this
test in the first place.  However, if we clean up your test
a little and run it with enough iterations:

=====
(defvar *test-fn* (compile nil (lambda  (a b) (setf (car b) a))))

(setf (fdefinition 'foo) *test-fn*)
(setf (fdefinition '(setf foo)) *test-fn*)

(defvar *b* '(alpha beta))

(defun test-access (n fnname) 
  (do ((start 0 (1+ start))) 
      ((> start n))
    (funcall (if (consp fnname) 
                 (fdefinition fnname) ;Duane say this takes longer ...  
                 (symbol-function fnname)) ;than this 
             (gensym) *b*)))

(defun test-access2 (n fnname)
  (declare (optimize speed (safety 0)))
  (do ((start 0 (1+ start))
       (loc (gensym)))
      ((> start n))
    (declare (fixnum start))
    (funcall (if (consp fnname)
                 (fdefinition fnname) ;Duane say this takes longer ...  
                 (symbol-function fnname)) ;than this 
             loc *b*)))
=====

Results on Allegro CL (not for absolute times, but for
comparsons between the two test times, so I'm not even
providing processor type or speed):

CL-USER(2): (compile 'test-access2)
TEST-ACCESS2
NIL
NIL
CL-USER(3): (time (test-access2 1000000 'foo))
; cpu time (non-gc) 60 msec user, 0 msec system
; cpu time (gc)     0 msec user, 0 msec system
; cpu time (total)  60 msec user, 0 msec system
; real time  55 msec
; space allocation:
;  2 cons cells, 72 other bytes, 0 static bytes
NIL
CL-USER(4): (time (test-access2 1000000 '(setf foo)))
; cpu time (non-gc) 1,290 msec user, 0 msec system
; cpu time (gc)     210 msec user, 0 msec system
; cpu time (total)  1,500 msec user, 0 msec system
; real time  1,495 msec
; space allocation:
;  2 cons cells, 32,000,104 other bytes, 0 static bytes
NIL
CL-USER(5): 

> > I have no doubts that point #2 is true.  However, let me give you
> > three reasons why point #1 is definitely _not_ true:
> > 
> > 1. The cadr: Most Common Lisp function calls start with a symbol,
> > grab the function object (the first memory reference) and then
> > sometimes access the start-address through the function object
> > (second chained memory reference).  Although this extra chained
> > reference (i.e. the results of the first reference must be available
> > before the second access can actually be scheduled), this is usually
> > an acceptable set of instruction sequence, because there are other
> > non-chained movements going on during the sequence (such as the
> > setting of the count register).  This is also approximately the time
> > position-independent C code takes, so it has proved to be an
> > acceptable calling overhead.
> > 
> > However, the taking of the CADR of (setf foo) requires two _extra_
> > chained references, before you even get to the symbol.   This creates
> > two large holes in the pipeline which other activity can't fill.
> 
> This conversation started with a complaint that it is not possible to
> funcall a setf function name.  If the user is doing funcall, they are
> already adding in extra overhead.  That suggests that something as
> small as 'two extra chained references' is not going to be the straw
> that breaks the camels back.

No.
  1. (funcall #'foo ...) takes no extra chaining overhead, because the
function is already at hand.
  2. (funcall 'foo ...) takes one chain (get the function object
first, then the start
  3. (funcall #'(setf foo) ...) takes the same time as #1, because
#'(setf foo) is a function object.
  4. (funcall '(setf foo) ...) would take as long as it takes to validate
and grab the function object, plus the time for #1.

You describe funcall overhead as if funcall must be the function
that is called.  However, a call to funcall, when compiled, need
not actually go through the funcall function; it can be inlined,
and it can even be treated precisely as if it were a normal call
through a function-designator.  There is a continuum of jumping
and inlining that can occur, but the minimum overheads always
include the above.

> > 3. Amortized cost: Funcall (and any other function-calling
> > functionality which can't see manifestly whether the function name
> > is a symbol or a cons) must now perform an extra test every time it
> > operates.  furthermore, in safe code that test would have to include
> > a check that the car of the function name is 'setf. 
> 
> In fact you need to also check that the cons does not have more than
> two elements and that the second element is a symbol.
> 
> > You're now
> > slowing down funcall, as well as each of the setf-function calls.
> 
> You don't _have_ to run the test in the common case.
> 
> What does your CL say to: (funcall '(not a function) 'bah) ?
> 
> I hope it signals an error

Of course.

 (even in unsafe code).

No - we sometimes (possibly often) do, but there's no requirement for
that.

>  So (_somewhere_ -
> an internal eval?) you are already checking to see if funcall is being
> called with a function object (or a symbol with a filled function
> slot) as an argument.  In most cases, this will still be true so the
> traditional case is not being slowed down.  (ie, invoke the object if
> it is a function object, or the object in the function slot if its a
> symbol, otherwise go on to the next <sarcasm> extremely expensive
> </sarcasm> test:
> 
> if t_cons object && car object == 'setf && (etc) 
> 
> I think it will be relatively rare to get this far.  I agree with
> Barry that funcall should have accepted function names, since the ugly
> damn things have been added anyway (for the sake of CLOS - and you
> bother about image size? bah!)

It's a shame you think these are ugly.  If your effort is to bring
GCL into CL conformance, it will be hard to do if you think CL is
ugly :-)

> > Whenever we're talking about the CL function call, it's important
> > not to trivialize what in other code would be small performance
> > impacts.
> 
> I agree. But costs must be weighed holistically. In CL, a setf
> function name is allowed in a function position (car of list).

Interesting position, but incorrect.  See the spec,
section 3.1.2.1.2.

If you want some history, go to the FUNCTION-NAME writeup:
(http://www.lispworks.com/reference/HyperSpec/Issues/iss174_w.htm)
It says that the "large" proposal was adopted except for items
7, 8, and 9.  Item 7 is the one which proposed to allow a "function
name" as the car of the list, rather than allowing only a symbol.

>  So
> instead of being on the defensive here, I'd like to ask you some
> questions about your CL:
> 
> (1) Is your CL compliant here?  

Irrelevant, since your extension of allowing setf names in the
function call is not CL.

> (2) If so, how does your CL find the function object to invoke?

By getting the function object out of the symbol...

> (3) Are you 'binding a cons' <Raspberry>?

Of course not; Steve was arguing against that because of the
performance repercussions...

> (4) Is it really 'cheaper' than my method, or have you moved the cost
> somewhere else?

Your method is much more expensive, because it is trying to do much
more than the spec requires.  Therefore, there is no cost that
needs moving.

> (5) If so, where?
> 
> I would be very interested to hear what your CL does.  I believe your
> only valid point is the one about size.  It was certainly that issue
> that worried me when I was implementing setf function names this way.
> However I consider the larger size an acceptable price to pay for a
> clean 'traditional', 'symbolic', implementation.

I favor the spec, myself.

-- 
Duane Rettig    ·····@franz.com    Franz Inc.  http://www.franz.com/
555 12th St., Suite 1450               http://www.555citycenter.com/
Oakland, Ca. 94607        Phone: (510) 452-2000; Fax: (510) 452-0182   
From: Peter Wood
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <804r7c13sx.fsf@localhost.localdomain>
Ok. I was wrong about setf function names being allowable as a car of
a function form.  Most of the ground is gone from under my feet.  You
were right.  I was wrong.

Adios,
Peter
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <IbS1a.8$0Y5.745@paloalto-snr1.gtei.net>
In article <·············@beta.franz.com>,
Duane Rettig  <·····@franz.com> wrote:
>Whenever we're talking about the CL function call, it's important
>not to trivialize what in other code would be small performance
>impacts.

Lisp is *full* of features that are non-trivial to implement efficiently.
If this were an important criteria of our community, would we have
automatic type dispatching, bignum arithmetic, or GC?  Compared to these,
the impact of this rare check in FUNCALL is virtually negligible.  FUNCALL
already has to perform a type dispatch, so the extra cost of going down to
the cadr would *only* be incurred in cases where the CONS case is invoked.

As for the space -- it doesn't have to be in a slot in every symbol.  It
could be in a hash table or the property list.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Frode Vatvedt Fjeld
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <2hbs1k2c7c.fsf@vserver.cs.uit.no>
Barry Margolin <··············@level3.com> writes:

> Lisp is *full* of features that are non-trivial to implement
> efficiently.

True, but there's an important distinction between non-trivial and
impossible that you want to be quite sure you're not crossing.

> If this were an important criteria of our community, would we have
> automatic type dispatching, bignum arithmetic, or GC?  Compared to
> these, the impact of this rare check in FUNCALL is virtually
> negligible.  FUNCALL already has to perform a type dispatch, so the
> extra cost of going down to the cadr would *only* be incurred in
> cases where the CONS case is invoked.

Don't forget that funcall is a hot candidate for being inlined. This
change would roughly double the size of such inlined code.

-- 
Frode Vatvedt Fjeld
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <FwU1a.19$0Y5.1036@paloalto-snr1.gtei.net>
In article <··············@vserver.cs.uit.no>,
Frode Vatvedt Fjeld  <······@cs.uit.no> wrote:
>Barry Margolin <··············@level3.com> writes:
>
>> Lisp is *full* of features that are non-trivial to implement
>> efficiently.
>
>True, but there's an important distinction between non-trivial and
>impossible that you want to be quite sure you're not crossing.

We've demonstrated that it's not even close to impossible.  The only
question is whether the performance impact is worth it.

>> If this were an important criteria of our community, would we have
>> automatic type dispatching, bignum arithmetic, or GC?  Compared to
>> these, the impact of this rare check in FUNCALL is virtually
>> negligible.  FUNCALL already has to perform a type dispatch, so the
>> extra cost of going down to the cadr would *only* be incurred in
>> cases where the CONS case is invoked.
>
>Don't forget that funcall is a hot candidate for being inlined. This
>change would roughly double the size of such inlined code.

The basic arithmetic operators are even more hot candidates for inlining,
yet we never shied away from making them generic (in the general sense, not
the CLOS sense).  If you want good optimization, you often have to add
declarations.

(funcall (the function ...) ...)

should be inlinable with minimal overhead.

However, I suspect that allowing (SETF xxx) lists in FUNCALL wouldn't
really double the size of the inlined code.  A likely implementation would
be something like:

(declaim (inline funcall))
(defun funcall (function &rest args)
  (if (functionp function)
      (system:%fast-apply function args)
      (system:generic-apply function args)))

The inline code optimizes the case where it receives a real function
object, and all other cases (e.g. symbols, lambda expressions for CLTL1
compatibility, the proposed (setf <sym>)) would be handled by the separate
SYSTEM:GENERIC-APPLY function.

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Frode Vatvedt Fjeld
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <2h7kc73f9g.fsf@vserver.cs.uit.no>
Barry Margolin <··············@level3.com> writes:

> The inline code optimizes the case where it receives a real function
> object, and all other cases (e.g. symbols, lambda expressions for
> CLTL1 compatibility, the proposed (setf <sym>)) would be handled by
> the separate SYSTEM:GENERIC-APPLY function.

It is the case on many systems (especially 32-bit) that the symbol
case is equally cheap to the real function case. That is, they both
require one load and one compare (symbol: Compare word for symbol tag,
load symbol's function cell, vs. real function: Compare word for
"other" tag, compare/load type-tag for function type). Neither case
requires the generic-apply fallback, which would only become required
if extending funcall to accept e.g. setf conses or lambda conses or
anything else. Hence my claim of this roughly doubling the size.

-- 
Frode Vatvedt Fjeld
From: Barry Margolin
Subject: Re: LAMBDA-EXPRESSION-P ?
Date: 
Message-ID: <ezW1a.29$0Y5.1074@paloalto-snr1.gtei.net>
In article <··············@vserver.cs.uit.no>,
Frode Vatvedt Fjeld  <······@cs.uit.no> wrote:
>Barry Margolin <··············@level3.com> writes:
>
>> The inline code optimizes the case where it receives a real function
>> object, and all other cases (e.g. symbols, lambda expressions for
>> CLTL1 compatibility, the proposed (setf <sym>)) would be handled by
>> the separate SYSTEM:GENERIC-APPLY function.
>
>It is the case on many systems (especially 32-bit) that the symbol
>case is equally cheap to the real function case. That is, they both
>require one load and one compare (symbol: Compare word for symbol tag,
>load symbol's function cell, vs. real function: Compare word for
>"other" tag, compare/load type-tag for function type). Neither case
>requires the generic-apply fallback, which would only become required
>if extending funcall to accept e.g. setf conses or lambda conses or
>anything else. Hence my claim of this roughly doubling the size.

OK.  So suppose the inline function were something like:

(defun funcall (function &rest args)
  (etypecase function
    (funtion (system:%fast-function-apply function args))
    (symbol (system:%fast-symbol-apply function args))))

It could simply be changed to:

(defun funcall (function &rest args)
  (typecase function
    (funtion (system:%fast-function-apply function args))
    (symbol (system:%fast-symbol-apply function args))
    (t (system:generic-apply function args))))

This basically replaces the part of the inline code that would have
reported an error with a call to another function to handle the less common
cases that don't need to be optimized.  The inline code should be about the
same size (maybe even shorter -- it depends on what is generated for the
error reporting from ETYPECASE, but it could hardly be much shorter than
calling a function with 2 arguments).

-- 
Barry Margolin, ··············@level3.com
Genuity Managed Services, 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.