When do functions expecting maps silently return nil when passed a non-map argument? - exception

I'm a bit surprised to see some functions silently returning nil (or the default value you pass) when you pass something that is not a map where a map is expected.
Take first the following doc and example, which works as I expected:
user> (doc dissoc)
-------------------------
clojure.core/dissoc
([map] [map key] [map key & ks])
dissoc[iate]. Returns a new map of the same (hashed/sorted) type,
that does not contain a mapping for key(s).
The first argument to dissoc must be a map as per the doc, so here's what happens:
user> (dissoc {:a 1 :b 2} :b)
{:a 1}
It works fine, I passed a map. Let's pass something that is not a map to that function whose doc says the first argument should be a map:
user> (dissoc 1 :b)
ClassCastException java.lang.Long cannot be cast to clojure.lang.IPersistentMap clojure.lang.RT.dissoc (RT.java:758)
Fair enough, an exception is thrown at runtime and the issue is clear enough, this is the behavior I expected.
Let's now take another function:
user> (doc get)
-------------------------
clojure.core/get
([map key] [map key not-found])
Returns the value mapped to key, not-found or nil if key not present.
The first argument to get must be a map as per the doc and here's what happens:
user> (get {:a 1} :a)
1
So far so good. Let's pass something that is not a map to that function whose doc says the first argument should be a map:
user> (get 42 :a)
nil
No exception. No nothing. Just a silent "failure".
How comes one function throws an exception when you pass something that is not a map and not the other, although both functions' docs clearly state that the first argument must be a map?
Is there a "rule" to know when, in Clojure, you'll get either exceptions or nil or should I just expect that kind of stuff to be inconsistent?
As a side-question: would Clojure and Clojure programs "break" if, say, get was modified to throw an exception instead of silently returning nil when you don't pass a map where you're supposed to?

An exception should probably be thrown for a get on non-associative arguments as in your example:
(contains? 42 :a)
;=> IllegalArgumentException
(get 42 :a)
;=> nil ??
This is an open issue in Clojure's Issue Tracker. As stated in the issue description, the current behavior of returning a nil is most likely a bug and can obscure programming errors.

get is intended to work on all associative data structures. The language implementors could have chosen to check if the argument was associative, or made a white-list of all associative things that it could check, but instead it has a few special cases defined in clojure.lang.RT, and will also work on anything that implements Map or IPersistentSet or ILookup.
the code is not too hard to grok
Now, as to why it would silently return nil on something that implements none of these interfaces, this is an instance of a persistent Clojure design strategy of silently returning nil rather than failing. This decision definitely has tradeoffs, but it is a pervasive way Clojure does things.

Related

Clojure map returned by JDBC becomes null after inspection

I'm writing a simple URL shortener in Clojure, using Ring, Compojure, clojure.java.jdbc and MySQL.
I'm seeing a very strange issue where some inputs seem to randomly become null midway through a function, causing my checks to fail.
My code:
(defn redirect-handler [slug]
(if (not slug)
(response/bad-request "Must provide slug."))
(let [mapping (db/get-slug slug)]
;; this passes fine
(if mapping
(println (str mapping)))
;; this always calls the else case for some slugs, but not others
(if mapping
(response/redirect (:url mapping))
(do
(println "Not running. Mapping: " mapping)
(response/not-found (str "Slug not found: " slug))))))
For certain inputs, it always returns 404 with "Slug not found: ". Logs reveal very strange behaviour:
{:slug "eel", :url "eel.com"}
Not running. Mapping: nil
And the response is 404 with message Slug not found: eel.com - even stranger, since it seems to be returning the url instead of the slug in the response. It's almost as though the data is being modified midway through the function.
I have already confirmed the data in the database is correct.
My DB code:
(def mysql-db (edn/read-string (slurp "env.edn")))
(def query-slug-sql "SELECT * FROM urls WHERE slug = ?")
(defn get-slug [slug]
(first (j/query mysql-db [query-slug-sql slug])))
My HTTP routing code:
(defroutes app-routes
(GET "/:slug" [slug] (redirect-handler slug))
(GET "/" [] (response/not-found "Must provide slug."))
(POST "/create" [slug url] (create-handler slug url)))
(def app
(-> app-routes
(json/wrap-json-params)
(json/wrap-json-response)))
Any idea what is happening here?
I understand your confusion, because given the code you posted, a single call to redirect-handler can't possibly produce those log messages, no matter what value it receives as argument, and no matter what is returned by db/get-slug. Local variables just can't change value at all, and there's no single value in Clojure that goes from truthy to falsey, ever.
I can think of two explanations (maybe there are others):
The code you posted isn't the code that's running. Maybe you rewrote the function but didn't reload it, for example.
The log message isn't exclusively coming from redirect-handler. Maybe some other function prints the map on line one, and then the second line is the only thing printed by redirect-handler.

Handling errors with purity in Clojure?

I'm working on a game using the big-bang style of programming where one defines the entire state as a single data structure and manages state change by swapping against a single atom.
In a game we cannot trust data sent by the client thus the server has to anticipate the possibility that some moves will be invalid and guard against it. When one writes a function for swapping world state it can start out pure; however, one must consider the possibility of invalid requests. I believe to effect the unhappy path in idiomatic Clojure one simply throws exceptions. So now functions that might have been pure are infected with side-effecting exceptions. Perhaps this is as it has to be.
(try
(swap! world update-game) ;possible exception here!
(catch Exception e
(>! err-chan e))
My aim is to defer side-effects until the last possible moment. I've hardly forayed into Haskell land but I know the concept of the Either monad. When one considers the happy and unhappy path one understands there are always these 2 possibilities. This has me thinking that swap! by itself is insufficient since it ignores the unhappy path. Here's the spirt of the idea:
(swap-either! err-chan world update-game) ;update-game returns either monad
Has the Clojure community adopted any more functional approaches for handling exceptions?
I tend to take a couple different approaches in cases like this. If the state is being updated in a single location I tend to go with:
(try
(swap! world update-game) ;possible exception here!
(catch Exception e
(>! err-chan e)
world) ;; <--- return the world unchanged
or if it's set in lots of places ad a watcher that throws the exception back to the place where swap! was called and doesn't change the state:
user> (def a (atom 1))
#'user/a
user> (add-watch a :im-a-test (fn [_ _ _ new-state]
(if (even? new-state)
(throw (IllegalStateException. "I don't like even numbers")))))
#object[clojure.lang.Atom 0x5c1dc37e {:status :ready, :val 1}]
user> (swap! a + 2)
3
user> (swap! a + 3)
IllegalStateException I don't like even numbers user/eval108260/fn--108261 (form-init8563497779572341831.clj:2)

Embedded ECL Lisp error handling fetch default error string and possibly line number

Please see #7755661 first. I am using ECL and basically want to execute some code, trap any kind of condition that may occur and then continue execution, without prompting or entering the debugger. This is easy to achieve with the following handler-case macro:
(handler-case
(load "code.lisp") ; this may raise a condition
(error (condition)
(print condition))) ; this prints sth like #<a UNBOUND-VARIABLE>
My only problem is that I cannot find a generic way to print a more meaningful error for the user. Indeed my application is an HTTP server and the output goes to a web page. code.lisp is written by the user and it can raise any kind of condition, I do now want to list them all in my code. I would just like to print the same error message I see on the REPL when I do not use handler-case, but in the HTML page, e.g. for an "unbound variable" error, a string like "The variable VAR is unbound".
By inspecting a condition object of type UNBOUND-VARIABLE I see it has two slots: SI:REPORT-FUNCTION, which is a compiled function and SI:NAME, set to the name of the variable in this case. I guess SI:REPORT-FUNCTION could be what I need to invoke but how can I call it? If I try:
(handler-case foo (error (condition) (SI::REPORT-FUNCTION condition)))
it tells me that SI:REPORT-FUNCTION is undefined. SI or SYS in ECL is a package for functions and variables internal to the implementation, but I don't worry if my code is not portable, as long as it works.
BTW in other kinds of condition objects there are also other apparently useful slots for my purpose, named SI:FORMAT-CONTROL and SI:FORMAT-ARGUMENT, but I cannot access any of them from my code too.
I was looking for somethink alike to the getMessage() method of Java exception objects in Lisp, but none of my sources ever mentions something like that.
Moreover, is there any hope to be able to get the line number in code.lisp where the error occurred too? Without that it would be difficult for the user to locate the problem in his code.lisp source file. I would really want to provide this information and stopping at the first error is acceptable for me.
In Common Lisp when print escaping is disabled, the error message is printed.
CL-USER > (handler-case
a
(error (condition)
(write condition :escape nil)))
The variable A is unbound.
#<UNBOUND-VARIABLE 4020059743>
Note that PRINT binds *print-escape* to T.
Using PRINC works - it binds *print-escape* to NIL.
CL-USER > (handler-case
a
(error (condition)
(princ condition)))
The variable A is unbound.
#<UNBOUND-VARIABLE 4020175C0B>
This is described in CLHS 9.1.3 Printing Conditions.
Also note, when you have an object, which has a slot and the value of this slot is a function, then you need to get the slot value using the function SLOT-VALUE and then use FUNCALL or APPLY and call the function with the correct arguments.
If you have a condition of type simple-condition then it has a format-control and a format-argument information. This is described with an example how to use it for FORMAT in CLHS Function SIMPLE-CONDITION-FORMAT-CONTROL, SIMPLE-CONDITION-FORMAT-ARGUMENTS
My answer below is based on one I already gave at the ECL mailing list. Actually I would claim that this is not an embedding problem, but a Lisp one. You want to get some information at the file position of the form which caused the error. This is not attached to a condition because conditions happen independently of whether the form evaluated was interpreted, compiled or part of a function that is already installed in the Lisp image. In other words, it is up to you to know the position of the file which is being read and do some wrapping that adds the information.
The following is nonstandard and prone to change: ECL helps you by defining a variable ext::source-location when LOAD is used on a source file. This variable contains a CONS that should NEVER be changed or stored by the user, but you can get the file as (CAR EXT:*SOURCE-LOCATION*) and the file position as (CDR EXT:*SOURCE-LOCATION*). The plan is then to embed your LOAD form inside a HANDLER-BIND
(defparameter *error-message* nil)
(defparameter *error-tag* (cons))
(defun capture-error (condition)
(setf *error*
(format nil "At character ~S in file ~S an error was found:~%~A"
(cdr ext:*source-location*)
(car ext:*source-location*)
condition)))
(throw *error-tag* *error-message*))
(defun safely-load (file)
(handler-bind ((serious-condition #'capture-error))
(catch *error-tag*
(load file)
nil)))
(SAFELY-LOAD "myfile.lisp") will return either NIL or the formatted error.
In any case I strongly believe that relying on LOAD for this is doomed to fail. You should create your own version of LOAD, starting from this
(defun my-load (userfile)
(with-open-file (stream userfile :direction :input :external-format ....whateverformat...)
(loop for form = (read stream nil nil nil)
while form
do (eval-form-with-error-catching form))))
where EVAL-FORM-.... implements something like the code above. This function can be made more sophisticated and you may keep track of file positions, line numbers, etc. Your code will also be more portable this way.
So please, read the ANSI Spec and learn the language. The fact that you did not know how to print readably a condition and instead tried to play with ECL internals shows that you might face further problems in the future, trying to go with non-portable solutions (hidden slot names, report functions, etc) instead of first trying the standard way.

find about about the type of function parameters

can i somehow find all functions/macros that take a specific type of parameter ?
for example, what function accepts a Namespace object as parameter ?
(this is because i can create a namespace and store it in a var, but i don't know where i could use that var; what function might i pass that var to ?)
here is some code:
user=> (def working-namespace (create-ns 'my-namespace))
#'user/working-namespace
;i created a namspace and want to use it later
user=> (class working-namespace)
clojure.lang.Namespace
; out of curiosity i found out that "working-namespace" is a Namespace object
user=> (ns working-namespace)
nil
working-namespace=>
; but how do i switch to it ? this didn't do what i wanted...
user=> (refer working-namespace)
java.lang.ClassCastException: clojure.lang.Namespace cannot be cast to clojure.lang.Symbol (NO_SOURCE_FILE:0)
; this did not work either as my expectations
user=> (the-ns working-namespace)
#<Namespace my-namespace>
user=> (class (the-ns working-namespace))
clojure.lang.Namespace
; great, this gave me the same thing, a Namespace
hence the question: how do i use it dynamically (that's why i had put my namespace into a var) ? how do i get something useful for me from a var that points to a namespace ?
i can try look around for functions that make use of a Namespace object or that convert it to something else. i did and only found "intern". searching by hand not seems not that promising
what if i have this problem a million time ? is there an automated way to get me what i'm looking for without having to ask around each time ?
In Clojure 1.2 and previous function arguments dont have types. every function argument is an object. So the question really becomes "how do i find functions that will cast the object I pass them into this type. so searching for type hints will find some of them, though it wont get you everything. I wish it where more possible to answer this in general.
starting with 1.3 (current dev branch 9/2010) function paramerters and return types can have a defined type and will be passed/returned as that type instead of being cast to object and then cast on the other side. This drops one of the zeros from the exacution time of numerical functions with the important limitation that it only works for :static functions and only with direct calls (ie: not through map/reduce/filter/etc.) There is not a lot published on this change yet though it has the important breaking change that integers are no longer boxed by default and integer (actually Long) overflow throws an exception. you can read more here
(defn ^:static fib ^long [^long n]
(if (<= n 1)
1
(+ (fib (dec n)) (fib (- n 2)))))
so after 1.3 is released and widely adopted you will see code with more commonly defined types because they will offer a big speed benefit and then you will be able to find more functions by argument type though still not all of them.
At the same lecture where I learned about function argument types, Rich mentioned plans in the distant Clojure future (after 'Clojure in Clojure') about better support for exposing the compiler internals to tools such as IDEs. So there is hope that someday you will get a real answer to this question.
Dynamic languages make this slightly more difficult in practice and a lot harder in theory.
You already got a good answer from Arthur, so I'll only answer the "how do i get something useful for me from a var that points to a namespace ?". From (doc ns), note that it says unevaluated:
user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
Sets *ns* to the namespace named by name (unevaluated), creating it
Now there's something you could do with in-ns if you want (the whole namespace object -> string -> symbol conversion is probably stupid, but enough to illustrate my point):
user=> (in-ns (symbol (str working-namespace)))
#<Namespace my-namespace>
my-namespace=>
I don't think you can do that without a lot of hackery in a dynamic language. If you want to now what function that take namespaces look at the documentation of the namespace stuff.
For example cleaning namespaces or reload them.
You wrote:
user=> (ns working-namespace)
nil
working-namespace=>
; but how do i switch to it ? this didn't do what i wanted...
But you did switch to the working-namespace namespace (that's why the prompt changed), so I'm not clear as to what "you wanted".
As I noted earlier, you need to present the ultimate problem are you trying to solve. It's entirely likely that messing with namespace objects won't be the solution.

Is there any problem with namespacing clojure keywords in a non-existent namespace?

Should I feel wary about creating clojure keywords which have non-existent namespaces?
An example would be :foo/bar, where namespace foo doesn't actually exist. This seems to be possible because these keywords behave like literals. I couldn't find any problems doing this in the REPL, but I'm concerned about possible problems with AOT compilation.
A namespace will in fact not be created simply because a keyword or symbol is encountered which would "belong" to it, as the following interaction at a fresh REPL illustrates:
; SLIME 2010-05-06
user> (-> (.getNamespace :user/foo) symbol)
user
user> (-> (.getNamespace :user/foo) symbol the-ns)
#<Namespace user>
user> (-> (.getNamespace :bar/foo) symbol the-ns)
; java.lang.Exception: No namespace: bar found
However, this is no cause for worry. A keyword's or symbol's "namespace" field is just an interned string; there is no reference back to the corresponding namespace object involved even if one exists. In fact, as can be seen above, the .getNamespace method of keywords and symbols returns a string and one has to jump a few hops to get to the actual namespace from that.
Trying to resolve a namespace-qualified symbol with the resolve function is safe too. That's regardless of whether the namespace actually exists; if it doesn't, nil is returned, as in the case where it does exist, but holds no Var of the given name. ns-resolve, in contrast, will throw an exception like the one mentioned in the snippet from the REPL above if it can't find the given namespace.