Skip to content

Conversation

@MilesCranmer
Copy link
Member

@MilesCranmer MilesCranmer commented Jul 5, 2025

The var"#self#" symbol refers to the enclosing innermost function. This PR defines it for callable structs to help make usage symmetric. This was first mentioned in #6733 (comment) (@c42f).

This is independent of #58909, but would help make a potential @__FUNCTION__ macro more general.

julia> struct Foo end

julia> (foo::Foo)() = var"#self#";

julia> Foo()()
Foo()

julia> bar() = var"#self#";

julia> bar()
bar (generic function with 1 method)

In the current code, var"#self#" does not work with callable structs:

julia> struct Foo end

julia> (foo::Foo)() = var"#self#";

julia> Foo()()
ERROR: UndefVarError: `#self#` not defined in `Main`

If combined with #58909 we can update the tests to use @__FUNCTION__ rather than var"#symbol#".

@c42f
Copy link
Member

c42f commented Jul 7, 2025

Potential @__FUNCTION__ macro

I assume this doesn't propose var"#self#" as a public API, but merely makes it possible to write @__FUNCTION__?

I guess any #-containing names should be compiler internal - if we want normal user code to be able to refer to them we should probably call them something else.

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Jul 7, 2025

@c42f that is done in #58909 – that PR, not this one, exposes @__FUNCTION__ as public API alias for var"#self#".

This PR just makes it var"#self#" available in callable structs. Which by extension would (if #58909 is merged) make @__FUNCTION__ also work in callable structs.

Copy link
Member

@vtjnash vtjnash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SGTM

@JeffBezanson
Copy link
Member

Yeah this was not meant to be a public API but I guess this is harmless.

Co-authored-by: Jeff Bezanson <[email protected]>
@c42f
Copy link
Member

c42f commented Jul 8, 2025

I have a thought on how to make this a little cleaner.

Can we use Expr(:self) instead of var"#self#", and have @__FUNCTION__ emit that? Then lowering expands Expr(:self) into either var"#self#" or first depending on context?

This might seem equivalent in the current implementation, but in JuliaLowering.jl the internal names like var"#self#" are inaccessible by default (due to hygiene being stronger),

Also we have precedent for this kind of thing in the way that things like @locals expand to special Expr forms.

Using Expr(:self) (or Expr(:function_self) idk?) just gives us a bit more separation between the internals of lowering and the code which uses it.

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Jul 8, 2025

(Sounds like a fine idea to me)

Then lowering expands Expr(:self) into either var"#self#" or first depending on context?

Just wondering, would introducing this split be adding unnecessary complexity? Because of things like:

julia> struct Foo end

julia> (::typeof(sin))(::Foo) = var"#self#";

julia> sin(Foo())
sin (generic function with 15 methods)

Idk I guess I wonder if it’s simpler to normalize to var"#self#" in all cases anyways

@MilesCranmer
Copy link
Member Author

Perhaps you could have Expr(:self, arg) expand to various reflection variables. Like

@__MODULE__ -> Expr(:self, :module) -> __module__
@__FUNCTION__ -> Expr(:self, :function) -> var"#self#"
...

and so on.

@JeffBezanson
Copy link
Member

Just wondering, would introducing this split be adding unnecessary complexity? Because of things like:

What is complex about this case? Actually I'm not sure there really is a split; it just returns the name of the first argument in all cases.

@JeffBezanson
Copy link
Member

We already have (thismodule) so maybe (thisfunction)?

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Jul 8, 2025

Regarding returning the first argument in all cases, are there potential issues with Core.kwcall?

@MilesCranmer
Copy link
Member Author

We already have (thismodule) so maybe (thisfunction)?

Sounds good to me. I'll give it a go

@MilesCranmer
Copy link
Member Author

MilesCranmer commented Jul 8, 2025

Quick questions – (1) should I make a new PR? (2) should I fold #58909 into this as a single PR defining @__FUNCTION__ and also adding Expr(:thisfunction) to the parser?

I'm going to assume (1) yes, (2) no. Let me know otherwise.

New PR in #58940

@MilesCranmer
Copy link
Member Author

Closing in favor of #58940

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants