This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # announcements (2)
- # babashka (38)
- # beginners (38)
- # calva (4)
- # cider (1)
- # clj-kondo (43)
- # clojure (33)
- # clojure-dev (39)
- # clojure-europe (4)
- # clojure-spec (4)
- # clojure-uk (2)
- # conjure (6)
- # core-async (5)
- # core-typed (3)
- # data-science (2)
- # datomic (6)
- # depstar (4)
- # emacs (1)
- # events (2)
- # fulcro (4)
- # jobs-discuss (4)
- # luminus (1)
- # off-topic (5)
- # re-frame (14)
- # shadow-cljs (8)
- # sql (8)
- # tools-deps (22)
I have noticed that the
defn macro does not allow me to define a function with a qualified name.
(defn foo/bar ...) fails with an error such as:
However, I can use
Syntax error macroexpanding clojure.core/defn at (rte_construct.clj:401:1). rte/expand - failed: simple-symbol? at: [:fn-name] spec: :clojure.core.specs.alpha/defn-args
(def ...)to achieve the same thing with no such error occurring. I suspect that the error is erroneous. I.e., the syntax checker is overzealous. If it is really important that
defnnot be used to define functions with fully qualified names, shouldn't
defhave the same restriction? And if using
deffor this purpose is OK, then shouldn't the restriction be relaxed on
defn? Why is the restriction in place for
defn only allows you to define vars in the current namespace, so a qualified symbol is not appropriate
appropriate in what sense? would it break something in the language?
What do you mean about using
For example if i'm at the REPL, i might very well like to
(defn ...) any function in my project. Right?
defn is just sugar over
def and the docstring of
> Creates and interns a global var with the name
> of symbol in the current namespace (ns) or locates such a var if
> it already exists.
so how can I use intern to define a function in a different namespace without interning into the current one? sorry I don't understand your suggestion.
OK, that's great. But it doesn't explain why defn has the extra syntax restriction that the name must be a simple symbol?
For example, I can define
-defn as follows
Is there anything dangerous about this, other than it doesnt handle the optional docstring as defn does, and doesnt handle var-args function defs?
(defmacro -defn "Like defn, but allows symbol naming the function to be in any namespace, not just a simple symbol" [name doc-string lambda-list & body] `(def ~name ~doc-string (fn ~lambda-list [email protected])))
I'm not sure why
defn doesn't allow qualified symbols, but my guess would be that it's not very common to define things outside of the current namespace.
I agree that it is probably the common case. However, I'd still like to know the reason for such a hostile syntax check?
If there is a real reason for the syntax check, then my use of
-defn may have the same problem. So I'd love to know about it.
The check is according to the docstring. Not letting slip through things that are against the docstring is helpful. You may disagree with the docstring, but that doesn't make it different.
So the question changes. Rather than asking about the syntax check, I need to ask about why the function is documented in such a restrictive way which doesn't match the implementation?
Michiel, I know you're not the one who did the implementation. so i'm not complaining in your direction.
I think your question is: why doesn't
defn let me define things outside the current namespace. That I don't know, other than my guess above.
This may also shed some light on it: https://stackoverflow.com/a/18141019/6264.
def is a special form, handled by the compiler
Which of the following is clearer?
(defn and ;; bdd/and "Perform a Boolean AND on 0 or more Bdds." ( true) ([bdd] bdd) ([bdd1 bdd2] (cond (= false bdd1) false (= false bdd2) false (= true bdd1) bdd2 (= true bdd2) bdd1 (identical? bdd1 bdd2) bdd1 :else (binary-op and bdd1 bdd2))) ([bdd1 bdd2 & bdds] (reduce and (apply cons bdd1 bdd2 bdds))))
(ns-defn bdd/and "Perform a Boolean AND on 0 or more Bdds." ( true) ([bdd] bdd) ([bdd1 bdd2] (cond (= false bdd1) false (= false bdd2) false (= true bdd1) bdd2 (= true bdd2) bdd1 (identical? bdd1 bdd2) bdd1 :else (binary-op and bdd1 bdd2))) ([bdd1 bdd2 & bdds] (reduce and (apply cons bdd1 bdd2 bdds))))
I did not design Clojure, but I suspect that those who did find it perfectly clear that
defn always and only are used to define Vars within the current namespace. The most common practice by far in Clojure is to have an
ns form near the beginning of each file, and then not to do
in-ns after that in source code files. (There are exceptions, but they are unusual). In this usual case, the namespace of every
defn in the same file is very clearly understood.
Based on my experience with Clojure, I would personally find it confusing if there were
defn forms that created Vars in namespaces other than the current one.
I can't say whether would be confusing or not. the the case is that
def allows it and
defn does not.
It seems that perhaps the implemention of
def allows it only if the namespace is the current namespace.
You asked which of two alternatives would be clearer. I tried to give reasons above why I think it is perfectly clear which namespace a
defn is in, even if there is no namespace in the symbol given to
defn -- because it is understood to be in the current namespace.
And for the majority of Clojure source files, every
defn is in the same namespace, i.e. the one whose
ns form is near the beginning of the file.
I'm not a designer of Clojure, just a close observer, so do not treat my words with the weight of someone who has designed it.
OK, it's not a real hinderance for me. and in the end it's not really so important. just seems inconsistent to me, with no compelling reason. But with lisp, it's very easy to work around most syntactical problems, whether real or perceived
foo=> (ns bar) nil bar=> (def foo/bar 1) Syntax error compiling def at (REPL:1:1). Can't refer to qualified var that doesn't exist bar=> (def bar/bar 1) #'bar/bar bar=> (ns foo) nil foo=> (def bar/bar 1) Syntax error compiling def at (REPL:1:1). Can't create defs outside of current ns
ahhh interesting. So that sounds like the syntax check is really wrong for defn. Because I've aliased the current ns to
foo and then attempted to
(defn foo/my-fun ....) which fails and
(def foo/my-fn ...) which succeeds. Looks like the syntax check for
defn should be changed to allow either a simple symbol, or a qualified symbol which resolves to the current namespace.