case fails with ArityException when a single clause with an empty test seq is used
Description
Environment
Attachments
Activity

Chris Blom May 22, 2017 at 4:11 PM
— () would never match anything now, so failing on () would not break any existing case that matches.
As () in case is allowed in clojure =<1.8 (just not when its the only clause), letting the compiler reject it would potentially break existing code.
— The one case I can imagine might exist though is a macro that creates a case and could potentially programmatically create an empty case list?
That is exactly how i ran into this problem

Chris Blom May 22, 2017 at 4:00 PM
I'm not using this to match empty lists, I ran into this corner case when generating case statements from a DSL.
While it is a pathological case, I disagree that is does not make any sense, an empty list here simply represents no alternatives,
so the clause wil never match and its result-expr will never run.
My point is that now (in clojure 1.8) this is allowed:
(case a
() :never-happens
1 :a
2 :b
:default)
it is equivalent to (as an empty list never matches)
(case a
1 :a
2 :b
:default)
But
(case a
() :never-happens
:default)
gives an uninformative error.
I argue that it should be equivalent to
(case a
:default)
as rejecting empty lists in case statements in general would be a breaking change,
and only rejecting empty lists when no other clauses are present is inconsistent.

Alex Miller May 22, 2017 at 3:57 PM
() would never match anything now, so failing on () would not break any existing case that matches.
The one case I can imagine might exist though is a macro that creates a case and could potentially programmatically create an empty case list? Something like this:

Nicola Mometto May 22, 2017 at 3:39 PM
an empty list doesn't make any sense in case as the correct way to match a literal empty list is `(case () (()) :empty)`. I don't see any value in making it not throw and my vote is to have the `case` macro complain at compile time every time a `()` ise used

Chris Blom May 22, 2017 at 3:07 PM
An empty list of options is currently supported when multiple clauses are given, so failing to compile on empty lists would be a breaking change.
This works in 1.8:
(case 1
() :never-happens
1 :ok
:default)
=> :ok
But this does not:
(case 1
() :never-happens
:default)
=> throws clojure.lang.ArityException: Wrong number of args (-2) passed to: core/max
Only failing when no other clauses are given seems very inconsistent to me.
Details
Details
Assignee
Reporter

It is not possible to use case with a single empty seq of options, or with a single seq of options and a default clause.
I would expect
to return :none, instead it fails with an uninformative exception: "Unhandled clojure.lang.ArityException: Wrong number of args (-2) passed to: core/max"
I would expect (case 1 () :a) to fail with "java.lang.IllegalArgumentException: No matching clause", but instead it also fails with
"Unhandled clojure.lang.ArityException: Wrong number of args (-2) passed to: core/max"
This seems inconsistent, as passing an empty list of options is fine when there are other alternatives:
returns :none, as expected
The attached patch removes the test-clause pairs with empty test lists before further conversion to case*, and adds tests.