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

#' in macros

10 views
Skip to first unread message

Vladimir Zolotykh

unread,
Mar 1, 2002, 8:35:19 AM3/1/02
to
Let me consider the simplified macros (useless as macros, the only
purpose is to illustrate the idea):

(defmacro foo ()
(flet ((bar (&key (test '#'equal) size)
`(make-hash-table :test ,test ,@(when size `(:size ,size)))))
(bar :test '#'eql)))

(defmacro baz ()
(flet ((bar (&key (test '#'equal) size)
`(make-hash-table :test ,test ,@(when size `(:size ,size)))))
(bar :test '#'eql)))

Are there strong reasons to use '#' instead of plain #' ? Seems so, at
least lexical environments might be important and of course they could
vary much while using FOO and BAZ. (For these two macros this is
unimportant though). Are there any other reasons beside that ?

--
Vladimir Zolotykh

Kent M Pitman

unread,
Mar 1, 2002, 9:11:23 AM3/1/02
to
Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:

> Let me consider the simplified macros (useless as macros, the only
> purpose is to illustrate the idea):
>
> (defmacro foo ()
> (flet ((bar (&key (test '#'equal) size)
> `(make-hash-table :test ,test ,@(when size `(:size ,size)))))
> (bar :test '#'eql)))
>
> (defmacro baz ()
> (flet ((bar (&key (test '#'equal) size)
> `(make-hash-table :test ,test ,@(when size `(:size ,size)))))
> (bar :test '#'eql)))
>
> Are there strong reasons to use '#' instead of plain #' ?

I'm not much of a fan of using #'eql as an arg to MAKE-HASH-TABLE.
I would never recommend anyone do so.

