Fork me on GitHub

Does anyone know why not= was chosen over !=? My brain just decided to ask itself.


I can’t answer with authority, but I would wager a combination of history and consistency. In most lisps that I’ve experienced, (not ...) is the negation function. Also in most Lisps “!” never carried the meaning of “not” as it does in C language descendants.


I assumed so @cmack, it's just like removing a paren in (not (... There was a lot of new syntax in Clojure however, compared to other lisps.


What’s the tidiest inverse of (vec some-map)?


Turning a vector of key value pairs into a map?


No, a vector of vectors of pairs. Edit: sorry, yes, I misunderstood.


(into {} %)

👍 8

where % is the result of (vec some-map)


should IPrintWithWriter/-pr-writer be expected to print valid EDN?

Alex Miller (Clojure team)16:07:43

there is no "edn safe" printing path


I voted 🙂

Alex Miller (Clojure team)16:07:13

this is a common problem and it doesn't have a good general solution, really it's up to you to ensure you have data that will print to valid readable edn right now

Alex Miller (Clojure team)16:07:55

but it seems like something that should have a better answer


yeah. I’m working on a REBL-like app for CLJS, but it requires sending/receiving the datafied form over a wire. not having a reliable way of ensuring something that a user application tap>s out can be read on the other side is rough


specifically, I had a hugely nested map with a Reagent RAtom like:

{:current-state #<Atom: 111, ...>}
which took a bit of time to troubleshoot. I couldn’t figure out how to get the reader to tell me what form it couldn’t read, either

Alex Miller (Clojure team)17:07:24

well you shouldn't have that problem in Clojure, as it will fall back to an #object tagged literal (which is still readable!)

Alex Miller (Clojure team)17:07:35

so that might be something to change in cljs


it will fallback in the reading or the writing?


I think the issue is that the implementation of -pr-writer for the reagent.ratom/RAtom type writes out #<Atom: something>, which isn't readable


I'm currently calling pr-str on the whole data structure to as a way to "write" the EDN


it sounds like you're saying that the behavior on the JVM would ignore this implementation and print #object[reagent.ratom/RAtom], or I'm using the wrong tool (`pr-str`) to do this?

Alex Miller (Clojure team)18:07:48

more specifically, print-method is defined on Object to print in a readable way

Alex Miller (Clojure team)18:07:44

Clojure used to print objects without a printer in an unreadable way but we changed that in Clojure 1.6 (iirc)

Alex Miller (Clojure team)18:07:01

and cljs could do the same


but if the object has their own implementation of printing, that doesn't apply, right?

Alex Miller (Clojure team)18:07:35

this is the fallthrough if no print is defined

Alex Miller (Clojure team)18:07:39

user=> *ns*
#object[clojure.lang.Namespace 0x51b01960 "user"]


right, I see the same behavior in CLJS

Alex Miller (Clojure team)18:07:13

there is no reader defined for #object, but you can install a default-data-reader-fn to use the built-in tagged-literal function as a reader


so for my case, the issue is the way Reagent implements printing on their custom atom type. but also that there's nothing that really says that printing should be valid EDN anyway

Alex Miller (Clojure team)18:07:53

well #<Atom: 111, ...> above is not readable

Alex Miller (Clojure team)18:07:20

well I'd say it's generally bad to print in a way you know won't be printable

Alex Miller (Clojure team)18:07:32

so whoever is doing that shouldn't imo :)


great, I'll open an issue with Reagent then

Alex Miller (Clojure team)18:07:00

or there should be something additional being done to install a print-method

Alex Miller (Clojure team)18:07:06

not sure which is appropriate here

Alex Miller (Clojure team)18:07:23

but atoms are a good case where it's probably possible to print something, but is that useful to you?


not sure I understand the question tbh


I'm not sure how useful printing just an atom is for me, except that it happens to be a part of a larger structure that I want to inspect

Alex Miller (Clojure team)19:07:25

if you have a stateful atom and print it to a string, does it make any sense to reconstitute it back into an object later when other objects can no longer refer to it

Alex Miller (Clojure team)19:07:36

if you're just inspecting, then you probably don't care


atm, I just want to make it passably readable. it doesn't need to hydrate it into an actual atom; just using the default tagged-literal would be enough for me


hydrating atoms could be useful for saving to disk and then resuming application state on startup, but not something I'm worried about atm


Would a multimethod be faster than the following:

(defn execute-on-type [type x y z]
  (case type
    :foo (execute-foo x y z)
    :bar (execute-bar x y z)))


not clear on what sort of magic happens under the hood


it would be slower, but it's extensible to new keys without changing its code


multimethods are definitely not there for performance


@csd that is just screaming for protocols

✔️ 4
Alex Miller (Clojure team)20:07:47

well with a keyword type, probably multimethods are better


you could make a placeholder type, but it would be clumsy yeah


Assuming there is some requirement to stick with keywords - it just seemed like type based dispatch to me


eyeballing the code for how case vs multimethod are implemented, I think you'll find multimethod to be a little slower, but it will be easier to extend. (case) can use hashing to run against pre-calculated values, whereas best case you get with multimethod is a pass on the initial (=) check in (isa?). I would prefer the multimethod for its easier extensibility (were I on the project).


also case doesn't do the var indirection that multimethods do


which can effect how things can inline when the JIT kicks in

Alex Miller (Clojure team)20:07:10

as usual, use appropriate skepticism with microbenchmarks


right - but the initial question was a microbenchmark question (is this dispatch faster than this other one)

Alex Miller (Clojure team)20:07:15

but general commentary still valid


What does protocol default mean in that benchmark? A protocol on java.lang.Object?


Given that (according to the blog) the greater the variety in your uses the less the margin gets, I would be really disinclined to write using (case)


You're also on the order of micro-optimizations here where you're better served by readability.


does anybody know the best way to launch a clojure repl within clojure? I want to make my clojure program into an uberjar that, when run, just dumps the user into a clojure repl in my module and prints a little help message.


As a newb, I'd guess something like ( function call


start clojure.main as your init class


^better idea


well maybe I can load my own module, then have it call the thing in clojure.main that launches a repl


Probably, and that's probably what you'll want to actually do anyway since you will want to do setup stuff for the user on startup (like read a config file, do your (requires), etc).


or if you require your module, when clojure.main starts your module will be preloaded - I think there's a way to select the ns clojure.main starts in as well


You mean by editing the clojure source file to (require '[myns])?


(nvm, answered by your link)


yeah - It would be more like -i "(doto 'my.ns require in-ns)" if the -i effects the repl itself


and maybe also -e for any prep code that shouldn't be run at the top level of that ns


Oh cool, thanks, that looks like it will work


this is what clj / clojure are using also, you could potentially leverage those depending on what you are doing


oh yeah clojure.main/repl looks easiest, thanks @dpsutton. Now i have to figure out how to exit the one I just launched inside of my repl in emacs...


(exit) function will close the repl


or alt+f4 maybe? I'm more a windows guy...


(exit) didn't work for some reason...


i just killed java


(exit) is an nrepl feature


control-d makes the repl process stop


(System/exit 0) makes the vm gracefully exit


control-c will also make the repl stop, and shut down the vm, unless you set up a signal handler like nrepl does


oh thanks, I'll just add my own exit function that calls (System/exit 0) so the users can exit easily


that's the secret behind the interruptible-eval function @dpsutton linked to actually - in the big picture it's part of machinery that links a thread you can kill to a signal handler to kill that thread instead of your vm


figures, I always use nrepl, so didn't even realize that.


something I literally used today at work: $ env $(grep -v '#' .env) rlwrap java -cp $(cat class-path) clojure.main - the class-path file was generated via a previous run of lein with-profile +repl cp


this gives me a repl with all the same definitions and config as my lein / nrepl but without any leiningen or nrepl code running, just clojure.main plus my own code I explicitly run (all this done in order to have a cleaner set of stack traces for a tricky stalling issue)


turned out I was eagerly consuming a lazy-seq backed by a network stream that wasn't receiving input


with nrepl, 9/10 of the stack trace data from jstack was either leiningen or nrepl code / threads; removing that made finding the real problem much easier


of course I would have the same result out of the box if the project was using clj :D


the :author field is commonly used on namespaces. is it also used on vars? and why not :authors?


:author is common in clojure contrib namespaces, I am not sure it is common outside of those, it definitely isn't used in the closed source clojure code I've worked on


I suspect it is :author instead of :authors, because as a feature it wasn't really designed, someone thought "oh, namespaces can have metadata, neat, I'll attach some" and they just picked :author, and others just copied it along


:author in clojure contrib is likely from back when contrib was in svn as a single repo, so without it it was hard to figure out who "owned" a given source file


git does a better job of tracking that sort of thing


:author also occurs quite a few times in clojure itself


apparently its use did not catch on like wildfire


my guess is the usage in clojure itself fall in to two camps: projects that moved from contrib in to core (I think this is just clojure.test) and places where stu came along and added it, which I dunno if he was inspired by the usage in contrib, or contrib was inspired by him there


I've never really found a usecase for derive with multimethods


Has anyone used the whole keyword hierarchy thing for real?


I feel like there is some pattern I am missing


@emccue the same case as concrete inheritance in eg. java, except not only do you define where implementations are derived from, but also the derivation rules on a method-by-method basis


I've never found it useful in practice myself

hiredman22:07:06 appears to be the first :author tag in contrib, looks like it was added for the autodoc tool that is used to generate documentation


so it exists for a tool that is used to generate docs for


@noisesmith yeah but with concrete inheritance in java you maintain method compatability or are ostensibly guaranteed a subset of fields/slots


The whole mechanism is more general than that


right - it's not a similar mechanism, but has some of the same justifications / use cases


it's the only real form of inheritance clojure offers beyond mucky stuff in gen-class


(and the weird/buggy proxy-super)