This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-12-13
Channels
- # admin-announcements (208)
- # beginners (53)
- # boot (46)
- # cider (10)
- # cljs-dev (26)
- # cljsjs (10)
- # clojure (66)
- # clojure-dev (3)
- # clojure-russia (14)
- # clojurecup (5)
- # clojurescript (302)
- # cursive (22)
- # data-science (1)
- # datomic (10)
- # emacs (1)
- # events (2)
- # hoplon (91)
- # incanter (1)
- # ldnclj (3)
- # leiningen (1)
- # off-topic (2)
- # om (41)
- # re-frame (40)
- # reagent (78)
there seem to be some subtleties to require
order — if I order things one way, I get “undefined” for imported identifiers. Does anyone know of a good wiki page or walk-through on this?
@jaredly: Hmm… perhaps something you are requiring itself doesn’t properly require its own deps.
I’ve definitely had an ordering error (a couple of days ago), where reordering imports fixed it 😞
@jaredly: Perhaps you simply caused a new hash ordering in the deps hash https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L1903
@jaredly: require order does not matter, if it does it is most likely due to some undeclared deps in your files.
@mfikes: I actually thought require ordering was changed to keep the ordering you used in the ns
form, because someone reported a bug that manifested due to them not being order, but I couldn't find the commit afterwards, so I might have imagined that '
candidate #1 for broken ordering are multi-methods since you can call the defmulti
without having to require the namespace that contains the defmethod
http://dev.clojure.org/jira/browse/CLJS-1159 if someone wants to get busy 😉
@thheller @jaen @jaredly I created a sample repo that shows that ClojureScript does not preserve order. Interestingly, the repo does not show that this is the case for Clojure.
Then I must have been imagining things, I was almost sure someone brought it up before and a fix was made for that. This has also bit me once or twice in the past.
@jaen: Hmm. Maybe you are recalling something from the Clojure side. Maybe it came up as an issue in Clojure and was addressed there.
Could be, though I was pretty sure it was Cljs. But well, memory likes playing tricks : V
@jaen: I’ve also seen something in the ClojureScript AST that appears to be keeping track of the order that symbols have been seen.
Oh, so maybe there was a fix, solved some surface issue, but not the root of it. But no matter, it's irrelevant whether I was imagining things or not in the end ; d
Nicola Mometto confirmed that Clojure does preserve order, but that this is only an implementation detail.
That's... peculiar. I imagined it would be a conscious choice since require order might matter.
That raises an interesting question: Are there cases where you need order but can’t establish it by saying ns a depends on ns b via a :require
spec in a?
I don't remember what I was doing that I would have needed deterministic ordering, but in general - that's a good question.
Just to make sure - we're talking about ordering of clauses within a single ns
declaration, yes? As in
(ns something
(:require cljs.react my.namespace))
not shuffling cljs.react
and my.namespace
around?Yes, the question has to do with trying to establish order via the textual order in an ns
form. Which is the bit that is not guaranteed.
So, with the example above, if my.namespace
uses stuff from cljs.react
, the textual order in something
is insufficient. (Instead my.namespace
needs to have a :require
for cljs.react
in its own ns
form.)
Then I can think up of a simple example. Not sure if that is a kosher way to structure an application, but nonetheless. Imagine there's some namespace called dispatcher
and you can register your function with it using (dispatcher/register path handler)
. The way dispatcher
resolves the handlers to call when you do (dispatcher/call path & arguments)
depends on the insertion order. There's no other way to guarantee this will work reliably unless :require
is ordered.
Otherwise the alternative is to not split up handlers across namespaces (like handlers.common
, handlers.authorisation
handlers.users-page
and so on), but keep them in a single file, but that doesn't sound like a good solution to me.
The problem goes away if you structure your application using components for example, but I don't think it's as common in the Clojurescript land as it is in Clojure.
If I want react mouse events to work well with async channels I need to call .persist on the events before shoving them down them don't I?
Having mutable events in React kind of makes core.async interaction a touch awkward doesn't it?
Has anyone used Mori w/ CLJS? I use CLJS for my data layer w/ vanilla JS/React. I would love to have my CLJS export functions return a Mori wrapped EDN objects.
I could do clj->js
then mori.toClj
. I couldn’t find anything better in the docs.
I might be wrong, but aren't mori's datastructures just Clojurescript structures, so no translation is necessary?
no i think maybe your right. It seems like all the functions to interact with EDN is calling mori.get instead of myEdnObject.get
I'd imagine basing on what I understand mori is for mori.first(your_cljs_function_returning_a_collection())
to work
thanks jaen. I guess that'll do it... in this instance it kind of feels like I'm splitting the slider logic between the callback and the async stuff.
@triss: some of that is inevitable, if you have some logic on the other side of the channel, I guess.
[Random] A quick way to see if you’re in a bootstrapped REPL: Evaluate #{1 2 3}
and see if it prints the same back (bootstrapped) or #{1 3 2}
(not).
might be worth to add a warning if a namespace tries to use a fully qualified name without a :require
for it
Ahh… perhaps this helps clarify: In the unordered repo, I expect the call to evaluate dep.z/z
to fail.
Right? I think this is just poor wording on my part in the readme, unless there is something more subtle you are saying.
since they don't have any deps the compiler thinks it is fair game to sort them in any way it likes
But isn't that's what the issue is about (if I understand it right)? That is whether the topological sort should only take namespace requirements into consideration or the order the namespaces appear in in the require clause as well.
The unordered
tree is an example of an incorrect setup. It is there to illustrate how things fail.
Why? If loading namespaces can be sideffectful, reordering can cause a working program to stop working.
The fundamental issue is that you cannot use the textual order in an ns
form to control the order.
Why? Would you then care to scroll up to my example and point out where my assumptions are wrong?
Right, @jaen you cannot use the textual order in :require
to make that situation work.
This is a point, like I said I used it to illustrate what I understand the problem is, not said it's a kosher way to structure a Clojurescript application, but that's sort of a thing allowing side effects in top level forms lets you do nonetheless.
If that's a bad thing to do, then there should probably be a warning for that at the very least.
@mfikes: well yes, but I understood that the issue is about whether the textual order in the ns
form should matter or not. Or did I misunderstand something?
@jaen: In Clojure it is evidently not guaranteed either. But it does occur by accident of an implementation detail.
(I think one thing that may have spawned this conversation is that there perhaps additional subtle issues surrounding this subject that come to play if you turn on the new parallel compilation feature. In other words, code that is skating on thin ice breaks when you turn on this feature.)
It may be a failing on my part, but I've never read that ordering in the :require
clause doesn't guarantee anything. Moreover it's a vector not a hash map (by which I mean the surface syntax), which implies that ordering is significant.
Here is the set https://github.com/clojure/clojurescript/blob/master/src/main/clojure/cljs/analyzer.cljc#L1903
But what I mean is - that is an implementation detail that's not evident from the outside.
Well, in Clojure I wouldn't, I use component which makes that irrelevent, since ordering is implicit from the system map shape.
A couple of other things that exacerbate things, IMHO, is that you can require
a and then gain access to the things that a itself requires. And (for some of us at least), Cursive will resolve a symbol even though you haven’t properly :require
d it.
Maybe, but observe for example this re-frame sample - https://github.com/madvas/fractalify/blob/master/src/cljs/fractalify/users/handlers.cljs
Perhaps two solutions in ClojureScript are (1) Explicitly do the registering in code that registers things in the required order. (2) Make one of the namespaces artificially depend on the other, to force the order.
@mfikes I think we should emit a warning if a namespaces requires a fully qualified var without having a :require
for it (or :use
)
I'm not saying it's good, but nonetheless it's popular, especially with libraries like Reagent making it simple to write that way.
The way I look at it, any namespace can declare a dependency on another. Thus you have a partial order.
If fractalify.users.handlers
expects other things to be registered prior to it, it can (artificially) require the namespace that registers those things. (But this seems less than ideal and perhaps an abuse of :require
)
Now, I'm not saying requires should be changed to have the order of clauses in it be significant, but if that's bad then I think user should be made aware of that by the compiler if possible.
Put all of those top level forms into a side-effecting function, and then call that function from some other namespace at the right time during inti.
warnings for fully-qualified vars without require should be pretty straightforward though
> you expect something, so declare it
But I'd agree that's abuse of require
, it's there for you to require code you need, not sequence sideffects in top level forms.
The init function for namespace sounds sensible, but it's a cultural thing. C++ is a great language if you have the right culture, experience and discipline. Enforcing things is better, I think.
@thheller: Perhaps it is even legal for code in ns a to make use of transitive deps of a ns it explicitly requires. But this seems fragile.
@mfikes: If I understand what you are saying then I'm pretty sure it works like that in Clojurescript. When I require a namespaces in the browser REPL, I can then use things it required with fully qualified symbols no problem.
@thheller: yep, what @jaen said. Let’s say (ns a.core (:require b.core))
then the code in a.core
can reliably use things that b.core
requires. But, this seems fragile to rely on transitivity. I’m arguing it is better for a.core
to actually :require
the things it uses.
I'm just wondering how feasible would it be for compiler to warn on any top-level function call that reaches outside the current namespace?
(ns a.core
(:require b.core))
(c.core/foo 1) ;; This should cause a warning to be emitted
@dnolen: maybe I'm not clear enough - I'm not talking about using undefined symbols, I'm talking about calling sideffecting functions from other namespaces at the top level.
@mfikes: but Cljs being different I mean you can't eval in Clojurescript so you can guarantee that during compilation. Not so in Clojure.
@thheller: I'm not saying there should be a warning about using symbols from other namespaces at the top level for any and all cases. Macros emitting code into current namespace are totally okay, since this does not depend on require ordering at all.
On the other hand if that macro emits a function that sideffects it should be a warning.
Hah, I noticed over at the dev channel, that I didn't make up the issue being reported at the very least. Just the fix part.
Don't want to barge in #C07UQ678E so I'll leave this here:
The way I look at this the options are either to:
a) have the ordering of require/use/etc. clauses in the ns
macro be a part of the language semantics, which makes sense since loading a namespace is an imperative process of creating vars and calling functions at the top level, where inter-namespace ordering can be significant,
b) have no ordering of require/use/etc. clauses in the ns
macro be a part of the language semantics, which in turn should make doing cross-namespace sideffects either outright forbidden or at the very least - warn.
Doing anything else would be inconsistent IMO. One behaviour would be declarative while the other - imperative, which would result in not-so-obvious behaviours when namespace require order gets well... reordered.
I know that explicit is better than implicit, but... Do anybody know robust way to pass some value inside lexical scope? Like binding
, but working with lazy sequences?
@ul: FWIW, that reminds me of this thread where Brandon Bloom ends up creating bound-fn
for ClojureScript. https://groups.google.com/forum/#!topic/clojure/6cmnkHmHBNw
@mfikes: so the branch patch in the thread is not in ClojureScript yet I assume?
@richiardiandrea: Please define “branch patch"
ok thanks, just because the thread is so old I thought of asking 😄
@richiardiandrea: No problem. I should have said Bloom ended up creating a proposed bound-fn
for ClojureScript.
I might actually add some tests on binding
to replumb
as it can be useful as reference...
I was wondering about the cost of var indirection. For me, this takes about 6.1 seconds
(time (let [a (atom 0)] (doseq [x (range 10000000)] (swap! a inc))))
while pulling the fns into locals
(time (let [local-swap! swap! local-inc inc a (atom 0)] (doseq [x (range 10000000)] (local-swap! a local-inc))))
runs in 4.5 seconds. This is probably a bad micro-benchmark, being a tight loop. Wondering if others have ever felt the need to do anything like this.So I imagine you were using those - https://github.com/andrewmcveigh/cljs-time/blob/master/src/cljs_time/extend.cljs - and they didn't work?
Even this is sufficient to make the test work: (extend-type js/goog.date.Date IHash (-hash [o] 1))
Without that, you get funny answers. (hash (js/goog.date.Date. 2015 11 3))
changes each time you do it.
@jaen: Because if the hashes collide then the hash-map and hash-set algorithms typically fall back to a linked list based on =
In @gerrit ’s original (not= (hash (Date. blah)) (hash (Date. blah))
given whatever funky thing was going on. (Perhaps it was giving the hash of the object address.)
(-hash [o] (hash (.getTime o)))
this should probably suffice as proper hash implementation?
yeah kind of. this is what cljs-time.extend
does:
(-equiv [o other]
(and (instance? goog.date.Date other)
(identical? (.getTime o) (.getTime other))
(identical? (.getTimezoneOffset o) (.getTimezoneOffset other))))
I guess doing it the java way should work. as timezoneoffset seems to be a number as well
I suppose as long as all datetimes are in the same timeones you shouldn't have too much collisions.
for reference: I hope this does the trick
(-hash [o] (+ (.getTime o) (* 37 (.getTimezoneOffset o))))
@gerrit: whether the TZ is included in the hash could be driven by perf. (Either choice should function correctly.)
Yeah, it's quite interesting how much the conflict resolution strategy affects the performance.
I am running a core.js that was generated by ClojureScript as part of a system running on node and the "system" can't find "goog" goog.provide('pow.core'); ^ ReferenceError: goog is not defined at Object.<anonymous> (/home/mstang/Desktop/projects/codetest-1/out/server/pow/core.js:2:1) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32)
I tried to use "require" thinking that nodes require would load it, but no luck. Has anyone else run into this issue?
What I tried was: var goog = require('../out/server/goog/base.js'); var code = require('../out/server/pow/core.js');
Also, I was building with an older version of cljs, I switched to the latest and now I am getting :
Compiling "out/server/pow.js" failed. Exception in thread "main" java.lang.AbstractMethodError: Method cljsbuild/compiler/SourcePaths.findsources(Ljava/lang/Object;)Ljava/lang/Object; is abstract, compiling:(/tmp/form-init6738966304942402426.clj:1:73)
@markstang: all I can say is Closure and CommonJS / Node are two different module systems, with two different require
constructs.
@mfikes Yeah, I read that somewhere someone had written a "require" for google to work within node
@markstang the second error most likely requires a newer version of lein-cljsbuild
wont work since goog is a required global object, but it should be managed by the build and included in core.js
sorry that is pretty much all I know about the cljsbuild world, not sure how things are done over there these days
you are not building a module, at least as far as I can tell cljsbuild does not support that
ok, well back to the drawing board, I am trying to replace an existing source file with a clojurescript generated one
Universal Module Definition
basically a way to combine the various module systems the js world has