6

Browsing through Common Lisp sources I notice that people most often use #'foo where 'foo would suffice – that is, wherever a function designator is accepted, they choose to pass a function.

Of course #'foo is necessary when foo is defined via flet and so forth. I understand the mechanics of it all – my question is one of style. Is it just because people don't want to think about 'foo versus #'foo, so they use the latter because the former will sometimes not work? Even if that were so, it wouldn't explain the use of #'(lambda ...) because #' is always unnecessary there.

CL is sometimes called ugly because of #', and most newcomers don't realize that it's unnecessary in (I daresay) the majority of cases. I'm not a newcomer but I happen to prefer 'foo. Why am I unusual? If I publish some code that gives symbols to funcall and apply, will I be mocked and humiliated? I am considering starting a Function Designators Anonymous chapter in my area. I suspect that people want to use function designators but, due to peer pressure, are afraid to "come out" about it.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • Incidentally, there are some functions that you might expect would accept function designators that don't. E.g., `complement` only accepts functions. This means that `(position-if (complement f) …)` isn't actually equivalent to `(position-if-not f …)`, as the latter can accept a symbol for `f`, but the former can't. I just stumbled across that in an answer to [Split a string even if the last character is a delimiter](http://stackoverflow.com/q/24000527/1281433). – Joshua Taylor Jun 02 '14 at 20:22

3 Answers3

6

Using #' is conceptually simpler: Whether you're dealing with an anonymous function, a function obtained by calling compile, or a function referenced with #', you're always referencing a function object. Given this, passing a symbol to map or funcall is an odd special case that is simply not as intuitive as passing a function object.

However, there are cases where symbols are arguably conceptually more appropriate, such as in the case of the :test argument to make-hash-table. In this case, you're selecting one out of four different kinds of hash tables specified by the name of the key comparison function. I prefer a symbol in this case, since there is no point in using a function object to distinguish one kind of hash table from another. (It is also misleading, since it tends to deceive you into believing that you can pass just any arbitrary equivalence predicate to make-hash-table.)

Matthias Benkard
  • 15,497
  • 4
  • 39
  • 47
3

They are not the same. 'foo is a reference to whatever happens to be the global definition of a foo function, and is a leftover from old times when scopes where muchly confused.

CL-USER(1): (defun foo (x) 1)
FOO
CL-USER(2): (flet ((foo (x) 2)) (mapcar #'foo '(1 2 3)))
(2 2 2)
CL-USER(3): (flet ((foo (x) 2)) (mapcar 'foo '(1 2 3)))
(1 1 1)
Eli Barzilay
  • 29,301
  • 3
  • 67
  • 110
  • 1
    It doesn't appear that you read past the first paragraph. You've missed both the purpose and the content of the post. – Brian Watkins Oct 09 '11 at 20:52
  • No, I didn't miss that. Using `'foo` is still a bad idea for that reason. If anything, consider what a compiler might do when you use `#'foo` (you use the value so it can inline the call and more) vs `'foo` (you refer to whatever the global function is, which can change when more code is reloaded). In any case, the same argument can be said on sending a symbol to `funcall`: you can replace `(funcall f 'x ...)` with `(f x ...)` -- it works in *most* cases, right? – Eli Barzilay Oct 10 '11 at 00:26
  • "I understand the mechanics of it all – my question is one of style." Please note the presupposition for the question. It is abundantly obvious that I did not imply they were "the same". I understand details involved. As I said, this was a question of style. – Brian Watkins Oct 10 '11 at 01:18
  • Please understand that I understand what you understand. To make my point painfully clear, there are cases where using `'foo` *happens* to work, due to certain ways in which your code is laid out and a coincidence of legacy support for ancient lisps which CL had as a subgoal. It is therefore a style that is hardly used in modern code as a result. IOW, the incorrectness of using `'foo` is far greater than the perceived ugliness of a `#` character. – Eli Barzilay Oct 10 '11 at 01:56
  • 1
    But the argument applies equally in the other direction. There is a certain school of thought that says explicit is better than implicit. I could equally argue that it's better to be explicit about what you mean: 'foo for global definitions and #'foo for lexical ones. A dogma of always using one or the other is probably the worst solution. – Brian Watkins Oct 10 '11 at 18:22
  • 2
    It is somewhat annoying that you are phrasing it as a legacy issue. No, global definitions are redefinitions are convenient. I know you hate them because you come from Scheme. But remember the Racket web server is restarted with every change, whereas I can connect to remote Lisp server with SLIME and change a definition on the fly. Big difference. (For good or bad, one could argue. I would say great for experts, bad for newcomers.) – Brian Watkins Oct 10 '11 at 18:25
  • The whole point of lexical scope -- which CL embraced as much as it could -- is the *uniform* treatment of all bindings, whether they come from "the global environment" or a local one. Ultimately, they are all treated in exactly the same way: as lexical environment. The same goes for referring to bindings, and trying to use a different reference for bindings based on other information you have on some name (how it's bound) is missing the point of lexical scope. In a way, this is much like the new closures in C++: letting you *specify* which names you close over is missing much of the point. – Eli Barzilay Oct 10 '11 at 23:39
  • As for Racket (or Scheme), that's completely unrelated here. They just happen to be more modern dialects of Lisp that have no such legacy use of symbols as fake functions. And I have no idea how you got the Racket web server here... Like most Lisps, it can certainly retain information and change definitions on the fly -- so this is obviously a non-point in this context. – Eli Barzilay Oct 10 '11 at 23:42
  • The blessed state of global definitions is what makes CL so much more practical and convenient than Scheme. It's what enables tools like SLIME, where one can examine any macro expansion (even stepwise recursively) or connect to a running server and compile new definitions just as one would locally. Passing global definitions off as unwanted legacy is simply ill-informed Scheme trolling. – Brian Watkins Oct 11 '11 at 00:45
  • These tools are not available in Racket because, I suspect, everything is lexical. That's why the Racket server gets restarted on each change: you have to rebuild the lexical environment from square one each time. The barrier to overcome these obstacles is too impractical for Scheme. Or perhaps you have better excuses for why such tools don't exist in Racket. In any case please think twice before trolling Lisp questions on SO. – Brian Watkins Oct 11 '11 at 00:46
  • Um, I said that these tools *do* exist for Racket, therefore building an argument on some inherent reason why they can't be made is provably false. Same goes for slime -- it definitely doesn't *depend* in some crucial way on "blessed" symbols. Same goes for looking at macro expansion (exists in Racket too). You're building towers of arguments assuming that I'm trolling for Scheme but you're the one who brought it in. In fact, your own question starts from admitting that most *CLers* avoid the symbol form (modulo Matthias's answer). – Eli Barzilay Oct 11 '11 at 03:38
  • But the tools don't exist. For example there is no SLIME for Scheme in which I can place my cursor on a form and see its macroexpansion, and then do so again for any of the expanded subforms. This convenience is due to global definitions along with the package system which makes it manageable. You can troll all you like about how global definitions are an unfortunate legacy in CL, but the fact of the matter is that they are downright practical. So please take the random Scheme advocacy elsewhere. – Brian Watkins Oct 11 '11 at 15:14
  • Portable tools for Scheme don't exist -- but they do for Racket, and they do for other implementation. (There's even a slime interface to some, IIRC.) But again, Scheme is unrelated here. Grepping this page for "scheme" and "racket" will show that you were the one who brought them into this "discussion", and you'll also see my first reaction: "completely unrelated here". I guess that you'll insist keeping them in, so go ahead, repeat your flame attempt yet one more time. It's fun. – Eli Barzilay Oct 11 '11 at 17:06
  • Well at least you finally conceded that Scheme cannot support these tools without implementation-dependent hacks. Ergo, global definitions are not "leftover from old times when scopes where muchly confused." There are good reasons behind them, and their practical result is that they enable these tools. Scheme has not developed the rich ecosystem of tools which are available in CL. Racket is stuck in a bottle, without a standard to break it free. Your initial post betrays the usual nearsighted Scheme advocacy. Why pretend otherwise? – Brian Watkins Oct 12 '11 at 11:56
  • 1
    Yes, *Scheme* (the general concept) is useless for real work. (I'm known for such criticism -- "finally" is bogus; if you google-stalk me, at least do your homework.) But that's still irrelevant -- "Ergo" is bogus: the fact that there are implementations that have these tools *without* using symbols as functions is a counterexample. IOW, CL without that hack would be mostly the same, tools will keep working, and looks like nobody except for you will notice much. As for the attempted flame finale, you'll need to do better if you want to be a troll. Keep practicing! – Eli Barzilay Oct 12 '11 at 13:47
1

Those are 2 separate style decisions, that anyone has to make for himself. I've never seen any criticism of any of the four combinations.

Personally I prefer to use #' instead of ', because it makes functions more visible. I think, this isn't ugly at all — on the contrary, I like this more explicit syntax. Although, programming in Clojure, I only rarely miss it.

Yet I use lambda without sharp-quote. A good discussion of this can be found in Let over Lambda. And the original argument for #'(lambda... goes to Kent Pitman, I believe.

Vsevolod Dyomkin
  • 9,343
  • 2
  • 31
  • 36