With respect to the Lisp 1/2 debate, I hate how this:
(defun foo (g y)
(g y))
(foo #'- 10) ; error
Is an error in Common Lisp. Instead, you have to: (defun foo (g y)
(funcall g y))
(foo #'- 10) ; works
That's just so inelegant IMO. Scheme does the "right" thing and lets you do: (define (foo g y) (g y))
(foo - 10) ; works
but lacks a de facto build tool and package management system. (I also really like Scheme's macro system, but not everyone agrees). Clojure solves the build tool and package management system, does the "right" thing with higher order functions, and offers seamless Java(Script) interop, which is why it has enjoyed more "mainstream" success than other Lisps. (define (foo lst)
(list (map + lst)
(map - lst)))
WTF?Or:
(define (foo + - lst)
(+ (reduce + lst)
(reduce - lst)))
(foo - +)That's one of the things I hate about Clojure. I _like_ being able to do this:
(defun foo (list)
(list "length" (length list))) (defn foo [list]
(clojure.core/list "length" (count list)))
Or, in the case of CL, we could do this: (defun foo (list)
(cl:list "length" (length list)))
I'd argue that you should do this anyway to clarify what you mean by "list" when you shadow a common name like that.Absolutely not, don't encourage people to do this in CL. Clojure is Clojure, you have to do this, or if you prefer you can use use (refer ... :rename {...}) to reference external names with different local names.
CL packages have their own semantic w.r.t. importing and shadowing symbols. Without context, if I read your example in CL, I am starting to ask myself if I am in a package where you defined a "list" function, because this is the unique case that requires me to explicitely qualify cl:list. If there was any confusion in the first place, I could easily select the symbol and ask Lisp what it is and whose package it belongs to.
> if I read your example in CL, I am starting to ask myself
> if I am in a package where you defined a "list" function
Anytime you use a shadowed symbol, qualify it with a namespace. Just because you can do something does not mean you should. It won't hurt the code and it makes the meaning perfectly clear.That's what I am telling you: in CL, your example does not make sense except in a package "FOO" where FOO:LIST is a function/macro, simply because there is absolutely no ambiguity between a function named LIST and a variable named LIST.
If I am in the CL-USER package and write (LIST (LENGTH LIST)), both occurrences of LIST refer to the same symbol, and there is no "shadowing" in place in the CL sense of the term.
> Specifying the namespace of `list` communicates one and only one idea: I am referring to a particular binding of `list`
The fact that you prefix or not the symbol with a package has no impact on the binding, i.e. the (CL) namespace where the symbol is being looked-up. As an operator, list is bound in the function namespace (and can't be redefined). Likewise, (find-class 'list) or (gethash my-hash 'list) look for different bindings in different namespaces.
What (CL:LIST LIST) actually communicates is that both symbols are most likely to be different ones, since for some reason the writer felt the need to distinguish them. That example tells me that something unusual is happening.
Assuming we are in package "P":
- You can refer to a symbol from another package like you did:
(lib:foo bar)
- or, if you don't have currently a FOO function in your package, you can (import 'lib:foo), in which case you can write: (foo bar)
You may mix symbols from different packages, as long as they don't conflict, but in some cases that might be difficult to understand. Whether you qualify all of them or only a subset depends on the actual context.- Finally, if you happen to have already a FOO in your package P but you prefer to use FOO from "lib", you can shadow the first one, and so:
(foo bar)
... will read as (lib:foo p:bar). But then you can't access p:foo anymore.
That's why "Anytime you use a shadowed symbol, qualify it with a namespace" is a strange thing to say under the CL notion of shadowing symbols, because by definition the symbol that was shadowed is uninterned and not accessible anymore, except if you manage to keep a reference to it or store a value that was bound to it in some namespace. > simply because there is absolutely no ambiguity between a
> function named LIST and a variable named LIST.
To a machine, correct. To a human, this is not always the case. > But then you can't access p:foo anymore. That's why
> "Anytime you use a shadowed symbol, qualify it with a
> namespace" is a strange thing to say under the CL notion
> of shadowing symbols, because by definition the symbol
> that was shadowed is uninterned and not accessible
> anymore, except if you manage to keep a reference to it
> or store a value that was bound to it in some namespace.
Of course the machine knows what you mean. I never denied this. But when you're in a massive file fixing a 15 year old bug this information becomes less clear and you're going to appreciate a fully-qualified name.If you have two namespaces providing the same symbol, qualify which one you mean. This is true in just about any language. The meaning of the code is painfully obvious to the human who has to maintain it. Even if you can keep track of it without any issues, assume the maintainer is totally inept and can't. Names are important, take the time to get them right.
EDIT:
Also adding I was using the term `shadowing` somewhat sloppily. Names are important enough that anytime one is being used in more than one way we should take great precaution.
I am not talking about different symbols which happen to share the same name (in different packages), but about the different meanings of a single symbol in different contexts. In the example of (CL:LIST LIST), I said that a reader would infer that both symbols are different, whereas you are saying that we should prefix them even if they are, in fact, the same symbol.
I am using the CL definition of namespace, by the way:
namespace n.
1. bindings whose denotations are restricted to a particular kind.
``The bindings of names to tags is the tag namespace.''
2. any mapping whose domain is a set of names.
``A package defines a namespace.''
That means that even though packages define namespaces, not all namespaces are tied to packages. In particular, you cannot distinguish the function namespace from the value namespace with a package prefix.That's why in Lisp I can clear any confusion by writing either LIST or #'LIST, and that's why I like FUNCALL. Within standard evaluation rules (LIST X) does not use the value of a variable named LIST.
In all your comments above you use words which have both verb and noun meanings, but you did not need to explain it to me. Did I seem confused? Did I say: "Hey, you wrote 'to shadow ...' but that's wrong, a 'shadow' is the thing I see on the ground when its sunny".
What words look like is very distinct from their "role" in a sentence, and this is so much a natural thing to do for humans that most mainstream programming languages enable this.
static void foo (int foo) {
System.out.println(foo);
}
So, in the extreme case of: (defmethod foo ((foo foo))
(funcall foo))
... how would you disambiguate things using package prefixes? (defmethod fun:foo ((var:foo class:foo))
(funcall var:foo))
Anybody who introduces made-up packages like this in CL to "clean-up the mess" will lose the right to commit code ;-)> Also adding I was using the term `shadowing` somewhat sloppily. Names are important enough that anytime one is being used in more than one way we should take great precaution.
Yeah, right. I am talking about lisp:namespaces instead of clojure:namespaces. But I can "name things" and "have a name" without having to distinguish both usages.