Type signature for sort is incorrect - never returns nil

Activity

Show:
Ambrose Bonnaire-Sergeant
June 19, 2015, 1:18 PM

AFunction is some weird type that is sometimes a valid Comparable.

How are you supposed to know [-> Num] in an invalid Comparable? [Any Any -> Any] ?

Ouch.

Marc O'Morain
June 19, 2015, 5:22 PM

I've gone ahead and added a local annotation to our project to remove nil from the return type from {sort} – after reflection I don't think it's worth burdening every caller of {sort} with adding a nil check to the result, or infecting all client code with an (Option) type for such an unlikely occurrence.

For the sort function to return a nil, the caller would have to pass in a mutable collection and (unsafely) modify the collection while sorting. If someone is doing this they have bigger problems that type safety.

Ambrose Bonnaire-Sergeant
June 19, 2015, 5:41 PM

I could imagine writing some library code in core.typed and then someone else triggering a NPE deep inside typed code; this is not supposed to be possible.

FWIW Nicola Mometto figured out a fun example of returning nil http://sprunge.us/VIFc?clj

Just a word about the philosophy of core annotations: the unchecked annotations of clojure.core must be sound, over any conveniences that might be gained. It doesn't take much to compromise all static guarantees.

This particular case, I think, is a bug in the implementation of `sort`; it should be an if-let.

Could you please share why this important to you? What functions are you using that accept () but not nil? What makes it more convenient to assume nil is impossible?

If it's only a problem in a few areas, you can convince core.typed nil is impossible with a runtime assertion. eg. (let [s (sort ..)] (assert s) s).

Marc O'Morain
June 22, 2015, 11:00 AM

> This particular case, I think, is a bug in the implementation of `sort`; it should be an if-let.
That's a good point, and I agree. I'll create a new ticket to address the documentation issues with sort.

> Could you please share why this important to you? What functions are you using that accept () but not nil? What makes it more convenient to assume nil is impossible?

I'm working on adding annotations to a namespace that searches and filters files in a file-system. There are function to search the filesystem, with signatures like [String Pattern -> (Seq String)] to search a directory for files that match the given pattern. There are also functions that filter searches like [(Seq String) Pattern -> (Seq String)].

My issue is philosophical – a nil becomes infectious, I would need to change the signatures to widen the allowed types from (Seq String) to (U (nil (Seq String)) throughout the namespace and client code, or alternatively to add assertions or change calls to sort to instead call a form like (or (sort x) '()).

The more I think about it the more I realise that the issue is with sort, not the type annotations, as you point out above. I'm writing code that sorts a non-empty list and I have to deal with the fact that the result of sorting a non-empty could be nil.

Ambrose Bonnaire-Sergeant
December 4, 2017, 12:11 AM

Unclear how to proceed.

Completed

Assignee

Ambrose Bonnaire-Sergeant

Reporter

Marc O'Morain

Labels

None

Approval

None

Patch

Code

Affects versions

Priority

Major
Configure