-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Allow type variables with do
syntax
#54915
Comments
This comment was marked as resolved.
This comment was marked as resolved.
I did make a PR to JuliaSyntax. It's a one-liner. |
This comment was marked as resolved.
This comment was marked as resolved.
If this doesn't cause any problems in the parser, looks like an obvious win to me. |
Which version is this proposal suggesting? Requiring the parens seems problematic, because julia> g(f, args...) = f(args...)
g (generic function with 1 method)
julia> g([1,2]) do (x, y)
@info "Look, they're unpacked" x y
end
┌ Info: Look, they're unpacked
│ x = 1
└ y = 2 It would not be good if the parentheses mean something different when the |
The fact that argument destructuring is supported in this case is arguably quite confusing and the best long term solution may be to make parentheses irrelevant in For example here's a very prolific and experienced Julia user getting confused by this: #47661 |
Making progress toward deprecating destructuring for this case would be a long term prospect I suspect. We could assess the current state by looking at how many times it occurs in the package ecosystem. |
IMO that's not viable. People write things like map(Iterators.product(a, b)) do (x, y)
#...
end all the time. |
The syntax I would consider reasonable here would be: f(a, b) do x::T, y::T where T
# body
end I'm not sure why you'd need to do this though... |
Yeah I agree the way parens work here was probably a mistake; |
We can possibly have the syntax @StefanKarpinski suggested - my guess would be that this is not used in practice for simple reasons of obscurity. However, it's technically breaking and we'd need to guess at whether it's actually breaking based on usage in Another option could be to finally do #32071 and make this the only supported way to express In either of these cases, I'd favor a long-term plan to make the current do+destructuring syntax a warning and eventually change it in "the mythical Julia 2.0". I like that syntax-appreciators like @MasonProtter like it and do understand it perfectly well! But it seems high on confusion and low on utility for the average user. |
I'm concerned that a syntax warning wouldn't be actionable because all julia> map(Iterators.product(1:2, 10:10:20)) do (x, y)
x,y
end
2×2 Matrix{Tuple{Int64, Int64}}:
(1, 10) (1, 20)
(2, 10) (2, 20)
SYNTAX WARNING: Destructuring syntax will change. For this use `do ((x,y),)`. The user is instructed to use julia> map(Iterators.product(1:2, 10:10:20)) do ((x, y),)
x,y
end
ERROR: BoundsError: attempt to access Int64 at index [2] |
Good point. To make any progress on syntax issues like this and others, we probably need to adopt something like Rust Editions which allow module-local breaking syntax changes. They allow carefully considered breaking changes without bifurcating the ecosystem:
JuliaSyntax already has a system for version-aware parsing. The main thing would be to add the edition to Project.toml (presumably) and we could do something like this on an opt-in basis. |
I like the idea of syntax editions, but IMO, that information should be in the file itself, not the One thing I like a lot about Julia is that the meaning of code is almost always self contained in the code itself, rather than being modified in disconnected configuration files. I don't want to share a code snippet saying map(Iterators.product(1:2, 10:10:20)) do (x, y)
x,y
end and have people not know what it does without me also supplying the Project.toml. Rather, I'd like something more like using JuliaSyntax
JuliaSyntax.@set_feature do_parens=v2
map(Iterators.product(1:2, 10:10:20)) do (x, y)
x,y
end or something like that. |
IMO it's important to have "all or nothing" for syntax editions which are designed to "improve" syntax in the sense of making it less confusing: there needs to be some incentive to drive the ecosystem forward so that everyone is using the latest syntax, where possible. See #54903 (comment). So we shouldn't have fine grained options like Also that's somewhat problematic from a semantic standpoint: there might not be any module for |
Things may become strange IIUC, since parenthesis may be peeled differently if we use a do block (right side) or not (left side of the call). Here is another proposal f(a, b) do x, y
#= ... =#
end
# may be <=> to
f(a, b) do x, y -> # recycle opener - leanified
#= ... =#
end
# THEN
# type welcome
f(a, b) do x::Int, y ->
#= ... =#
end
# kwarg welcome too
f(a, b) do x, y; u ->
#= ... =#
end
# destructuring ok (same old form)
f(a, b) do (x, y); u ->
#= ... =#
end
# w type params
f(a, b) do x::T, y::T; u ->
#= ... =#
end where {T}
# !!! special point . rhs is listof ; but do is already new line sensitive
f(a, b) do x::Int, y ->
#= ... =#
end
|
From triage: This makes sense from a theoretical/consistency perspective, but we don't think it's worth doing practically. In a perfect world, this would work, but the Most of the time the type is used statically, The primary (though by no means exclusive) use of type variables in function declarations is for dispatch and folks almost never define multiple methods on a function declared with Ultimately, the practical cost of increased confusion likely outweighs the practical benefit. |
Thanks for the nuanced consideration and the well written summary. |
The
do
syntax should support type variables, so that something likeor at least
should behave the same as in regular functions regarding
T
.There are three reasons why the do syntax should allow type variables:
This is discussed in a Question and a Suggestion. A change proposal is already provided by
sgaure
(without pull request).The text was updated successfully, but these errors were encountered: