-
-
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
"Tuple field type cannot be Union{}" error in all 1.10 and 1.11 versions #52385
Comments
This is a deliberate change, see #49111. |
You didn't include a stacktrace, but it looks like this calls
|
The MWE doesn't depend on See: julia> arrs = (Union{}[], Int[])
# works on 1.9 – broken on 1.10rc
julia> Tuple{map(eltype, arrs)...}
ERROR: Tuple field type cannot be Union{} |
Not all |
Creating a Tuple type with arbitrary types inside seems to make total sense, that's one of the most fundamental Julia types. I haven't seen anywhere in the docs that Tuple only supports a subset of Julia types. And this limitation does sound strange, doesn't it? |
So, should this error be removed?
|
Running into this error using
|
As with the previous person, this is due to the Dictionaries package using the disallowed private symbol |
This issue (the one discussed here, don't know about AoG) is independent on There's nothing fundamentally bad with breaking changes, they should just be clearly communicated. For now, Julia promises no breaking changes in 1.x, which this clearly contradicts. |
The empty union, I admit this might be difficult to fix, though. |
Having no instances is not the same as having no subtypes. Those are 2 orthogonal properties. We could try to return Union{} here, as that was the first attempt before making it an error, but much code behaved poorly with that, so it would be a breaking change. Making it an error--for this case which was already buggy--was not a breaking change, since packages had always been told not to call the Core.Compiler functions. |
Both |
Not sure why |
#51950 can be a "duplicate" from the internals PoV (function signatures are implemented as tuples), but for a user these are two different scenarios. |
@vtjnash I've opened a PR against Dictionaries.jl that only uses public API and this problem still arises, so this is definitely not an issue arising relying on compiler internals. |
Still - in terms of the implementation, having As for |
This seems like legitimate Julia code that does not depend on internals, though I don't think I've ever had a use-case for julia> eagerzip() = error()
eagerzip (generic function with 1 method)
julia> function eagerzip(args::AbstractArray...)
allequal(axes.(args)) || throw(DimensionMismatch())
Base.require_one_based_indexing(args...)
res = similar(first(args), Tuple{eltype.(args)...})
for i in eachindex(args...)
res[i] = getindex.(args, i)
end
res
end
eagerzip (generic function with 2 methods)
julia> eagerzip([1,2,3], [5,6,7])
3-element Vector{Tuple{Int64, Int64}}:
(1, 5)
(2, 6)
(3, 7)
julia> eagerzip(Int[], [])
Tuple{Int64, Any}[]
julia> eagerzip(Union{}[], [])
Tuple{Union{}, Any}[] # 1.9
ERROR: Tuple field type cannot be Union{} # 1.10
Stacktrace:
[1] eagerzip(::Vector{Union{}}, ::Vararg{AbstractArray})
@ Main ./REPL[201]:4
[2] top-level scope
@ REPL[204]:1 |
Looks effectively the same as the example in #52385 (comment) (except much longer)? |
Yep! It's the same, just with a bit more motivation. The first example in the OP was, by itself, a valid regression report IMO. |
Do you have an example of that? Arguably |
No, I don't have an example of this breaking anything "in the wild" that does not depend on internals. If nobody else has such an example either, then we can call it a minor change and be done with it, but it is technically breaking. |
Irrespective of semantic versioning, I don't see how it follows from any of the documented type rules that this should fail, so the error would be a special case, which isn't great from a user perspective. |
It follows from the rule that the intersection of Tuple{T} and Tuple{S} is empty if the intersection of T and S is empty. That is a rule that subtyping has always had, so that is why this wasn't a major breaking change, as it only sets out to align the rest of the system with the existing rule. As for being a special case, this implementation is equivalent to adding a lower bound on the typevar for Tuple, which is not a particularly special case. Although it does also happen to implement the oft-requested feature of being able to prohibit a type var from being exactly
OT, but every change, including bugfixes, are technically breaking. But semantic versioning is mostly about not changing the result beyond the limits of what was promised. I actually wonder if there is an argument to be made that most changes from semi-working -> error or error -> working is allowable by semantic versioning therefore, since in neither case does a working program get a different return value. |
Aren't there enough examples in this thread already? I'm not sure why "internals" are even brought up here, as Core.Compiler is completely unrelated to this issue. Julia docs say that
I've always interpreted that (and want to continue doing so...) that any code (not relying on internals/experimental) will continue to work. Not "only code that julia devs explicitly approve". Moreover, as @jariji also points out, this is not just a breaking change in the abstract – it breaks totally sensible behavior, not a weird historical quirk. Vector or AbstractVector with eltype == Union{} is a perfectly fine thing in Julia. It's also a natural thing to put such a vector into a StructArray. And this doesn't work anymore in 1.10. Nothing in the Tuple/NamedTuple documentation suggests that they only support a subset of Julia types. Like, I can create another type with any parameter that I want: julia> struct S{T}
t::T
end
julia> S{Union{}}
S{Union{}} but not Tuple or NamedTuple for some reason. |
For example, let's take using CairoMakie
scatter(Union{}[])
MethodError: plottype(::Vector{Union{}}) is ambiguous.
Candidates:
plottype(::AbstractVector{<:GeometryBasics.LineString})
@ Makie ~/.julia/packages/Makie/VRavR/src/interfaces.jl:217
plottype(::AbstractVector{<:GeometryBasics.AbstractPolygon})
@ Makie ~/.julia/packages/Makie/VRavR/src/interfaces.jl:222
Possible fix, define
plottype(::AbstractVector{Union{}}) Also, see all these functions: https://juliahub.com/ui/Search?q=AbstractVector{%3C:(Named)?Tuple}&type=code&r=true and more. |
Ah, that's great — and perhaps the best possible failure mode here. I see your this-is-a-regression path here and I respect the drum you're beating on, but I think it's worth noting how this is really on the edge of just-barely-working in multiple respects:
Of course, just-barely-working is still working, and none of the above points mean this isn't fundamentally a change in previously-working behaviors. How we best (potentially retroactively) communicate this change is a good question. But I'm inclined to wait for the dust to settle with #53516 and #53452 before figuring that step out. |
Why should the code using CairoMakie
scatter(Union{}[]) even work in the first place? If any, I would expect it to throw an error sooner rather than later, and in fact, it does throw an error in 1.9 with the same ambiguity error. It's reasonable that this code doesn't function, as it is analogous to As an example, the following code also throws errors in both 1.9 and 1.10: x = String[]
# ... fill x, but it can remain empty ...
points = StructArray((eachindex(x), x))
scatter(points) What makes |
It shouldn't, and was specifically crafted to produce an error message now, that'll probably be similar to what x = Union{}[]
# ... fill x, but it can remain empty ...
points = StructArray((eachindex(x), x))
scatter(points) will produce when those linked PRs are merged.
The same code with |
Indeed, the better link is https://juliahub.com/ui/Search?q=AbstractVector{%3C:(Named)?Tuple{&type=code&r=true. They won't probably work. |
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
Just checked - this regression appears to be present on 1.11 betas as well. Over time, I've encountered more and more instances of completely innocent code broken in 1.10 and 1.11b. Here are a few more examples of code working in 1.9 but broken in 1.10. # if file content is {"a": [1], "b": [2]}, works on all Julia versions
# if file content is {"a": [], "b": []}, broken on 1.10 and 1.11
J = JSON3.read("somefile.json")
A = StructArray((J[:a], J[:b]))
scatter(A) 2: # if "x=[1]\ny=[2]", works on all Julia versions
# if "x=[]\ny=[]", broken on 1.10 and 1.11
T = TOML.parsefile("somefile.toml")
A = StructArray((T["x"], T["y"]))
scatter(A) I hope these examples would serve to further strengthen the motivation to find way to fix this regression – and not to switch those specific packages to return I understand that this issue is nontrivial, but still keeping some hope that it can be fixed and these examples can run again in some future Julia version... |
It seems you should be filing these bugs with StructArrays, since that seems to be where all the issues you keep finding are in |
Why, can you elaborate a bit more? It doesn't seem to be using any internals, and not even the only popular package affected by this regression in Julia. With so many packages/functions using/returning arrays with |
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
return_type() is kinda broken in v1.10, see: JuliaLang/julia#52385 In any case Base.promote_op() is the official public API for this operation so we should use it anyway.
I've been running some package tests on the upcoming julia version (1.10rc) and noticed this error newly introduced there, compared to 1.9:
Not sure if introduced deliberately or as a side-effect of some other change, but it breaks perfectly working code. And I don't see it anywhere in
Tuple
docs that it shouldn't support all element types.The above is an MWE, and below is the simplified situation where I actually encountered it:
The text was updated successfully, but these errors were encountered: