I think it would because in that case you'd just pass your arg map straight
through rather than having to reconstruct it. So if you weren't passed :y
in g (in Mark's example), g wouldn't pass it on to f. By forcing the
reconstruction of the map from explicit args, you're forced to use the
value (incorrectly) destructured in g. Mark could work around it in his
example by using (apply f (mapcat identity m)) in g, but it's far from
intuitive.


On 1 May 2014 15:04, Jim Crossley <j...@crossleys.org> wrote:

> Unless I'm missing something subtle, all of your points would hold if you
> removed the & in your argument vector to turn your kwargs into an explicit
> map, wouldn't they? One advantage is you'd be able to (apply f [m]), but
> I'm not sure the :or logic would be any less troublesome.
>
>
> On Wed, Apr 30, 2014 at 8:06 PM, Mark Engelberg 
> <mark.engelb...@gmail.com>wrote:
>
>> Here's the thing I can't stand about keyword args:
>>
>> Let's start off with a simple function that looks for keys x and y, and
>> if either is missing,
>> replaces the value with 1 or 2 respectively.
>>
>> (defn f [& {:keys [x y] :or {x 1 y 2}}]
>>   [x y])
>>
>> => (f :x 10)
>> [10 2]
>>
>> So far, so good.
>>
>> Now, let's do an extremely simple test of composability.  Let's define a
>> function g that destructures the keyword args, and if a certain keyword
>> :call-f is set, then we're just going to turn around and call f, passing
>> all the keyword args along to f.
>>
>> (defn g [& {call-f :call-f :as m}]
>>   (when call-f
>>     (apply f m)))
>>
>> => (g :call-f true :x 10)
>> [1 2]
>>
>> What?  Oh right, you can't apply the function f to the map m.  This
>> doesn't work.  If we want to "apply" f, we somehow need to apply it to a
>> sequence of alternating keys and values, not a map.
>>
>> Take 2:
>>
>> (defn g [& {:keys [call-f x y] :as m}]
>>   (when call-f
>>     (f :x x :y y)))
>>
>> OK, so this time we try to workaround things by explicitly calling out
>> the names of all the keywords we want to capture and pass along.  It's
>> ugly, and doesn't seem to scale well to situations where you have an
>> unknown but at first glance, it seems to work:
>>
>> => (g :call-f true :x 80 :y 20)
>> [80 20]
>>
>> Or does it?
>>
>> => (g :call-f true :x 10)
>> [10 nil]
>>
>> What is going on here?  Why is the answer coming out that :y is nil, when
>> function f explicitly uses :or to have :y default to 2?
>>
>> The answer is that :or doesn't do what you think it does.  The word "or"
>> implies that it substitutes the default value of :y any time the
>> destructured :y is nil or false.  But that's not how it really works.  It
>> doesn't destructure and then test against nil; instead the :or map only
>> kicks in when :y is actually missing as a key of the map.
>>
>> This means that in g, when we actively destructured :y, it got set to a
>> nil, and then that got passed along to f.  f's :or map didn't kick in
>> because :y was set to nil, not absent.
>>
>> This is awful.  You can't pass through keyword arguments to other
>> functions without explicitly destructuring them, and if you destructure
>> them and pass them along explicitly, nil values aren't picked up as absent
>> values, so the :or default maps don't work properly.
>>
>> To put it simply, keyword args are bad news for composability.
>>
>> It's a shame, and I'd love to see this improved (rather than just having
>> the community give up on keyword arguments).
>>
>> --
>> You received this message because you are subscribed to the Google
>> Groups "Clojure" group.
>> To post to this group, send email to clojure@googlegroups.com
>> Note that posts from new members are moderated - please be patient with
>> your first post.
>> To unsubscribe from this group, send email to
>> clojure+unsubscr...@googlegroups.com
>> For more options, visit this group at
>> http://groups.google.com/group/clojure?hl=en
>> ---
>> You received this message because you are subscribed to the Google Groups
>> "Clojure" group.
>> To unsubscribe from this group and stop receiving emails from it, send an
>> email to clojure+unsubscr...@googlegroups.com.
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>  --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to