Zulip Chat Archive
Stream: mathlib4
Topic: Naming convention for structure projections and dot notation
Bhavik Mehta (Apr 15 2025 at 16:35):
(This was originally for the undocumented informal policy thread, but after writing it I realised it makes a lot more sense as its own thread!)
Here's something that's been on my mind recently: the naming convention for functions which are at least one of a) structure projections (eg Functor.obj
) or b) dot notation: should these be prefixed or suffixed?
Currently mathlib often uses suffixes in names for structure projections, eg docs#CategoryTheory.Functor.comp_obj, and these are almost always spelled using dot notation. (The exception is coercions to fun/set, which are named coe_
and written using prefixes). For example named lemmas generated by simps
are always suffixed, unless they're special cased otherwise (which happens exactly in coercion case).
The Lean4 Std naming convention explicitly prescribes that structure projections should be suffixed: https://github.com/leanprover/lean4/blob/master/doc/std/naming.md#naming-algorithm-for-theorems-and-some-definitions, but my understanding is that this is not meant to be prescriptive for mathlib.
Mathlib in practice is somewhat split between whether prefixes or suffixes should be used for dot notation, except: predicates are explicitly named in #naming as being prefixes (except for certain common examples like _injective
). Yaël claims here that use of dot notation should not change the name, which didn't seem to have either pushback or general agreement. (Others also suggested that "functions are prefixed" in general might not even be the right rule, let alone dot notation). Before that, a similar discussion happened #general > #naming and dot notation here, where there was general (but not complete) consensus that use of dot notation should change the name. For example Kim suggests that we encourage dot notation to be used, and so the naming should too (although this was quite a while ago, so it's very reasonable for opinions to have changed!).
I would like there to be a clearer convention on when prefix or suffix should be used for these situations.
Mario Carneiro (Apr 15 2025 at 16:47):
This discussion also came up in Batteries and we went with prefix naming convention for both functions used in dot notation as well as structure projections
Mario Carneiro (Apr 15 2025 at 16:47):
It's interesting (surprising?) that Std is now going the other way
Markus Himmel (Apr 15 2025 at 20:20):
The reason why Std
has this convention is because I believed that this is the preferred in mathlib, and I guess I believed this because this is the scheme used by the simps
attribute.
Markus Himmel (Apr 15 2025 at 20:28):
I think it's safe to say that the standard library convention will change to match whatever mathlib decides here.
Bhavik Mehta (Apr 15 2025 at 20:29):
Markus Himmel said:
The reason why
Std
has this convention is because I believed that this is the preferred in mathlib, and I guess I believed this because this is the scheme used by thesimps
attribute.
From looking through what happened at the time, it seems to me that mathlib preferred suffix for structure projections, and so simps
was implemented to reflect this, so that it could be used out-of-the-box to generate lemmas. So that justification seems reasonable enough!
Mario Carneiro (Apr 15 2025 at 20:30):
I wanted to link a discussion on Batteries about this but my search-fu is failing. I think it was on a github issue?
Mario Carneiro (Apr 15 2025 at 20:33):
aha: https://github.com/leanprover-community/batteries/pull/329#issuecomment-1786193983
Markus Himmel (Apr 15 2025 at 20:52):
Personally, I like the rule "functions are prefixes (except for infix notations) and dot notation does not matter" (which if I understand correctly is the Batteries convention). I like it because it contains very few special cases and it is easy to construct and guess names using this rule.
Bhavik Mehta (Apr 15 2025 at 21:03):
Note that following this rule would require a lot of changes (and deprecations) in mathlib; especially throughout category theory!
Mario Carneiro (Apr 15 2025 at 21:09):
I recall that Kim was not happy with this choice in Batteries (well, at least they were advocating for dot notation as suffix)
Kyle Miller (Apr 15 2025 at 21:30):
I used to be an advocate for "if a function is meant to be used with dot notation, use a suffix". One justification I had for this is that we name theorems for other notations based on how they pretty print (e.g. add
comes between operands' names). However, using dot notation is optional, and binary operations are basically not optional. The pretty printer is allowed to not use dot notation when it would not round trip as well.
Because of these reasons, I've shifted toward being pro "always prefix". Somehow still Functor.comp_obj
somehow feels more right than Functor.obj_comp
(and a point for Functor.comp_obj
is in discoverability; comp
is more salient than obj
), but I don't mind to see the Functor.obj_comp
.
Bhavik Mehta (Apr 15 2025 at 21:47):
In what sense is dot notation more optional than binary operations? I can write HMul.hMul a b
just as I could write Functor.obj (F.comp G) X
(and in this example, avoiding dot notation for Functor.obj
is more painful than avoiding the binary operation!)
Kyle Miller (Apr 15 2025 at 21:48):
In the sense that no one realistically writes HMul.hMul a
. Everyone expects HMul.hMul
to be pretty printed using *
.
Kyle Miller (Apr 15 2025 at 21:49):
Well, people probably do write HMul.hMul a
sometimes, but at least HMul.hMul a b
is unlikely.
Bhavik Mehta (Apr 15 2025 at 21:49):
But no one realistically writes Functor.obj F X
either!
Kyle Miller (Apr 15 2025 at 21:51):
Wow, it really is never. Prefunctor.obj
appears just once in Mathlib.AlgebraicGeometry.Scheme
.
Bhavik Mehta (Apr 15 2025 at 21:52):
On a quick grep through mathlib, I can find two instances (outside of meta code) of fully-applied HMul.hMul a b
, and one of Prefunctor.obj
, as you mention
Mario Carneiro (Apr 15 2025 at 21:54):
does that include uses of obj
with the appropriate namespace open?
Bhavik Mehta (Apr 15 2025 at 21:54):
Actually, that one is to define notation:
scoped[AlgebraicGeometry] notation3:90 f:91 " ⁻¹ᵁ " U:90 =>
@Prefunctor.obj (Scheme.Opens _) _ (Scheme.Opens _) _
(Opens.map (f : Scheme.Hom _ _).base).toPrefunctor U
Bhavik Mehta (Apr 15 2025 at 21:55):
Mario Carneiro said:
does that include uses of
obj
with the appropriate namespace open?
It does not (although I really doubt that happens)
Mario Carneiro (Apr 15 2025 at 21:56):
well when you have to use the namespace dot notation is clearly better but when it is open they are equally terse
Bhavik Mehta (Apr 15 2025 at 21:56):
Yeah, I can't find any matches for open.*Prefunctor
, and looking through the files which namespace Prefunctor
, none of them seem to use obj
as a prefix
Mario Carneiro (Apr 15 2025 at 21:56):
Certainly this happens a lot for list functions
Mario Carneiro (Apr 15 2025 at 21:57):
Isn't obj
also in the Functor
namespace?
Bhavik Mehta (Apr 15 2025 at 21:57):
I don't think so? It's docs#Prefunctor.obj
Mario Carneiro (Apr 15 2025 at 21:57):
yes, but there is extends magic
Kyle Miller (Apr 15 2025 at 21:58):
Maybe it should, but that doesn't put it into the Functor
namespace
Kyle Miller (Apr 15 2025 at 21:58):
You can't use Prefunctor.obj
on a Functor
without using dot notation.
Kyle Miller (Apr 15 2025 at 21:58):
without writing Prefunctor.obj (Functor.toPrefunctor f)
Kyle Miller (Apr 15 2025 at 21:59):
(remember the good old days of Lean 4 when it pretty printed as f.toPrefunctor.obj
? :-))
Mario Carneiro (Apr 15 2025 at 22:01):
I see, so that explains why this one in particular is always dot notation
Kim Morrison (Apr 16 2025 at 00:15):
Mario Carneiro said:
I recall that Kim was not happy with this choice in Batteries (well, at least they were advocating for dot notation as suffix)
I think I was confused by inconsistencies, rather than unhappy with any particular choice. (At least I hope so! I recall also having the same thought Markus mentions above: thinking @[simps]
was prescriptive.)
I would prefer "functions are prefixes, ignore dot notation, projections are not special" if we can get there!
Eric Wieser (Apr 16 2025 at 00:18):
I guess this means that instead of foo_apply
and foo_symm_apply
we'd have foo_apply
and symm_foo_apply
?
Eric Wieser (Apr 16 2025 at 00:18):
Or is symm
going to get a special case?
Bhavik Mehta (Apr 16 2025 at 15:28):
Thinking more about the distinction between List and functor as above, to me the difference is in how the pretty-printer shows it:
import Mathlib
open CategoryTheory
variable (F : Type ⥤ Type) (X Y : Type) (a : List X) (f : X → Y)
#check a.map f -- says List.map f a
#check F.map f -- says F.map f
Drawing the line here would be a smaller change to mathlib. And for Kyle's point of the pretty printer is allowed to not use dot notation: it's still well-defined what the "standard" behaviour of the pretty printer is for a definition.
Bhavik Mehta (Apr 16 2025 at 19:37):
Eric Wieser said:
I guess this means that instead of
foo_apply
andfoo_symm_apply
we'd havefoo_apply
andsymm_foo_apply
?
If I'm understanding correctly, "projections are not special" means that bundled maps would have the apply
as prefixed as well, since that's a structure projection. So bare functions would be suffix but bundled functions would be prefix? Or there should be special cases for certain kinds of projections instead
Aaron Liu (Apr 16 2025 at 19:39):
It's actually not a structure projection, but DFunLike.coe
.
Bhavik Mehta (Apr 16 2025 at 19:39):
I think that's an implementation detail, these are named from (eg) here: https://github.com/leanprover-community/mathlib4/blob/da9d909e9bbfda893df76c07801fe587bc030fc9/Mathlib/Algebra/Group/Hom/Defs.lean#L515
Aaron Liu (Apr 16 2025 at 19:40):
You can tell they're distinct because we have lemmas to rewrite between them (eg docs#Equiv.toFun_as_coe)
Bhavik Mehta (Apr 16 2025 at 19:43):
I'm not sure I understand the rule then, it's that structure projections are prefix unless someone makes them into a DFunLike?
Aaron Liu (Apr 16 2025 at 19:45):
I think the rule for pp is that if the first explicit argument has the type with the same namespace, then it's dot notation
Aaron Liu (Apr 16 2025 at 19:46):
Should we just mirror that?
Bhavik Mehta (Apr 16 2025 at 19:50):
Perhaps, but that's inconsistent with Kim's rule from above, I'm pretty sure
Johan Commelin (Apr 17 2025 at 06:47):
Kyle Miller said:
Because of these reasons, I've shifted toward being pro "always prefix". Somehow still
Functor.comp_obj
somehow feels more right thanFunctor.obj_comp
(and a point forFunctor.comp_obj
is in discoverability;comp
is more salient thanobj
), but I don't mind to see theFunctor.obj_comp
.
To me this salience is an important feature. The status quo somewhat prioritizes it, but not consistently. I would like new conventions to also take it into account.
Last updated: May 02 2025 at 03:31 UTC