Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standalone dotted function names #40858

Open
knuesel opened this issue May 18, 2021 · 13 comments
Open

Standalone dotted function names #40858

knuesel opened this issue May 18, 2021 · 13 comments
Labels
broadcast Applying a function over a collection feature Indicates new feature / enhancement requests parser Language parsing and surface syntax

Comments

@knuesel
Copy link
Member

knuesel commented May 18, 2021

This is to track an idea originally from #34156: It would be nice to allow something like map(f., a, b) as a shorthand for Base.BroadcastFunction(f). Following #37583 this is now supported for operators, but it would be equally useful for functions I think.

@mbauman mbauman added broadcast Applying a function over a collection parser Language parsing and surface syntax labels May 18, 2021
@stevengj
Copy link
Member

f.(_) would be a nice syntax for this (#24990)…

@goretkin
Copy link
Contributor

f.(_) would represent specifically a 1-arg invocation of broadcastedf, right? I understood the OP to be something like map((x, y) -> f.(x, y), a, b)

@knuesel
Copy link
Member Author

knuesel commented May 18, 2021

Indeed... One can do map(f.(_, _), a, b) but that means the number of arguments must be known at "broadcastizing" time. So it would not be as general as Base.BroadcastFunction(f) which works with different numbers of arguments at call time. It would still cover a large portion of use cases I guess?

@knuesel
Copy link
Member Author

knuesel commented May 18, 2021

#24990 could be extended to support f(_...) with the meaning of (x...) -> f(x...). But that's not great: I think logically it should rather mean x -> f(x...). And it doesn't cover keyword arguments.

Maybe better would be to have f(__, a) represent (x...; y...) -> f(x..., a; y...). Then Base.BroadcastFunction(f) would be essentially the same as f.(__) I think?

@rafaqz
Copy link
Contributor

rafaqz commented Feb 21, 2024

This issue was slightly derailed by the underscore question. But seeing that syntax has not worked out so far, can we again focus on why we have .+ and not f. (or another shorthand) ?

@ararslan noted in the original issue:

Would it be weird to be able to do e.g. map(.+, a, b) but not map(f., a, b) in general?

And it seems like the answer is yes, it is a bit weird that one is .+ and the other needs Base.BroadcastFunction(f). We can't really put that in package docs.

@LilithHafner LilithHafner added the feature Indicates new feature / enhancement requests label Feb 21, 2024
@LilithHafner LilithHafner added the triage This should be discussed on a triage call label Feb 29, 2024
@JeffBezanson
Copy link
Member

Maybe just a nicer function name for it like dotted(f)? My main worry is that f. or .f is confusable with field access.

@LilithHafner
Copy link
Member

LilithHafner commented Feb 29, 2024

Triage concurs that a nicer name (e.g. dotted) would be good but doesn't have a strong opinion about the specific name. But using . is not good because of map(.x [(x=5,), (x=6,)])

Edited to fix (x=5) => (x=5,)

@LilithHafner LilithHafner removed the triage This should be discussed on a triage call label Feb 29, 2024
@rafaqz
Copy link
Contributor

rafaqz commented Feb 29, 2024

Is f. really ambiguous?

map(f., [(; x=5), (; x=6)])

What would be the expected result?

(Also dont quite get the .x example... its just a vector of Int, and we cant broadcast over NamedTuple anyway?)

@mbauman
Copy link
Member

mbauman commented Feb 29, 2024

One trouble with f. is that it can change the meaning of existing code. Currently, this is valid Julia:

julia> f = Ref{Any}()
Base.RefValue{Any}(#undef)

julia> g = f.
       x = 2
2

What if . itself were the name of the dotted function? I think that's more available.

julia> const var"." = Broadcast.BroadcastFunction
Base.Broadcast.BroadcastFunction

julia> var"."(sin)
Base.Broadcast.BroadcastFunction(sin)

julia> Meta.parse(".(f)")
ERROR: ParseError:
# Error @ none:1:1
.(f)
╙ ── invalid identifier

@adienes
Copy link
Contributor

adienes commented Feb 29, 2024

Currently, this is valid Julia:

julia> f = Ref{Any}()
Base.RefValue{Any}(#undef)

julia> g = f.
       x = 2

wait... that's valid?? what does it mean?

EDIT: oh I see Ref just has a field named x so it's no different than this being "valid"

julia> struct X x end

julia> X(1).
       x
1

although I'm pretty surprised this doesn't throw a parse error...

@LilithHafner
Copy link
Member

I like that .(f) looks like .*, but words are nice too.

@mbauman
Copy link
Member

mbauman commented Feb 29, 2024

It not only looks like it, but .(*) would be === to .*

julia> var"."(*) === .*
true

@rafaqz
Copy link
Contributor

rafaqz commented Feb 29, 2024

.(f) is really nice! and matches how concise .+ is already.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
broadcast Applying a function over a collection feature Indicates new feature / enhancement requests parser Language parsing and surface syntax
Projects
None yet
Development

No branches or pull requests

8 participants