What causes "java.lang.IllegalArgumentException: No value supplied for key"? - clojure

I have code of the shape
(let [{foo :foo} (make-foo)] ...)
This code occasionally emits a java.lang.IllegalArgumentException: No value supplied for key: {:foo "foo" :other "other"}.
I've seen Clojure : "java.lang.IllegalArgumentException: No value supplied for key:" when I changed require, however I haven't changed the require of my program since it last worked.
What are the possible causes for the "No value supplied for key" exception?

This happens when you try to create a map from an odd number of key/value entries: the last key is missing a value. One way this can happen is when destructuring a non-map collection but treating it as a map, since this implicitly creates a map from the collection for you before destructuring it as an ordinary map.

Related

Is there a canonical way to name variables that would otherwise cause name collisions?

Say I'd like to name a variable seq, referring to some kind of sequence.
But seq is already a function in clojure.core, so if I try to name my variable seq, the existing meaning of seq will be overwritten.
Is there a canonical way in Clojure to name a variable that would otherwise have a name collision with a default variable?
(e.g., in this case, my-seq could be used, but I don't know whether that would be standard as far as style goes)
There is no "standard" way of naming things (see the quote and the related joke).
If it is a function of only one thing, I often just name it arg. Sometimes, people use abbreviations like x for a single thing and xs for a sequence, list, or vector of things.
For small code fragments, abbreviating to the first letter of the "long" name is often sufficient. For example, when looping over a map, each MapEntry is often accessed as:
(for [[k v] some-map] ; destructure key/val into k & v
...)
Other times, you may prefix it with a letter like aseq or the-seq.
Another trick I often use is to add a descriptive suffix like
name-in
name-full
name-first
(yes, there is a Clojure function name).
Note that if you did name it seq, you would create a local variable that shadowed the clojure.core/seq function (it would not be "overwritten"). I often just "let it slide" if the scope of the shadowing is limited and the name in question is clear & appropriate (key and val are often victims of this practice). For name, I would also probably just ignore the shadowing of clojure.core/name, since I rarely use that function.
Note that you can shadow your own local variables. This is often handy to coerce data in to a specific format:
(defn foo
[items]
; assume we need a sorted vector with no duplicates
(let [items (vec (sort (set (items))))]
...))
By shadowing the original items argument, we ensure the data is in the desired form without needing to come up with two good, descriptive names. When this technique doesn't quite fit, I often fall back to the suffix trick and just name them items-in and items or similar.
Sometimes a suffix indicating type is valuable, when multiple representations are required. For example:
items
items-set
items-vec
type-str
type-kw
type-sym
There are many other possibilities. The main point is to make it clear to the reader what is happening, and to avoid creating booby traps for the unaware.
When in doubt, add a few more letters so it is obvious to a new reader what is happening.
You won't override clojure.core/seq. You will be simply shadowing the var seq with your local bindings or vars. One can always use fully qualified name to use core seq.
Example:
;; shadow core seq
(def seq [1 2 3])
WARNING: seq already refers to: #'clojure.core/seq in namespace: user, being replaced by: #'user/seq
=> #'user/seq
;; local binding
(defn print-something [seq]
(prn seq)
(prn (var seq)))
=> #'user/print-something
;; use fully qualified name
(clojure.core/seq "abc")
=> (\a \b \c)
(print-something "a")
"a"
#'user/seq
=> nil
(prn seq)
[1 2 3]
=> nil
(var seq)
=> #'user/seq
But, its not a clean practice to shadow clojure.core vars as it might lead to buggy code. It does more harm than good if any. I usually name vars based on code context, like employee-id-seq, url-seq etc. Sometimes, it okay to use short names like x or s if usage scope is limited. You can also see clojure.core implementation to find more examples.
A good guide: https://github.com/bbatsov/clojure-style-guide#idiomatic-names
I also recommend clj-kondo plugin

Error while defining map in clojure

I am new clojure and am not able to understand exact issue while running this code
(def my-map {name "Srini" empid "10000"})
Receving this error:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: empid in this context, compiling:(/Users/srini/Downloads/clojureexample/my-stugg/src/my_stugg/corecomponents.clj:95:1)
(def my-map {name "Srini" :empid "10000"})
Running successfully.
What wrong I am doing in the first line?
(def my-map {name "Srini" empid "10000"})
Clojure is trying to resolve empid and can't, so it returns an error.
Clojure allows you to define maps with most anything as a key. This includes keywords and strings, which are very common, but also symbols, functions, numbers, data structures such as vectors and other maps, and more.
Your example contains one valid mapping, that is, the function bound to name which maps to the string "Srini". However, the other mapping is invalid because empid is not bound to anything.
The most common case is to use keywords for your keys, which have a particular advantage of allowing the values to be accessed via the keywords in a safe (non-NullPointerException-causing) way:
(:name {:name "Srini" :empid 10000})
=> "Srini"
So, while there may be a case where you'd want to map a function to something, this is clearly not the right way for you here. (as an aside, strings as keywords are particularly useful when reading from a file or database where the data is already a string and there's no advantage to converting to and from a keyword.
You probably want to change your keys to keywords. In Clojure keywords are written with a colon in front of a string, but you don't need the quotes (as long as your keyword has no spaces in it, but let's not get complicated).
I recommend starting simply:
(def my-map {:name "george"})
This will create a map with a single key and value in it.
If you want to use let, do it like so:
(let [my-map {:name "george"}] my-map)
Update: Hm you seemed to have changed your question a fair bit! I still really recommend starting simply.
name is already defined as a function in clojure (it gets the string version of a symbol or keyword), so you shoudln't use that. Use :name if you want to create a key, unless you want to shadow the name "name" in a let binding, but that's nothing to do with keys in maps.
I feel like perhaps you need to learn the basics of maps and let before you go crazy with examples. Stick to simple things, and make sure your keys are not symbols.

Clojure basics: counting frequencies

I am learning Clojure, and I saw this bit of code online:
(count (filter #{42} coll))
And it does, as stated, count occurrences of the number 42 in coll. Is #{42} a function? The Clojure documentation on filter says that it should be, since the snippet works as advertised. I just have no idea how it works. If someone could clarify this for me, that would be great. My own solution to this same thing would have been:
(count (filter #(= %1 42) coll))
How come my filtering function has parenthesis and the snippet I found online has curly braces around the filtering function (#(...) vs. #{...})?
=> #{42}
#{42}
Defines a set...
=> (type #{42})
clojure.lang.PersistentHashSet
=> (supers (type #{42}))
#{clojure.lang.IHashEq java.lang.Object clojure.lang.IFn ...}
Interestingly the set implements IFn so you can treat it like a function. The behaviour of the function is "if this item exists in the set, return it".
=> (#{2 3} 3)
3
=> (#{2 3} 4)
nil
Other collections such as map and vector stand in as functions in a similar fashion, retrieving by key or index as appropriate.
=> ({:x 23 :y 26} :y)
26
=> ([5 7 9] 1)
7
Sweet, no? :-)
Yes, #{42} is a function,
because it's a set, and sets, amongst other capabilities, are
functions: they implement the clojure.lang.IFn interface.
Applied to any value in the set, they return it; applied to anything
else, they return nil.
So #{42} tests whether its argument is 42 (only nil and false are false, remember).
The Clojure way is to make everything a function that might usefully be one:
Sets work as a test for membership.
Maps work as key lookup.
Vectors work as index lookup.
Keywords work as lookup in the map argument.
This
often saves you a get,
allows you, as in the question, to pass naked data structures to higher order functions
such as filter and map, and
in the case of keywords, allows you to move transparently between maps and records
for holding your data.

Clojure get nested map value

So I'm used to having a nested array or map of settings in my applications. I tried setting one up in Clojure like this:
(def gridSettings
{:width 50
:height 50
:ground {:variations 25}
:water {:variations 25}
})
And I wondered if you know of a good way of retrieving a nested value? I tried writing
(:variations (:ground gridSettings))
Which works, but it's backwords and rather cumbersome, especially if I add a few levels.
That's what get-in does:
(get-in gridSettings [:ground :variations])
From the docstring:
clojure.core/get-in
([m ks] [m ks not-found])
Returns the value in a nested associative structure,
where ks is a sequence of keys. Returns nil if the key
is not present, or the not-found value if supplied.
You can use the thread-first macro:
(-> gridSettings :ground :variations)
I prefer -> over get-in except for two special cases:
When the keys are an arbitrary sequence determined at runtime.
When supplying a not-found value is useful.
Apart from what other answers has mentioned (get-in and -> macro), sometimes you want to fetch multiple values from a map (nested or not), in those cases de-structuring can be really helpful
(let [{{gv :variations} :ground
{wv :variations} :water} gridSettings]
[gv wv])
Maps are partial functions (as in not total). Thus, one can simply apply them as functions. Based on the map from the question:
(gridSettings :ground)
;=> {:variations 25}
The result is a map. So, it can be applied again, which results in a very similar (but not backwards) "syntax" as proposed in the question:
((gridSettings :ground) :variations)
;=>25

How do I get core clojure functions to work with my defrecords

I have a defrecord called a bag. It behaves like a list of item to count. This is sometimes called a frequency or a census. I want to be able to do the following
(def b (bag/create [:k 1 :k2 3])
(keys bag)
=> (:k :k1)
I tried the following:
(defrecord MapBag [state]
Bag
(put-n [self item n]
(let [new-n (+ n (count self item))]
(MapBag. (assoc state item new-n))))
;... some stuff
java.util.Map
(getKeys [self] (keys state)) ;TODO TEST
Object
(toString [self]
(str ("Bag: " (:state self)))))
When I try to require it in a repl I get:
java.lang.ClassFormatError: Duplicate interface name in class file compile__stub/techne/bag/MapBag (bag.clj:12)
What is going on? How do I get a keys function on my bag? Also am I going about this the correct way by assuming clojure's keys function eventually calls getKeys on the map that is its argument?
Defrecord automatically makes sure that any record it defines participates in the ipersistentmap interface. So you can call keys on it without doing anything.
So you can define a record, and instantiate and call keys like this:
user> (defrecord rec [k1 k2])
user.rec
user> (def a-rec (rec. 1 2))
#'user/a-rec
user> (keys a-rec)
(:k1 :k2)
Your error message indicates that one of your declarations is duplicating an interface that defrecord gives you for free. I think it might actually be both.
Is there some reason why you cant just use a plain vanilla map for your purposes? With clojure, you often want to use plain vanilla data structures when you can.
Edit: if for whatever reason you don't want the ipersistentmap included, look into deftype.
Rob's answer is of course correct; I'm posting this one in response to the OP's comment on it -- perhaps it might be helpful in implementing the required functionality with deftype.
I have once written an implementation of a "default map" for Clojure, which acts just like a regular map except it returns a fixed default value when asked about a key not present inside it. The code is in this Gist.
I'm not sure if it will suit your use case directly, although you can use it to do things like
user> (:earth (assoc (DefaultMap. 0 {}) :earth 8000000000))
8000000000
user> (:mars (assoc (DefaultMap. 0 {}) :earth 8000000000))
0
More importantly, it should give you an idea of what's involved in writing this sort of thing with deftype.
Then again, it's based on clojure.core/emit-defrecord, so you might look at that part of Clojure's sources instead... It's doing a lot of things which you won't have to (because it's a function for preparing macro expansions -- there's lots of syntax-quoting and the like inside it which you have to strip away from it to use the code directly), but it is certainly the highest quality source of information possible. Here's a direct link to that point in the source for the 1.2.0 release of Clojure.
Update:
One more thing I realised might be important. If you rely on a special map-like type for implementing this sort of thing, the client might merge it into a regular map and lose the "defaulting" functionality (and indeed any other special functionality) in the process. As long as the "map-likeness" illusion maintained by your type is complete enough for it to be used as a regular map, passed to Clojure's standard function etc., I think there might not be a way around that.
So, at some level the client will probably have to know that there's some "magic" involved; if they get correct answers to queries like (:mars {...}) (with no :mars in the {...}), they'll have to remember not to merge this into a regular map (merge-ing the other way around would work fine).