Zulip Chat Archive
Stream: mathlib4
Topic: Unused arguments and by_cases
Mario Carneiro (Apr 23 2025 at 03:33):
that's a bug in the implementation of by_cases
Yury G. Kudryashov (Apr 23 2025 at 04:33):
I see that by_cases
is implemented as dite
. I think that if h : p x then (code using h) else (code not using h)
in Prop
context should report unused variable too.
Kevin Buzzard (Apr 23 2025 at 05:36):
Well then how the heck am I supposed to prove it without writing noisy code?
Yury G. Kudryashov (Apr 23 2025 at 05:56):
Just use the negative branch of the argument.
Notification Bot (Apr 23 2025 at 05:57):
4 messages were moved here from #mathlib4 > Call for help: technical/ organisational debt by Yury G. Kudryashov.
Yury G. Kudryashov (Apr 23 2025 at 05:58):
The messages above were replies to this message:
Yury G. Kudryashov said:
- Better support for
by_cases
(and may be somecases
- not sure) in the "unused *" linters. If I runby_cases h : _
, but one of the branches doesn't useh
, thenh
is unused. Forrcases, see src#iteratedDerivWithin_const_add (going to be fixed in #24227): the 2nd branch doesn't use
hxs, but this
hxs` isn't marked as unused.
Mario Carneiro (Apr 23 2025 at 07:06):
Yury G. Kudryashov said:
I see that
by_cases
is implemented asdite
. I think thatif h : p x then (code using h) else (code not using h)
inProp
context should report unused variable too.
Neither of these are giving me unused variable warnings:
theorem foo (p : Nat → Bool) (h0 : p 0) (x : Nat) : ∃ x, p x :=
if h : p x then ⟨x, h⟩ else ⟨_, h0⟩
theorem foo' (p : Nat → Bool) (h0 : p 0) (x : Nat) : ∃ x, p x := by
by_cases h : p x
· exact ⟨x, h⟩
· exact ⟨_, h0⟩
I'm testing on 4.19.0-rc3, which I think is the latest version. There was another report about a recent regression on unused variable warnings which could be related?
Mario Carneiro (Apr 23 2025 at 07:09):
At least the version of the unused variable warning that I wrote is designed to handle this case - if you have multiple variables declared by the same syntax then if any of them is used the unused variable warning on it is suppressed
Mario Carneiro (Apr 23 2025 at 07:09):
it's been rewritten at least once since then though, and it's possible that some correctness was traded for efficiency
Yury G. Kudryashov (Apr 23 2025 at 12:23):
This is not a recent regression. This bug was there for quite some time.
Mario Carneiro (Apr 23 2025 at 20:36):
Can you give a reproduction? As I mentioned, the obvious thing is not a reproducer
Yury G. Kudryashov (Apr 23 2025 at 23:39):
In what sense your examples aren't reproducers? They don't mark h
as unused while they should.
Yury G. Kudryashov (Apr 23 2025 at 23:45):
I found our previous discussion of this topic: #lean4 > Unused linter with `by_cases`
Mario Carneiro (Apr 25 2025 at 01:30):
wait, the complaint is that the linter doesn't fire? As I said, this is by design; it would make no sense to call h
unused here because it is used and if you change the name of the variable binder then the proof breaks
Mario Carneiro (Apr 25 2025 at 01:32):
Reading the other thread, the issue isn't so much that h
is unused as the whole by_cases
is unused (in the sense of the "tactic does nothing" lint)
Mario Carneiro (Apr 25 2025 at 01:33):
I think this should be done by an entirely different tactic / linter than the unused variables linter
Yury G. Kudryashov (Apr 25 2025 at 03:39):
I won't enter the argument "should it be a part of the existing linter or a new one?" Let me rephrase my request as "add a linter that catches this anti-pattern".
Yury G. Kudryashov (Apr 25 2025 at 05:38):
BTW, this is definitely out of scope of the "tactic does nothing" lint, because the call to by_cases
modifies the goal. It's closer to "unused have" (but that's not it, because it's not a have
or let
).
Jz Pan (Apr 25 2025 at 05:56):
It is just "suboptimal proof"
Yury G. Kudryashov (Apr 25 2025 at 06:10):
All the "unused ..." linters check for suboptimal proofs.
Yury G. Kudryashov (Apr 25 2025 at 06:10):
E.g., if one of your assumptions is used in the unneeded branch only, then it's actually an unneeded assumption.
Robin Arnez (Apr 25 2025 at 06:38):
Well there are reasons for why one might intentionally have it unused in one of the branches (that is, when constructing data), e.g.:
def toFin3? (x : Nat) : Option (Fin 3) :=
if h : x < 3 then some ⟨x, h⟩ else none
def inverse [Nonempty α] (f : α → β) : β → α := by
intro x
by_cases h : ∃ y, f y = x
· exact h.choose
· exact Classical.ofNonempty
For Prop
goals I would say the tactic is more at fault then the variable (you can also omit the variable name but that won't change whether the by_cases
is unused).
Ruben Van de Velde (Apr 25 2025 at 07:04):
Yes, but Yury explicitly said "in Prop
context"
Kevin Buzzard (Apr 25 2025 at 07:27):
The point (which took me a while to understand) is that if if h : P then <proof using h> else <proof not using h>
can always be replaced by <proof not using h>
Last updated: May 02 2025 at 03:31 UTC