Fork me on GitHub
Chris Bailey05:01:57

Trying to create a multimethod with implementations that have multiple arity, but can’t quite get it. Something like this:

(defmulti fixture identity)

(defmethod fixture :user
  ([_] (fixture :user {}))
  ([_ attrs] (create-user (merge {:name "Chris" :email ""} attrs))))

(fixture :user)
(fixture :user {:name "Fred"})

Chris Bailey05:01:47

The (fixture :user {:name "Fred"}) version works, but I get an ArityException on (fixture :user)


@chris.bailey The despatch function needs to accept the same arities as you want the defmethod to support. identity only accepts one argument.

Chris Bailey05:01:21

ok, I also tried it with fn [kind & args] kind, but same issue (sorry, newb on this, so I think I’m missing something maybe obvious?)

Chris Bailey05:01:22

I tried making the dispatch a multi-arity method too, with no luck, but I may not be implementing the actual dispatch function correctly either?


Like this:

(defmulti fixture (fn [kind & args] kind))

Chris Bailey05:01:09

hmm, ya, that’s what I had/have, and I still get the artityException when I do (fixture :user)


You probably need to restart the REPL. Multimethods can't just be redefined I think...


(I haven't used them much in the REPL but ran into strange behavior just now trying to redefine an example to try it out)

Chris Bailey05:01:10

oh, snap! restarting the repl fixed!

Chris Bailey05:01:19

oy, thank you!

Chris Bailey05:01:42

REPL restarts (when needed) are def something I’m learning/finding out about 😕


I'm sure there is a way to redefine multimethods without restarting the REPL... I've just never needed to figure it out 😐


you can probably ns-unmap the previous definition

Chris Bailey05:01:56

nah, tis totally fine, small frequency, so I just need to beware of it in the future


but you also need to re-eval all the defmethod forms too


Ah, looking at the definition of defmulti, it only defines the function if it doesn't already exist...


So you can do

(def fixture nil)
and then defmulti will work


@chris.bailey That'll save some pain in future -- just def it to nil and then do defmulti (and defmethod) again!

Chris Bailey06:01:40

awesome, thanks!


the easy way to rebind a defmulti is (def fixture nil) before reloading the defmulti


defmulti refuses to overwrite a defmulti, but def doesn't care, and defmulti will overwrite a def


IIRC, (defn dispatch-fn [kind & args] kind) (defmulti fixture #'dispatch-fn) should also be reloadable.


oh, yeah, that should work


but it would be sad to see all the defmultis obfuscated like that


Yeah, it's not optimal.

Nick Stares14:01:46

why is ['(1 2 3)] different from (vec '(1 2 3))?


vec turns a collection into a vector, while in the first example you have a list inside a vector


the first example would be equivalent to (vector (list 1 2 3))


probably that's the source of your confusion: vector != vec


I think the first is taken like a vector from 1 element (`(1 2 3)`), in the second it's vector of three elements because '(1 2 3) is taken as list

Nick Stares14:01:45

ah did not realize that vector != vec. thanks


Howdy folks. I have been trying to get datomic pro to work locally. I started the peer-server and added the dependency to my project. When I start the repl and try to issue the require command, I get an error: "CompilerException java.lang.RuntimeException: Unable to resolve symbol: halt-when in this context, compiling:(datomic/client/api.clj:57:11)" Any thoughts?


halt-when was added with clojure maybe related to clj version


I am using clojure 1.8


it seems odd that you seem to be compiling datomic's code instead of simply using the jar...but I never used peer server


maybe execute lein deps :tree and see what version of clj does the library require


you may need to use a version that supports clj 1.8, or upgrade to 1.9


Hey guys, any recommendations regarding choosing either a database or some sort of construct to persist 2 files (or collections) prone to application state mutation?


IMHO treating a thing outside process (inside a storage engine) as being a "collection" is asking for trouble - treat it as an external source of information with all that entails because it has failure modes and gotchas that collections never have


even though said external source of information goes through a lot of mutation?


I've had great luck with using kafka channels to stream events that represent status updates - then every consumer can replay the same stream and achieve the same state




because clojure collections are immutable


external storage can't be


at first, to keep it ultra simple I was thinking of swapping atoms


might definitely not be the best approach


oh - I assumed you meant something outside the vm, shared across runtimes or servers


atoms work great if you don't need a guarantee that the state persists between servers or restarts, I might have misunderstood your question


oh, cool! Yea I'm assuming only a single instance with a single source of truth (which would be these 2 collections and their state thats constantly shifting)


I could go for a database approach but that might be overkill


right - but still I'd suggest adjusting the mental model - in clojure collections never change, the container i nthe future might hold a different collection though


an atom synchronizes changes to a container, that change usually means putting a different collection inside - each of those collections is immutable


I see, thank you very much for the insights!


I'll dig deeper, might end up going this way though


I like to write functions using the “named parameters” trick like so:

(defn labeled-input
  [& {:keys [name class type on-cancel focus?]}] ...
Some of these are optional and some are not. I was hoping to use spec (or some other library) to check to ensure that I’ve always specified the mandatory parameters and to throw an error if something unexpected is passed. I can’t figure out how to get spec to do this since it seems focused on positional parameters. Are there any libraries out there that help with this?


@justinlee I haven't done it before, but I have seen keys* mentioned when such things are asked about.


if you had an :as clause in the map couldn't you spec the thing that binds to it?


Search for keys* (with the asterisk after the "s") on this page:


@andy.fingerhut nice! thanks. i read that whole page and didn’t register that.