I'm not sure there's any requirement that #' (that is, that the FUNCTION
special operator) not cons. Mostly it doesn't need to, and most
implementations avoid consing where they can, but I think it would be
conforming (someone correct me if I'm misremembering) if an implementation
were to store functions in a "more efficient" [non-object] form and only
cons function objects (or even only create function cells) on demand.
The "function cell" is an abstraction, not a data layout requirement.
I think it was the case in Maclisp that symbols didn't get value cells
unless you assigned them. [Maclisp didn't have function cells per se; it
did something much weirder with symbol properties, but one could make the
analogy that it didn't have function cells except on demand either, since
the various properties didn't exist unless needed, in part because their
order in the plist actually mattered and having them pre-exist would have
had weird and unacceptable implications on the order, which was intended to
be settable by users for certain kinds of tricks it's better not to mention
in polite company. (Programming style wasn't given by God, we had to
evolve it gradually by observing what made us most queasy and learning not
to do that.)]

In a world where #' can return different values each time, and wher
(eq #'foo #'foo) might be NIL, you have the weird problem of how to write
MAKE-HASH-TABLE as a structural access looking for a name rather than an
EQ test ... and this could be spoofed, by the way, by someone knowing what
the low-level implementation is. All in all, seeing people compare function
objects for identity of this kind makes me nervous because my mind immediately
sees the "possible world" where this is unpleasant.

> Seems so, at
> least lexical environments might be important and of course they could
> vary much while using FOO and BAZ. (For these two macros this is
> unimportant though). Are there any other reasons beside that ?

I'm not sure what lexicality has to do with anything here. MAKE-HASH-TABLE
doesn't know the lexical environment, and only four possible functions may
be designated (though 8 possible designators are allowed, two for each
function). However you name things, I took the real question to be what kind
of object you could/should pass as an arg to MAKE-HASH-TABLE.

Erik Naggum

unread,
Mar 1, 2002, 2:00:01 PM3/1/02
to
* Kent M Pitman

| I'm not much of a fan of using #'eql as an arg to MAKE-HASH-TABLE.
| I would never recommend anyone do so.

Are you discommending #'eql and 'eql, or are you discommending #'eq,
#'eql, #'equal, and #'equalp? I believe the latter, but there is some
possibility you mean the former.

///
--
In a fight against something, the fight has value, victory has none.
In a fight for something, the fight is a loss, victory merely relief.

Martin Simmons

unread,
Mar 1, 2002, 2:49:35 PM3/1/02
to
"Vladimir Zolotykh" <gsm...@eurocom.od.ua> wrote in message
news:3C7F8397...@eurocom.od.ua...

Hmm, it seems to me that you intended one of your macros to use plain #'...
Assuming that, then the answer is yes, there are strong reasons. The reason is
that using #' will evaluate at macroexpansion time and hence will attempt to
place the function object #'eql into the compiled file, which isn't allowed by
ANSI.
--
Martin Simmons, Xanalys Software Tools
zne...@xanalys.com
rot13 to reply

Kent M Pitman

unread,
Mar 1, 2002, 6:53:15 PM3/1/02
to
Erik Naggum <er...@naggum.net> writes:

> * Kent M Pitman
> | I'm not much of a fan of using #'eql as an arg to MAKE-HASH-TABLE.
> | I would never recommend anyone do so.
>
> Are you discommending #'eql and 'eql, or are you discommending #'eq,
> #'eql, #'equal, and #'equalp? I believe the latter, but there is some
> possibility you mean the former.

The latter. Sorry if I said something confusing. I prefer to pass any of
the four symbols (EQ, EQL, EQUAL, or EQUALP) rather than any of the four
corresponding function objects (#'EQ, #'EQL, #'EQUAL, or #'EQUALP).

[Also, just as random trivia, since you're asking if I'm opining along another
axis not the topic of this thread, but I'll answer anyway: I dislike EQUALP
generally and avoid it as much as possible. I try never to use EQUALP hash
tables for the sake of fully general EQUALPness of recursive structures,
which I mostly don't understand or trust. Mostly I only ever use EQUALP
hash tables as substitutes for STRING-EQUAL hash tables or = hash tables ...
and I try hard not to pun it so I'm doing both at the same time, since it's
only coincidence that one can; that is, you can't pun STRING= (strict
compare for strings) with = (loose compare of numbers), nor can you pun
STRING-EQUAL (loose compare of strings) + EQL (strict compare of numbers)...]

Vladimir Zolotykh

unread,
Mar 2, 2002, 6:17:02 AM3/2/02
to
Kent M Pitman wrote:
>
> Erik Naggum <er...@naggum.net> writes:
>
> > * Kent M Pitman
> > | I'm not much of a fan of using #'eql as an arg to MAKE-HASH-TABLE.
> > | I would never recommend anyone do so.
> >
> > Are you discommending #'eql and 'eql, or are you discommending #'eq,
> > #'eql, #'equal, and #'equalp? I believe the latter, but there is some
> > possibility you mean the former.
>
> The latter. Sorry if I said something confusing. I prefer to pass any of
> the four symbols (EQ, EQL, EQUAL, or EQUALP) rather than any of the four
> corresponding function objects (#'EQ, #'EQL, #'EQUAL, or #'EQUALP).

But this is not always give needed results. For example: (I must say
that example in my original posting was badly chosen because it
emphasizes hash-tables but actually they are not the key of a
question):

(defun my-test (x) (oddp x))
(defmacro my-macro (list)
(let ((test '#'my-test)) ; [*]
`(find-if ,test ,list)))

(defun test ()
(flet ((my-test (x)
(evenp x)))
(my-macro '(1 2))))

This gives:

(test) => 2

If I change to ''my-test at line marked [*] it become
giving 1. '#' seems is more reliable in macros, isn't it ?

--
Vladimir Zolotykh

Kent M Pitman

unread,
Mar 2, 2002, 10:40:37 AM3/2/02
to
Vladimir Zolotykh <gsm...@eurocom.od.ua> writes:

> Kent M Pitman wrote:
> >
> > Erik Naggum <er...@naggum.net> writes:
> >
> > > * Kent M Pitman
> > > | I'm not much of a fan of using #'eql as an arg to MAKE-HASH-TABLE.
> > > | I would never recommend anyone do so.
> > >
> > > Are you discommending #'eql and 'eql, or are you discommending #'eq,
> > > #'eql, #'equal, and #'equalp? I believe the latter, but there is some
> > > possibility you mean the former.
> >
> > The latter. Sorry if I said something confusing. I prefer to pass any of
> > the four symbols (EQ, EQL, EQUAL, or EQUALP) rather than any of the four
> > corresponding function objects (#'EQ, #'EQL, #'EQUAL, or #'EQUALP).
>
> But this is not always give needed results. For example: (I must say
> that example in my original posting was badly chosen because it
> emphasizes hash-tables but actually they are not the key of a
> question):

No, in all the cases of things like FIND-IF, you can pass any function
and it is simply funcalled. In that case, I absolutely believe you should
use the function object, not a symbol (which must be coerced to a function).

But MAKE-HASH-TABLE is special because it doesn't take a general predicate,
and in general its argument is more like a keyword than like a function.
You certainly can't pass #'(lambda (x y) (eql x y)) to MAKE-HASH-TABLE.
You can pass #'(lambda (x) (evenp x)) to #'FIND-IF.

> (defun my-test (x) (oddp x))
> (defmacro my-macro (list)
> (let ((test '#'my-test)) ; [*]
> `(find-if ,test ,list)))
>
> (defun test ()
> (flet ((my-test (x)
> (evenp x)))
> (my-macro '(1 2))))
>
> This gives:
>
> (test) => 2
>
> If I change to ''my-test at line marked [*] it become
> giving 1. '#' seems is more reliable in macros, isn't it ?

It isn't an issue of "reliable", it's an issue of "definition".
The outcome is not probabilistic. The macro has a meaning and a
contract of of use which if clearly expressed to its users will
work fine.

Incidentally, IMO, you should never write a macro like the above.
It is legal code, but I think it is very very bad style.
IMO, macros should always assume their function namespace is fixed,
and no author of a macro should ever perturb the internal workings
of a macro by changing the binding of a function or other operator
that its expansion depends on. You should never use FLET, LABELS,
or MACROLET to bind a function name for a package you do not own,
and if you own the package, you should know the macro's definition
and avoid doing this.

One of the great lessons in the acquisition of power, not just in
programming languages but in life, is that the phrase "I have the
power to do" is not synonymous with "I should do". The more power you
acquire, the more the world is saying to you "I trust you not to use
this power indiscriminately." If you insist on using broad power
indiscriminately, you will soon find yourself causing problems and
restricted from using it.

For MY-MACRO to work as you're describing, a critical aspect is that
it must document that it uses the lexical environment's definition of
MY-TEST. If it documents that, then there's not a "reliability
question", there's just a "correctness question". To use that
environment, you must use certain operators and not others.

0 new messages