This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-08-18
Channels
- # alda (6)
- # architecture (1)
- # bangalore-clj (3)
- # beginners (39)
- # boot (292)
- # braveandtrue (1)
- # cider (7)
- # clara (2)
- # cljs-dev (20)
- # cljsjs (9)
- # cljsrn (42)
- # clojure (127)
- # clojure-chennai (1)
- # clojure-dev (96)
- # clojure-india (1)
- # clojure-russia (175)
- # clojure-spec (56)
- # clojure-uk (11)
- # clojureindia (1)
- # clojurescript (82)
- # core-async (7)
- # cursive (21)
- # data-science (1)
- # datomic (173)
- # funcool (4)
- # hoplon (8)
- # instaparse (1)
- # jobs (7)
- # jobs-discuss (1)
- # jobs-rus (30)
- # lambdaisland (1)
- # lein-figwheel (8)
- # off-topic (5)
- # om (51)
- # onyx (79)
- # other-languages (7)
- # planck (8)
- # re-frame (95)
- # reagent (6)
- # rum (8)
- # specter (4)
- # untangled (54)
- # yada (5)
With the namespaced maps functionality, is the intention that the namespaces refer to valid existing namespaces?
i.e. in the example: #:person{:first "Han" :last "Solo" :ship #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter"}}
, is the assumption that person
and ship
are actual namespaces, or is it considered ok that they just be ad-hoc qualifiers?
Just ad hoc qualifiers (although they can be namespaces).
That’s why there’s a JIRA issue open for allowing some sort of alias call for a non-existent namespace, so you can use it with ::
keywords.
@seancorfield: Thanks - got a link for that JIRA?
Having said that, I can’t find the JIRA issue (hah! I knew you were going to ask!)
Does that mean that ::
keywords and namespaced map forms do have to use aliases or valid namespaces?
I swear @alexmiller said that such an issue was under consideration...
Right now, you need a valid namespace to create an alias. Alex offered a workaround (that is used somewhere in core I think?) where you use in-ns
to enter the non-existent namespace then in-ns
to switch back to your own namespace, then you can create the alias.
That’s the current workaround 🙂
"Clojure/core-approved!" 😈
That’s pretty horrible, I’d better check what Cursive thinks of that, especially since it looks like those aliases will be used outside that ns.
This in one of our files where we’re using specs and namespaced keywords:
;; workaround aliasing restriction
(in-ns 'ws.domain.member)
(in-ns 'ws.domain.member.update)
(in-ns 'ws.domain.member.validation)
;; back to normal
(in-ns 'ws.profile.field)
(alias 'm 'ws.domain.member)
(alias 'mu 'ws.domain.member.update)
(alias 'mv 'ws.domain.member.validation)
😆It is under consideration but I don't think there is a public jira
@alexmiller: Is the current expectation that ::
keywords and maps do use valid aliases or namespaces?
i.e. should I be flagging it if the user used #::ship{:name "Millenium Falcon" :model "YT-1300f light freighter”}
where ship
is not a valid alias or namespace?
It needs to be a valid alias
The reader blows up otherwise:
boot.user=> #::ship{:foo :bar}
clojure.lang.LispReader$ReaderException: java.lang.RuntimeException: Unknown auto-resolved namespace alias: ship
java.lang.RuntimeException: Unknown auto-resolved namespace alias: ship
clojure.lang.LispReader$ReaderException: java.lang.RuntimeException: Unmatched delimiter: }
java.lang.RuntimeException: Unmatched delimiter: }
boot.user=> (in-ns 'ship)
:foo:bar#object[clojure.lang.Namespace 0x74bf3db1 "ship"]
ship=> (in-ns 'boot-user)
#object[clojure.lang.Namespace 0x215119de "boot-user"]
boot-user=> #::ship{:foo :bar}
#:ship{:foo :bar}
Right, can be fully qualified
Basically the namespace part is resolved in the current ns
Ok. But the same is not true of #:
forms, they can have some arbitrary disambiguator?
Not sure what you mean
If you mean namespaced maps they follow the same rules
Has to be either fully qualified or an alias in current ns
@alexmiller: So in #:ship{:name "Millenium Falcon" :model "YT-1300f light freighter”}
ship
must be a valid namespace?
No, we showed that above.
It must be either a fully qualified ns or a valid alias in current ns
I don't know what you mean by that
#:anything{:foo :bar}
is valid right?
Those are both auto resolved
Ohhh, you may be right
I'm tired
Ah, I see the confusion. That produces {:anything/foo :bar}
which is fine.
So the result is fully qualified.
I’m trying to figure out if only “auto-resolved” forms are required to use a valid alias or namespace.
#:: is auto resolved
But if you use ::
on a key it will auto-resolve
Using same rules as :: keywords
So #:
as a prefix is a red herring here. Only ::
matters. For your question.
The alias or valid namespace issue only applies to ::
Right. So for both maps and keywords, using the ::
form means that the following name must refer to an alias or namespace, but for :
forms it can be anything you like.
And there's #:ship{:name ".." ::thing 42}
as well, right? Where ::thing
will auto-resolve.
Right. In the map case where the keyword actually specifies a ns, that ns will be used (taking into account the _
case too)
So in boot.user=> #:ship{:name ".." ::thing 42}
will produce {:ship/name ".." :boot.user/thing 42}
Did the _
thing get in? Hmm, let me try...
Yeah, :_/a
produces :a
(inside a ns-qualified map literal)
boot.user=> #:ship{:name "..." ::thing 42 :_/a 1}
{:ship/name "...", :boot.user/thing 42, :a 1}
Is all of this documented somewhere, hopefully? i.e. what is supposed to be accepted, and for bonus points whether the implementation accepts things that are not supported?
@andy.fingerhut: Yes, the JIRA is pretty comprehensive: http://dev.clojure.org/jira/browse/CLJ-1910
The one case that is confusing is the #:foo{}
case, where the JIRA uses the word “namespace” but foo
is not actually required to be one.
So that case is something that could be documented more explicitly? (assuming it is intended to be accepted, not an accident of the current implementation)
Is there any known resolution regarding
(defn ^long bad [x] (inc x))
vs (defn good ^long [^long x] (inc x))
?
I know the second approach is the proper one, but if you mistakenly apply the first one - there's nothing to warn you that you might get a clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException: Unable to resolve classname: [email protected]
later on
the explicit {:tag 'long}
approach got fixed in 1.8 (http://dev.clojure.org/jira/browse/CLJ-1533)
@andy.fingerhut @cfleming it is documented at https://clojure.org/reference/reader
The issue with the dual meaning of "namespace" (as a naming qualifier in keywords and symbols) and as a named var container is not unique to here. older Clojure docs refer to the latter as libraries, which is equally confusing in a different way. Not enough words.
@dm3 what resolution are you looking for? In general type hints are hints and this ignored if not applicable. This is a bit different in that it's a hint of an invalid form, not a hint that doesn't apply. I think http://dev.clojure.org/jira/browse/CLJ-1674 may be applicable
Regarding primitives support in Clojure, I'm guessing the 4 argument restriction was to avoid generating too many interfaces. Was an alternate design considered of dynamically generating interfaces based on what combinations of primitive arguments are actually used throughout a project?
So if only usage of primitives is [a1 ^long a2 a3 a4 a5]
the only interface generated is clojure.lang.IFn$OOLOOO
don’t know, that was long before my involvement
@dm3: the Eastwood linter helps detect some incorrect type hints, and I think the one in your example, too. https://github.com/jonase/eastwood
@nathanmarz: The problem is that Clojure in general does not assume global knowledge of the project
I guess you could have a global cache of type signature->interface, and that would be populated as you compiled forms
I looked at doing exactly that for a while, but you quickly run into problems with naming the generated interfaces, especially if you allow the generation of typed invoke signatures for arbitrary user types.
The JVM gives you a 65535 chr budget for class/interface names, so for the most part you can just splat fully qualified type names together, but I never got past a proof of concept using short class names and the hash of the full thing which was problematic from a repeatability/caching perspective. For binary compat your generated invoke interface names need to be fully deterministic. I know @bronsa looked at this too at some point, don't think he took it any further.
@cfleming @arrdem Yea the caching approach is what I was thinking of, and you could just limit the types to objects, doubles, and longs. Pushing user types down to the bytecode level seems like a separate issue.
I think it should be an easier way to extend over the 4args support by reducing the number of combinations, making eg IFn$LOLD , IFn$LLOD, $LDOL and so on map to the same interface and have the compiler just reorder args at compile time but I never tried implementing it (using this approach the current number of prim interfaces would go from 358 to 100 and adding a 5th arg would go from 100 to 162 rather than from 358 to 1086, we could support 7 args with just 352 interfaces)
I suspect there’s probably a much better approach using invokedynamic that would let you do this stuff dynamically without all the interfaces