ocaml icon indicating copy to clipboard operation
ocaml copied to clipboard

__FUNCTION__: document inclusion of module-level let-bindings

Open nojb opened this issue 2 months ago • 15 comments

Attempt to address #14376. I used the formulation "module-level let-binding" to exclude bindings introduced by "let-in" expressions, but perhaps there is something clearer that could be used. Suggestions welcome!

Fixes #14376

nojb avatar Dec 11 '25 10:12 nojb

I'm not sure what @gasche means by "correct", is that terminology introduced somewhere? The manual calls these value definitions though I'm not sure it makes things clear, unless you link on it.

I think that if I'd mention that concept casually I would rather say a "top level binding".

dbuenzli avatar Dec 11 '25 10:12 dbuenzli

I think we should stop making a distinction between the final things and the enclosing things. __FUNCTION__ can also return a class, and methods and top-level bindings can also be enclosing.

lthls avatar Dec 11 '25 10:12 lthls

Thanks for the suggestions! What about:

(** [__FUNCTION__] returns a period-separated string consisting of the
    names of all enclosing functions, methods, classes, modules, and top-level let-bindings.

nojb avatar Dec 11 '25 10:12 nojb

Technically methods are separated from their class by a # symbol, not a period. I'm not sure how important it is to mention it.

lthls avatar Dec 11 '25 10:12 lthls

Technically methods are separated from their class by a # symbol, not a period. I'm not sure how important it is to mention it.

Good point. We could avoid going into those details:

(** [__FUNCTION__] returns a string containing the names of all
    enclosing functions, methods, classes, modules, and top-level let-bindings.

nojb avatar Dec 11 '25 10:12 nojb

I had to test what __FUNCTION__ is to understand your definition, so I guess it's still not so good :–)

> cat test.ml 
let f () = let g () = __FUNCTION__ in g ();;

print_endline (f ())
> brzo --root .
Test.f.g

I suspect this could be reframed in terms of module paths extended with looking up into closures. But what about:

[__FUNCTION__] is the string ["N0.n1.n2…"] with [ni] the names of enclosing definitions
that lead to the location of the call. [N0] is the module name of the compilation unit.

dbuenzli avatar Dec 11 '25 10:12 dbuenzli

@dbuenzli I think that your proposal would be great if we changed the definition of __FUNCTION__ to match it. If we don't change how __FUNCTION__ works, then your proposal misses some of the small inconsistencies that were pointed out in #14376. So my favourite proposal so far is @nojb's last one, where the only inaccuracy is that all module-level bindings are included, not only the top-level ones, but I think that's fine. (Amusingly, allowing let let x = ... in ... in #14040 would have allowed x to appear in scopes, whereas it doesn't with a single let.)

lthls avatar Dec 11 '25 11:12 lthls

I don't object @nojb's last one except for the fact that I don't think it's understandable :–)

dbuenzli avatar Dec 11 '25 11:12 dbuenzli

We could go for maximum precision, but this will make it harder to change the format in the future:

__FUNCTION__ returns a string of the form "N0n1n2..." where N0 is the name of the compilation unit and the ni are the names of the successive scopes leading to the location of the call, each of which has one of the following forms:

  • .n if n is the name of a function, module, class or value definition,
  • #n if n is the name of a method, or
  • (fun) if the scope corresponds to an anonymous function.

nojb avatar Dec 11 '25 13:12 nojb

but this will make it harder to change the format in the future:

In my opinion, either you specify that format is unspecified and should not be relied on (but people will anyways) or you describe it precisely (in which case I think your last proposal is good).

dbuenzli avatar Dec 11 '25 13:12 dbuenzli

@lthls @gasche are you satisfied with the latest formulation?

nojb avatar Dec 11 '25 13:12 nojb

I'm also wondering if the actual string may change depending on compilation options (e.g. inlining) if that is the case then perhaps it should be mentioned.

dbuenzli avatar Dec 11 '25 13:12 dbuenzli

I think of __FUNCTION__ as a best-effort description of the location of the current code position, and in my mind the "best-effort" part means that it could evolve in the future. Documenting the current output is fine, but I would say explicitly that it is best-effort and may change later.

gasche avatar Dec 11 '25 13:12 gasche

I would say explicitly that it is best-effort and may change later.

Seems fair, I will add a note about this.

nojb avatar Dec 11 '25 13:12 nojb

I pushed cf28a4545b829de893f75714fa7f3bf3c6c3e9c9 with the latest changes. This is what it looks like in rendered form:

image

nojb avatar Dec 11 '25 13:12 nojb