3 ms·
That is convenient, but keep in mind that namespaces solve this problem: (defn foo [list] (clojure.core/list "length" (count list))) Or, in the ca
by madmax96 10y ago
That is convenient, but keep in mind that namespaces solve this problem:
(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.
- junke 10y ago> 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.
- madmax96 10y agoReadability matters. Specifying the namespace of `list` communicates one and only one idea: I am referring to a particular binding of `list`. By leaving out the namespace qualifier when you shadow a symbol you can only add to the cognitive load necessary to understand the meaning of the code. A languages' only purpose to communicate meaning, whether that be to a machine or a person. > 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.
- junke 10y ago> Readability matters. 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.
- madmax96 10y ago> 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.