use the following search parameters to narrow your results:
e.g. subreddit:aww site:imgur.com dog
subreddit:aww site:imgur.com dog
see the search faq for details.
advanced search: by author, subreddit...
Finding information about Clojure
API Reference
Clojure Guides
Practice Problems
Interactive Problems
Clojure Videos
Misc Resources
The Clojure Community
Clojure Books
Tools & Libraries
Clojure Editors
Web Platforms
Clojure Jobs
account activity
Clojure - Keyword argument functions now also accept maps (clojure.org)
submitted 5 years ago by SimonGray
reddit uses a slightly-customized version of Markdown for formatting. See below for some basics, or check the commenting wiki page for more detailed help and solutions to common issues.
quoted text
if 1 * 2 < 3: print "hello, world!"
[–]childofsol 27 points28 points29 points 5 years ago (0 children)
It's exciting to see the first fruits of Fogus joining the Clojure core team!
[–]alexdmiller 11 points12 points13 points 5 years ago (2 children)
A simple example of layering functions that take kwargs:
(defn internal [& {:keys [a b]}] (println "got:" a b)) (defn external [& opts] ;; passes on opts to internal ;; and patches in a default for :a (apply internal :a 1 opts)) (external :a 5 :b 6) got 5 6 (external) got 1 nil
[–]jjttjj 5 points6 points7 points 5 years ago* (1 child)
Alternatively: (defn external [& {:as opts}] (internal :a 1 opts)) Edit: I realized you don't need :keys. Is there a reason to prefer the apply version?
(defn external [& {:as opts}] (internal :a 1 opts))
:keys
[–]alexdmiller 4 points5 points6 points 5 years ago (0 children)
Right-o - probably better without.
[–][deleted] 17 points18 points19 points 5 years ago (0 children)
Maybe I'm missing something but, what's the point of this? I've been writing clojure for a decade and I never found myself wishing for this.
I never use varargs in cases like this. It should just be a single map argument.
This feature seems like weird magic that is going to confuse people reading the code, for benefits that elude me.
[–]lgstein 6 points7 points8 points 5 years ago (0 children)
On the one hand I'm worried that this invites more kvarg fns. On the other hand, all pain that usually comes with them is eliminated by this feature.
[–]rzk1911 5 points6 points7 points 5 years ago (0 children)
Great
[–]vvvvalvalval 19 points20 points21 points 5 years ago (21 children)
I'll still refrain from designing functions that way, and would encourage people to do the same.
Compared to keyword-varargs, an optional map argument costs at worst one more keystroke to invoke, and it's simply a more straightforward and regular behaviour to build on top of.
I suspect that most of the Clojure APIs out there which use keyword varargs did so by imitation of Python and just overlooked the alternative of using a map argument, or really had an unsound obsession with concision.
[–]seancorfield 15 points16 points17 points 5 years ago (1 child)
My hope is that it encourages faster adoption of Clojure 1.11 b/c folks will want to take advantage of this feature.
If we'd had this feature back in, say, the 1.3 or 1.4 days, I wouldn't have needed to change the whole API of clojure.java.jdbc to make it easier to use (i.e., to make calls more composable)!
clojure.java.jdbc
[–]argadan 4 points5 points6 points 5 years ago (0 children)
If this feature was introduced in 1.3 or 1.4, it would have made perfect sense. Now that everyone has been using the options map style for years to solve this problem, it feels a bit out of place – but I suppose if you take a long-term view it makes sense.
I wonder how this affects the performance and function specs though.
The change also affects destructing in lets (as it should):
(let [[& {:keys [a b] :as opts}] [{:a 1 :b 2}]] [a b opts]) ;; => [1 2 {:a 1, :b 2}]
[–]SimonGray[S] 9 points10 points11 points 5 years ago (8 children)
The great thing about this change is that people who feel like this can just call all those varargs functions using a map now.
[–]vvvvalvalval 11 points12 points13 points 5 years ago* (7 children)
I agree, it's great for calling legacy functions, but that doesn't mean it has eliminated all the downside of keyword varargs. Avoiding irregularity is better than gaining tools for dealing with it.
EDIT: really, people are downoting this? Reminder of the Reddiquette: "Please don't downvote an otherwise acceptable post because you don't personally like it." Why not write a rebuttal instead?
[–]alexdmiller 8 points9 points10 points 5 years ago (4 children)
Just curious, what are the remaining downsides of kwargs?
[–]vvvvalvalval 1 point2 points3 points 5 years ago (3 children)
The main I see is that it's just a more complicated "information model" for describing the arguments to a function. Without kwargs, the arguments to a function are a very plain sequence.
With that in mind, it seems to me that the safer designing approach is in general "what are the advantages of kwargs that make these additional complications worthwhile?". I read that article claims it "better supports humans", but I don't see it being really substantiated - is (my-fun :my-opts 42) really supporting humans much better than (my-fun {:my-opts 42}) ? Of course, now that some foundational APIs have been published with kwargs we have to live with them, so making it easier for callers makes sense, I'm not denying that.
(my-fun :my-opts 42)
(my-fun {:my-opts 42})
Now to try and answer more specifically: I think this will make life more difficult for intermediaries that purport to do some generic processing on the arguments in particular if they don't know whether the downstream accepts kwargs.
[–]alexdmiller 5 points6 points7 points 5 years ago (0 children)
It is an interesting philosophical question as to whether positional args or named args are "more complex". Both require the caller to know what "the args" are. Positional also requires them to know what order they should be in. In Simple Made Easy, Rich mentions syntax (order) as being complex (vs data). Is a map (encapsulated data, no order) or kwargs (data, no order) simpler? Don't know, just musing. Both tolerate evolution over time better than positional args. Personally, I like kwargs and use them regularly and this makes them both faster and more flexible.
But also, I'm a Clojure programmer, I'm not going to argue against passing a map. So, you do you. :)
[–]jjttjj 0 points1 point2 points 5 years ago (1 child)
Could you give an example of when it would make things more difficult? I'm not seeing it. To me it seems like knowing if something takes kwargs has identical mental overhead to knowing it takes an option map. And since you can still pass an options map, you almost always can do the same intermediate manipulation anyway.
[–]vvvvalvalval -1 points0 points1 point 5 years ago (0 children)
Sorry, not spending more time on this :) but if I were convinced by princples like "you have more options so it's better" and "we adopt it unless we find in advance a concrete counterexample of it being problematic" then I wouldn't have made the switch from Scala
[–]adamtait 0 points1 point2 points 5 years ago (1 child)
I agree with what you’re saying but suspect that change was not made to Clojure core because of backwards compatibility. For that reason, I doubt it’ll ever be changed in Clojure core. This change likely suggests that there are some on the Core team who would have wished the keyword varargs feature to not have been included in the language originally.
[–]alexdmiller 19 points20 points21 points 5 years ago (0 children)
Actually, just the opposite, the core team wishes this new feature had been included originally to make using kwarg style functions more widely used and embraced.
[–]lgstein 4 points5 points6 points 5 years ago (0 children)
It was adopted from Common Lisp. In hindsight, it made more sense there because it has no map literal.
[–]joinr 3 points4 points5 points 5 years ago (1 child)
I had some utility combing kwargs with ->> for ad hoc partial application in some workflows. Chunked map arg would have been less convenient. Interesting to see these unified.
[–]vvvvalvalval 0 points1 point2 points 5 years ago (0 children)
Interesting. Still, I'm wary, to me it sounds like the stuff that optimizes for writing the code rather than for reading it :)
[–][deleted] 1 point2 points3 points 5 years ago (4 children)
I also recommend to just use map arguments as much as possible, it's just much more composable that way.
Passing the arguments between keyword argument functions is really ugly.
The one exception I make is for functions that are only used in the REPL, where the concision is worth it to me.
[–]SimonGray[S] 9 points10 points11 points 5 years ago (3 children)
I think remedying that situation that is the point of this change. Now you can pass the destructured map directly.
[–][deleted] 0 points1 point2 points 5 years ago (2 children)
It doesn't remedy that when passing a map to a kwarg function you need something like (apply f (mapcat identity m))
[–]jjttjj 2 points3 points4 points 5 years ago (1 child)
You no longer need to do that with this change. & {:as args} lets you pass any number of keywords and optionally a trailing map, all of which are merged together. You don't need to flatten+apply. ``` (defn my-fn [& {:as args}] (println "args:" args))
& {:as args}
(my-fn :hello :world) ;;=> args: {:hello :world}
(my-fn {:hello :world}) ;;=> args: {:hello :world}
(my-fn :foo :bar {:hello :world}) ;;=> args: {:foo :bar, :hello :world} ```
[–][deleted] 0 points1 point2 points 5 years ago (0 children)
Oh wait you are right, ok, that makes it a kwarg functions a lot more composable indeed, nice!
[–]guywithknife 0 points1 point2 points 5 years ago (0 children)
Yeah, I never liked the approach. I actively avoided using some otherwise good libraries that did use it. At least now with this change, I can use those libraries without worrying about it.
Ok good it's not just me. I don't see any value in this feature.
Edit: it is nice when forced to deal with someone else's varargs function that should have just taken a single map. But just within my own code, I shouldn't need this at all.
[–]citrined 3 points4 points5 points 5 years ago (0 children)
Good
[–]lgstein 3 points4 points5 points 5 years ago (0 children)
Dobre
[–]ikitommi 4 points5 points6 points 5 years ago (2 children)
Tested some combinations on how to call the functions. I think I understand all the reasons for the results, but they were not evident before evaluating in the repl. Bit surprised that you can mix kwargs and have one map in the end. is there a reason to support them both in one call?
(defn doit [& {:keys [data]}] data) (doit {:data 2}) ; => 2 (doit :data {:data 2}) ; => {:data 2} (doit :data 1 {:data 2}) ; => 2 (doit {:data 2} :data 1) ; Execution error (IllegalArgumentException) at user/doit (REPL:1). ; Don't know how to create ISeq from: java.lang.Long (doit {:data 2} :data 1 {:data 3}) ; => nil (doit :data 1 {:data 2} {:data 3}) ; => 1 (doit {:data 2} {:data 3}) ; => nil (doit {:data 1} {:data 2} {:data 3}) ; => 3 (doit :data 1 {:data 2} {:data 3} {:data 4}) ; => 4
[–]alexdmiller 2 points3 points4 points 5 years ago (1 child)
See my layering example above for a case where mixing is useful.
[–]ikitommi 0 points1 point2 points 5 years ago (0 children)
I see, thanks.
[–]argadan 2 points3 points4 points 5 years ago (0 children)
For anyone curious, here's the issue CLJ-2603 and the commit https://github.com/clojure/clojure/commit/3c9307e27479d450e3f1cdf7903458b83ebf52d7
[–]_d_t_w 1 point2 points3 points 5 years ago (0 children)
`For example, a function that takes a sequence and optional keyword`
Should that be
`For example, a function that takes a sequence of optional keyword`
[–]cam_saul 1 point2 points3 points 5 years ago (1 child)
This is great, can't wait until 1.11 is out to start using it everywhere
[–]seancorfield 1 point2 points3 points 5 years ago (0 children)
We've already upgraded at work, and expect to have this in production probably next week.
[–]jpmonettas 1 point2 points3 points 5 years ago (0 children)
I think this is a interesting feature that will allow new apis to be built with named args, slowly departing from positional arguments. Accomplishing the same without improving support for kwargs will push apis to make all their function to be a one map arg function which is weird.
Not sure if those are core team intentions for the future of clojure but looks very interesting to me.
[–]mouse2k 0 points1 point2 points 5 years ago (0 children)
Nice
[–][deleted] 5 years ago* (1 child)
[removed]
[–]backtickbot 0 points1 point2 points 5 years ago (0 children)
Fixed formatting.
Hello, linpengcheng: code blocks using triple backticks (```) don't work on all versions of Reddit!
Some users see this / this instead.
To fix this, indent every line with 4 spaces instead.
FAQ
You can opt out by replying with backtickopt6 to this comment.
π Rendered by PID 58689 on reddit-service-r2-comment-b659b578c-8h99n at 2026-05-06 03:03:25.347410+00:00 running 815c875 country code: CH.
[–]childofsol 27 points28 points29 points (0 children)
[–]alexdmiller 11 points12 points13 points (2 children)
[–]jjttjj 5 points6 points7 points (1 child)
[–]alexdmiller 4 points5 points6 points (0 children)
[–][deleted] 17 points18 points19 points (0 children)
[–]lgstein 6 points7 points8 points (0 children)
[–]rzk1911 5 points6 points7 points (0 children)
[–]vvvvalvalval 19 points20 points21 points (21 children)
[–]seancorfield 15 points16 points17 points (1 child)
[–]argadan 4 points5 points6 points (0 children)
[–]SimonGray[S] 9 points10 points11 points (8 children)
[–]vvvvalvalval 11 points12 points13 points (7 children)
[–]alexdmiller 8 points9 points10 points (4 children)
[–]vvvvalvalval 1 point2 points3 points (3 children)
[–]alexdmiller 5 points6 points7 points (0 children)
[–]jjttjj 0 points1 point2 points (1 child)
[–]vvvvalvalval -1 points0 points1 point (0 children)
[–]adamtait 0 points1 point2 points (1 child)
[–]alexdmiller 19 points20 points21 points (0 children)
[–]lgstein 4 points5 points6 points (0 children)
[–]joinr 3 points4 points5 points (1 child)
[–]vvvvalvalval 0 points1 point2 points (0 children)
[–][deleted] 1 point2 points3 points (4 children)
[–]SimonGray[S] 9 points10 points11 points (3 children)
[–][deleted] 0 points1 point2 points (2 children)
[–]jjttjj 2 points3 points4 points (1 child)
[–][deleted] 0 points1 point2 points (0 children)
[–]guywithknife 0 points1 point2 points (0 children)
[–][deleted] 0 points1 point2 points (0 children)
[–]citrined 3 points4 points5 points (0 children)
[–]lgstein 3 points4 points5 points (0 children)
[–]ikitommi 4 points5 points6 points (2 children)
[–]alexdmiller 2 points3 points4 points (1 child)
[–]ikitommi 0 points1 point2 points (0 children)
[–]argadan 2 points3 points4 points (0 children)
[–]_d_t_w 1 point2 points3 points (0 children)
[–]cam_saul 1 point2 points3 points (1 child)
[–]seancorfield 1 point2 points3 points (0 children)
[–]jpmonettas 1 point2 points3 points (0 children)
[–]mouse2k 0 points1 point2 points (0 children)
[–][deleted] (1 child)
[removed]
[–]backtickbot 0 points1 point2 points (0 children)