Open nsajko opened 7 months ago
Hey there, I found a probable solution to your problem. The purpose of use behind the syntax is incorrect. Using the block delimeters "{}" after the "Tuple" keyword is to define the datatype of each element one by one in the tuple rather than defining the datatype of the whole tuple.
when you use :
julia> Tuple{Int}([3, 4])
output : (3,)
This happens because an array is a mutable type container and therefore it somewhat ignores the element that doesn't have any datatype defined for it in the core.tuple function.
when you use:
julia> Tuple{Int}((3, 4))
ERROR: MethodError: Cannot `convert` an object of type Tuple{Int64,Int64} to an object of type Tuple{Int64}
This happens because a Tuple is a non-mutable type container and therefore doesn't ignore the element that doesn't have any datatype defined resulting it into throwing a MethodError for a faulty conversion.
Use the syntax like this instead:
julia> Tuple{Int, Int}((3, 4))
(3, 4)
julia> Tuple{Int, Int}([3, 4])
(3, 4)
julia> Tuple{Int, String}([3, "Aman"])
(3, "Aman")
this feature is present so that, if you used any other datatype in the tuple you could define it. It is said in the documentation "A tuple is a fixed-length container that can hold any values of different types, but cannot be modified"
Hope this helps :) . Documentation source here
Yeah, it would make sense to me that both should throw.
Related: https://github.com/JuliaLang/julia/issues/40495 Not quite a duplicate, because a resolution to this issue could be to allow the latter case.
I ran into this with NTuple
s (#52963, marked as a duplicate, thanks!) and I also agree that it should throw. Specifically, if the argument supports length
(iterator, ::AbstractVector
), length should match the number of elements in the Tuple
.
But what to do about infinite iterators (IsInfinite()
)? Should they just silently take the first N
elements, which is what currently happens? I think it would be cleaner to ask the user to Iterators.take
first, but that may be breaking.
IMO, an infinite iterator is longer than any tuple, so trying to construct any type of tuple from an infinite iterator would ideally throw.
Should the exception be ArgumentError
, DimensionMismatch
, InexactError
or a custom exception type?
AFAIK DimensionMismatch
is inter-argument mismatch. I would go with ArgumentError
and an informative message.
I agree about infinite objects throwing.
Analogous issue for NamedTuple
:
julia> (@NamedTuple{})(1:3)
NamedTuple()
julia> (@NamedTuple{})((10, 20))
ERROR: ArgumentError: Wrong number of arguments to named tuple constructor.
Stacktrace:
[1] @NamedTuple{}(args::Tuple{Int64, Int64})
@ Base ./namedtuple.jl:117
[2] top-level scope
@ REPL[2]:1
It doesn't seem right for
Tuple{Int}([3, 4])
to succeed (giving a truncated output, however), whileTuple{Int}((3, 4))
throws. IMO ideally both calls would throw, but I'm not sure if making that change would violate backwards compatibility.The problem with
Tuple{Int}([3, 4]) == (3,)
is that(3,) == [3, 4]
doesn't hold, in case it's not clear.This is similarly silly:
Tuple{}(1:10) == ()
.What does any relevant documentation on constructors say? EDIT: there's no relevant documentation as far as I can tell, so I guess it wouldn't be breaking to make
Tuple{Int}([3, 4])
andTuple{}(1:10)
throw.