Fork me on GitHub

Hi @mfikes & @darwin I had a question..what is the scope of the cljs-oss organization on GitHub? There is one tiny tiny cljs project that deserves some love and I was wondering whether it would be a good idea to "share" it under an org 😄


Sorry for the ping 😅


@richiardiandrea Here is the discussion that led to the creation of that organization:


Ok cool so my small adopted lib would not be a good fit there 😸


mfikes posted a message in the last week or so on a single 'clj' command line to start a cljs repl. Does anyone have that handy? I thought I could find it by searching on Slack, but either it has fallen out of the history, or I am just not choosing the right search terms. Anyone have that handy?


If empty were defined as

(defn empty [coll] 
  (when (implements? IEmptyableCollection coll) 
    (-empty coll)))
it would seem to more closely match the semantics of Clojure's empty (with a simple example being the case of passing a non-collection: (empty "abc")). Is my thinking flawed here? (Apart from perf implications.)


@mfikes There are def a few people out there extending native types for -empty and this would break it.


@rauh OK, so satisfies? would be needed


@mfikes Yeah, or how we often do it: First check for implements, then dispatch with ^not-native hint and then check for statisfies and dispatch to protocol dispatcher.


I guess we currently throw whereas Clojure silently return nil. So yeah, we do have a semnatic mismatch here.


Another option is to just do a extend-type default which we also do for hash & iequiv


I could see an argument that empty only takes collections, but, with no spec for empty, it is tempting to derive the semantics from the Clojure implementation.


I'll write up a JIRA so the presumed semantic mismatch is captured.

Alex Miller (Clojure team)15:01:41

regarding empty and things that don’t work with it ….

Alex Miller (Clojure team)15:01:36

the reason why records and map entries don’t work with empty is because they are fixed size tuples and it does not make sense to have a fixed size tuple that has 0 entries/elements

Alex Miller (Clojure team)15:01:09

semantics that align with that idea are good ones

Alex Miller (Clojure team)15:01:46

we don’t have explicit tuple types in Clojure, which is what makes this harder to talk about. Rich went down that road back in the 1.7-ish timeframe but ultimately found that it did not perform well enough to replace small vector usage (mostly due to megamorphic de-optimizations)

Alex Miller (Clojure team)15:01:29

while having empty return nil as the fallback is the current documented behavior, I would find it difficult to defend that design decision. It’s hard for me to come up with a scenario where that seems like the right answer. :)

Alex Miller (Clojure team)15:01:40

records throw UnsupportedOperationException if you try to empty them and that seems better


I agree, I think the current impl which throws is better than silently returning nil, even if it's different to CLJ.


I wonder, does (empty "abc") only work accidentally in Clojure? In other words, is it an invalid program with undefined semantics?


probably one for @alexmiller

Alex Miller (Clojure team)15:01:43

as always, I would suggest reading the docstring

Alex Miller (Clojure team)15:01:25

in this case, it says “, or nil” which implies to me that it is intentionally returning nil for non-collection use cases. That does not make sense to me personally.

Alex Miller (Clojure team)15:01:49

while there many punny cases where nil is handy, it is not clear to me that this is one of them :)

Alex Miller (Clojure team)15:01:29

(empty nil) ;; => nil is probably useful


FWIW, my intent with the above was to simply make ClojureScript match Clojure's semantics. (While also only guessing at what those semantics truly are, and cheating by looking at the implementation.)

Alex Miller (Clojure team)16:01:13

I hear ya. I don’t think it would be a bad thing if cljs deviated in disallowing empty on things that are not collections or nil


And, I failed in my analysis, missing the behavior for records 🙂

Alex Miller (Clojure team)16:01:14

so records are tricky in that they are collections and will probably pass any type check but throw in the impl


(Part of me feels like simply waiting on these kinds of things where there is a bit of uncertainty for the point when specs are written, which nails things down, in a sense.)

Alex Miller (Clojure team)16:01:46

the problem is that there are 100s of methods that require this kind of interpretation :)


If you had to spec empty that would be an interesting task... hrm

Alex Miller (Clojure team)16:01:48

Clojure actually has a test-empty test that checks things like (and (= (empty "abc") nil))

Alex Miller (Clojure team)16:01:12

but I think that’s more tests written from looking at the impl, than tests that should predict the behavior

Alex Miller (Clojure team)16:01:07

(ignore the and there, that’s some test detritus)

Alex Miller (Clojure team)16:01:24

I think I would spec it as (s/fdef clojure.core/empty :args (s/cat :c (s/nilable coll?)) :ret (s/nilable coll?))


I forget, is there a desire / goal to ultimately spec the core functions, where feasible?

Alex Miller (Clojure team)16:01:10

yes, and I’ve worked on it at times

Alex Miller (Clojure team)16:01:28

one of the issues is whether you proactively load them

Alex Miller (Clojure team)16:01:45

loading 100s of specs on startup is unlikely to make anyone happy wrt startup time

Alex Miller (Clojure team)16:01:17

so I think you would want them in a separate namespace (from the existing macro specs) so you can choose whether and when to load them


For now, I've "self-declined" as being premature, especially if the spec for empty ends up invalidating the questionable reversed engineered semantics in that ticket.