<< Back to previous view

[CLJ-461] require namespace implicitly Created: 16/Oct/10  Updated: 21/Jun/11  Resolved: 21/Jun/11

Status: Closed
Project: Clojure
Component/s: None
Affects Version/s: None
Fix Version/s: Backlog

Type: Enhancement Priority: Blocker
Reporter: Mike Hinchey Assignee: Mike Hinchey
Resolution: Declined Votes: 1
Labels: None


Referencing a function with a fully-qualified namespace should work without first using require or use, similar to how a fully-qualified java class can be used without importing it.

It's a small change in Compiler that tries to call (require x) if the fully qualified classname is not found. This should give priority to the java class, which protects backwards compatibility. There is no runtime performance impact, only compile time (the first time the namespace is seen). The fact that code (the namespace) is loaded during compilation of a form is no different than loading code to look up a java class.

This makes it easier to write quick scripts as in the example below, also to use one-liners in the repl or ad hoc in code.

For example: java -cp src/clj/:classes clojure.main -e "(clojure.set/union #{1} #{2})"

Currently on master, this produces: Exception in thread "main" java.lang.ClassNotFoundException: clojure.set
but this works: java -cp src/clj/:classes clojure.main -e "(require 'clojure.set) (clojure.set/union #{1} #{2})"

Obviously, (use) would make the code shorter, but my goal is to make it implicit.

Discussion: http://groups.google.com/group/clojure-dev/t/69823ce63dd94a0c

Comment by Assembla Importer [ 17/Oct/10 9:37 PM ]

Converted from http://www.assembla.com/spaces/clojure/tickets/461
mh-461-require.patch - https://www.assembla.com/spaces/clojure/documents/cQSfQ22L8r37zxeJe5cbCb/download/cQSfQ22L8r37zxeJe5cbCb

Comment by Assembla Importer [ 17/Oct/10 9:37 PM ]

mikehinchey said: [file:cQSfQ22L8r37zxeJe5cbCb]: patch to fix #461

Comment by Assembla Importer [ 17/Oct/10 9:37 PM ]

mikehinchey said: The discussion shows some people want this, other's aren't sure. Attached the patch so people can try it out.

Comment by Stuart Sierra [ 12/Dec/10 4:06 PM ]

One problem I see: With this change, it becomes harder for code-reading tools to determine all the dependencies of a namespace without evaluating it. Right now, I can parse the "ns" declaration of any file and know its dependencies. (Obviously, this breaks if the file loads code outside of the "ns" declaration, but then static analysis is virtually impossible.)

With this change, the "ns" declaration no longer represents the complete set of dependencies for the namespace. I can try to read the whole file, but I have no way of knowing if "foo.bar.baz/quux" represents a namespace-qualified symbol or a static Java member, unless I evaluate it.

I think loading Java classes and loading Clojure namespaces are fundamentally different operations because classes, unlike namespaces, cannot change after they are loaded.

Comment by Paul Stadig [ 10/Jun/11 2:01 PM ]

On the first point: it is already hard for code-reading tools. One can (require 'something) outside of the ns form. There are also uses of eval, direct references to fully qualified classes, and other nefarious ways. You seem to have admitted this already, so I'm not quite sure what you are objecting to? Objection 1: OVERRULED.

On the second point: you already admitted above that the ns declaration doesn't represent the complete set of dependencies, so there is no "no longer" about it. It was just never the case. Secondly, "foo.bar.baz/quux" could be a static Java member, or a Clojure Var, but that is irrelevant to this patch. That was always the case, and the patch is about autoloading, not about interpreting to what "foo.bar.baz/quux" is referring. Objection 2: OVERRULED.

On the third point: again, I don't see the relevance of the fact that a namespace can be changed after it has been loaded but a class cannot. Again, the patch is about autoloading, and the immutability/mutability of namespaces vs. classes is orthogonal. Objection 3: OVERRULED.

Finally, the original ML thread that spawned this had a +1 from the following persons: myself, Christophe Grand, Phil Hagelberg, Laurent Petit, Steve Gilardi, Cosmin Stejerean, and Chas Emerick.

It had a -1 only from: you, Dimitry Gashinsky.

A negative comment from Stu Halloway, and a positive-ish comment from Chris Houser.

I say we move forward with this.

Comment by Kevin Downey [ 10/Jun/11 2:07 PM ]

I have serious reservations about the complexity this will add to the compiler. the current patch is no good, it will break for aot compilation.

Comment by Paul Stadig [ 10/Jun/11 2:21 PM ]

So I've been told that my tongue-in-cheek may not have translated well, but that was the intent. I apologize if that was the case.

My point is just to draw attention to this ticket again. It was discussed on the ML with several +1's and has been mentioned again in chat. I don't think any of the objections that Stuart Sierra raised are particularly relevant to the question of autoloading the namespace of a fully qualified var.

Has anyone tried the patch? Kevin Downey seems to think it will not work in the context of AOT.

Do we need a new patch?

Comment by Kevin Downey [ 10/Jun/11 2:27 PM ]

the patch doesn't actually cause code to load the required namespaces to be generated. it only loads the required namespaces during compilation, which is why it breaks aot. once you get into code generation for aot it gets complicated, where does the generated code go? do we want to try and emit it separately like the requires from an ns form or does it get emitted in the middle of the particular function being compiled. I think the first approach is desirable from a stand point of correctness, but carries with it a load of complexity.

Comment by Paul Stadig [ 10/Jun/11 3:00 PM ]

I think it gets emitted in the middle of a function, just like would happen now if you do (require 'clojure.set) (clojure.set/union ...)

Is there a benefit to having it emit separately like an ns form? Isn't the ns form just a macro that turns into calls to (require ...) which happen to be at the top of a file because that's where the ns form is?

Comment by Rich Hickey [ 21/Jun/11 6:41 PM ]

This is not a good idea, for many reasons, the simplest of which is: it makes loading a side effect of calling a function in a module. Since loading can have arbitrary effects, it shouldn't be implicit. This isn't warranted by the meager benefits it might provide.

Generated at Thu Jul 02 18:26:32 CDT 2015 using JIRA 4.4#649-r158309.