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
Assignee
UnassignedUnassignedReporter
Chris BlomChris BlomApproval
TriagedPatch
Code and TestPriority
MinorAffects versions
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.