Zulip Chat Archive
Stream: mathlib4
Topic: Private definitions and lemmas
Emilie (Shad Amethyst) (Feb 02 2024 at 01:00):
I'm unsure what the current stance is on private definitions and lemmas; I'm thinking of marking a few things in my formalization of Rubin's theorem as private, because to me they're just implementation detail, namely:
- defining an intermediary function before proving it is bijective and using
Equiv.ofBijective
— the function is only really exposed if one unfolds the generatedEquiv
, and I have a theorem that makes this result public already (example snippet from my branch) - wrappers around
Exists.choose
andExists.choose_spec
— I have to applyExists.choose
inside of abiInter
, and I haven't found a better way to do this without making the proof next to unreadable (example snippet from my branch) - in general, one-time-use lemmas that are very unlikely to see any use outside of one or two upcoming theorem
- strictly weaker statements, like proving
≤
before proving=
fromle_antisymm
The big issue I am seeing with private definitions is that you cannot unfold
them, but in a perfect world unfold
-ing shouldn't be necessary outside of the module proving theorems about the definition.
Moritz Doll (Feb 02 2024 at 01:24):
Mathlib generally avoids private
and instead uses names like foo_aux
instead, see docs#ContinuousLinearMap.adjointAux for example
Ruben Van de Velde (Feb 02 2024 at 06:44):
I think there were implementation issues with private in lean 3 but they may be solved in lean 4, so I don't think there's a strong reason to avoid it on that account. It may make it harder to prove new API lemmas elsewhere though, for example in preparation for upstreaming
Yaël Dillies (Feb 02 2024 at 07:30):
I agree with your use cases. I mark definitions private when they fulfill one of your requirements.
Yaël Dillies (Feb 02 2024 at 07:30):
And I believe the pattern Moritz is referring to should be stopped
Eric Wieser (Feb 02 2024 at 07:44):
Maybe the rule should be that if you put aux
in the name, it should also be private? I think keeping the aux in private names is fine, as it avoids local naming conflicts
Yaël Dillies (Feb 02 2024 at 09:04):
Yeah sure (and I've mostly been doing that). private
names don't really matter, so you do you
Mario Carneiro (Feb 02 2024 at 10:07):
I think for definitions we should still avoid private
. For theorems it's mostly fine
Mario Carneiro (Feb 02 2024 at 10:08):
but the argument that you never know when someone will want to prove more things about that definition you made and thought was only relevant for two theorems still applies in mathlib itself
Damiano Testa (Feb 02 2024 at 10:12):
I personally do not really like private
, but I like the idea of some flagging of definitions that are intended as stepping stones. So, personally, I find the aux
naming a good practice.
Damiano Testa (Feb 02 2024 at 10:15):
My view is that private
is a good way of avoiding downstream use of the declaration. This makes perfect sense for a programming language developper that wants to have some internals, but only worry about not changing the outward-facing programs.
In Mathlib, the subject is... mathematics! Everyone should have access to whatever they want!
Mario Carneiro (Feb 02 2024 at 10:20):
well there is still the issue of backward compatibility and migration, which makes it useful to have a notion of "these things you can count on, those things are refactored frequently and you should coordinate with X and Y if you want to use them"
Mario Carneiro (Feb 02 2024 at 10:20):
I'm not sure private
is exactly the right mechanism for this though
Martin Dvořák (Feb 02 2024 at 10:23):
In my projects, almost everything is private. It sometimes leads to a clash of opinions when I end up contributing my results to Mathlib. Namely #9705 ...
Mario Carneiro (Feb 02 2024 at 10:28):
these are mathlib wide design decisions, I would advise you to go with the prevailing style and separately pursue changing that style if you want
Martin Dvořák (Feb 02 2024 at 10:40):
Yeah, I usually aim to accommodate my work the the Mathlib ways. Sometimes it is hard tho, because this design decision raises the bar for how well my implementation details have to be handled. Hence my PR is currently in the "awaiting author" state.
Mario Carneiro (Feb 02 2024 at 10:50):
I'm not sure what that means, the bar is the same either way
Mario Carneiro (Feb 02 2024 at 10:51):
an *Aux
function can be written in a way which is convenient for the known use cases just like a private function
Yaël Dillies (Feb 02 2024 at 13:30):
Mario Carneiro said:
but the argument that you never know when someone will want to prove more things about that definition you made and thought was only relevant for two theorems still applies in mathlib itself
It definitely doesn't apply to the things I mark private
in Bhavik and I's formalisation of combinatorics where concepts do not correspond to a single general theorem but rather to a collection of analogous statements with varying asymptotic behavior depending on the application.
Mario Carneiro (Feb 02 2024 at 13:54):
I don't know what that means
Junyan Xu (Feb 02 2024 at 20:18):
Emilie (Shad Amethyst) said:
- wrappers around
Exists.choose
andExists.choose_spec
— I have to applyExists.choose
inside of abiInter
, and I haven't found a better way to do this without making the proof next to unreadable (example snippet from my branch)
This seems to be a combination of docs#Finite.to_properlyDiscontinuousSMul and this lemma I proved.
Also,
lemma _root_.OrderEmbedding.injective {α β : Type*} [PartialOrder α] [Preorder β] (f : α ↪o β) :
Function.Injective f := f.inj'
should work
Emilie (Shad Amethyst) (Feb 02 2024 at 20:57):
Yeah I figured in the meantime this lemma could go, I was focused on something else when I wrote this :)
Eric Wieser (Feb 02 2024 at 21:15):
Mario Carneiro said:
but the argument that you never know when someone will want to prove more things about that definition you made and thought was only relevant for two theorems still applies in mathlib itself
If this happens, then arguably this definition is worthy of an aux
-less name; but I guess the difference is that it's easier for downstream users to work around a weird name than it is to direct them to import private
or whatever the command is
Junyan Xu (Feb 02 2024 at 21:19):
This seems to be a combination of docs#Finite.to_properlyDiscontinuousSMul and this lemma I proved.
I see that my version doesn't subsume yours because your code doesn't mention compactness and allows for a set s
not necessarily equal to the whole group. Nevertheless I think the statements are similar in spirit so I hope my code could help you simplify yours :)
Emilie (Shad Amethyst) (Feb 02 2024 at 21:40):
I'd have to ponder this a bit more, I don't see immediately how I can use your theorem, since I don't think I can get to a ProperlyDiscontinuousSMul
from my context
Mario Carneiro (Feb 02 2024 at 23:42):
Eric Wieser said:
Mario Carneiro said:
but the argument that you never know when someone will want to prove more things about that definition you made and thought was only relevant for two theorems still applies in mathlib itself
If this happens, then arguably this definition is worthy of an
aux
-less name; but I guess the difference is that it's easier for downstream users to work around a weird name than it is to direct them toimport private
or whatever the command is
I don't think this follows. You can have a function which is intended as a building block for another function, which has complex arguments, which nevertheless has useful lemmas about it. It doesn't become any easier to name as a result
Mario Carneiro (Feb 02 2024 at 23:42):
A lot of the List
functions are like that
Mario Carneiro (Feb 02 2024 at 23:43):
List.reverseAux
actually gets used quite a lot in mathlib because it has really nice defeqs
Last updated: May 02 2025 at 03:31 UTC