5 ms·
I'm curious as to how lisp has dealt with this for 40+ years
by jcapote 18y ago
I'm curious as to how lisp has dealt with this for 40+ years
- silentbicycle 18y agoBy getting a reputation of being poorly suited to team development, unfortunately.
- gruseom 18y agoLisp's reputation has a tenuous connection to reality; even so, I see no connection between it and the problem being discussed here (name collisions) which doesn't come up in CL. If anyone does make that argument, I'd like to see it: it would appear to require even more obtuseness than usual.
- silentbicycle 18y agoI was thinking specifically of unintentional variable capture causing name collisions in non-hygienic Common Lisp macros. While people can certainly write macros correctly and avoid them, this takes experience, and minor mistakes can introduce some really subtle bugs. [edit: noted that I'm talking specifically about Common Lisp]
- arohner 18y agoIn Scheme, it's basically impossible to write a non-hygienic macro, and in Clojure, there are no name collisions and it takes extra work to variable capture.
- deleted 18y ago[deleted]
- gruseom 18y agoOh, that. That is one of those problems people talk about but no one has. While people can certainly write macros correctly and avoid them, this takes experience No, it doesn't. It's trivial to call gensym. Edit: I'm not saying that CL's way is the best, just that this question gets way more attention than it deserves.
- dunham 18y agoI'm not a lisp expert, but my understanding is that CLOS uses packages for this. In CLOS, methods (generic functions) live outside classes. So, like normal functions, their names are qualified by the packages that they are defined in. If you want the 'sum' method declared in package 'foo', you either import it into the package/namespace you're working in, or you fully qualify the name ('foo::sum', I think). This lets you extend built-in classes within your package without getting in anyone else's way.
- gruseom 18y agoGreat explanation. It doesn't really have to do with CLOS though. The package system works on any names whether you use classes or not (we don't). One little detail I love because it illustrates Lisp's design style nicely. If you're using an exported (public) name, you say foo:sum. But if the name is private and you want to breach encapsulation to get at it, you say foo::sum. The language makes you state your intention, but makes it easy to do so and doesn't get in your way.
- arohner 18y agoClojure deals with this by having strict namespaces. Every function and "global" variable belongs to a namespace. At any time, you can refer to a function by it's fully qualified name. At the top of a namespace declaration, you can import other namespaces and alias (rename) other namespaces. It's a compile error if your declarations create an ambiguous name. i.e. (ns :foo (:use classifier) (:use active-support)) Use allows you to call all of the functions in the namespace without a fully qualified name. In this case, there would be a compile error, because both use statements try to alias a function sum in the current namespace. The alternative would be to use require, which doesn't bring the functions into the current namespace: (ns :foo (:require classifier) (:require [active-support :as as])) Then you call the two sum functions like (classifier/sum [1 2 3 4]) (as/sum [1 2 3 4]) The huge advantage is that since there are only functions, there are no methods on objects and every function is subject to namespacing. If you want to monkey patch, there is a function called binding, which changes the value of a variable, but only within the calling scope, in the current thread. i.e. (def x 3) (println "x = " x) (binding [x 5] (println "x = " x)) (println "x = " x) will return => 3 => 5 => 3 Since named functions are just anonymous functions stored in variables, you can use the binding trick to monkey patch. It's very clean because you can't interfere with any other code. Binding affects fully qualified vars, which makes it very difficult to stomp on someone else's function.