> The fact that you can write NTuple{Any,Int} at all seems to be a bug.
Well, that explains why it had confusing behaviour :)
Using a typealias / dropping N doesn't seem to prevent specialization.
As a (somewhat pointless) example:
julia> type NArray{T,N}
contents::NTuple{N,T}
end
julia> Base.length{T}(x::NArray{T}) = length(x.contents)
mylen (generic function with 1 method)
julia> @code_native mylen(NArray((1,2,3)))
.text
Filename: none
Source line: 1
pushq %rbp
movq %rsp, %rbp
movl $3, %eax
Source line: 1
popq %rbp
ret
Even my attempts to hide it behind ANY are defeated (maybe by inlining?):
julia> Base.length{T}(x::NArray{T}) = mylength(x.contents, T)
length (generic function with 59 methods)
julia> mylength{T}(x::ANY, ::Type{T}) = length(x)
mylength (generic function with 1 method)
julia> @code_native length(NArray((1,2,3)))
.text
Filename: none
Source line: 1
pushq %rbp
movq %rsp, %rbp
movl $3, %eax
Source line: 1
popq %rbp
ret
Hmmm, perhaps I need to erase the type entirely, like hide it behind a Ref.
On 8 January 2016 at 19:37, Stefan Karpinski <[email protected]> wrote:
> Setting the fix-size mutable array thing aside, one thing that's glaringly
> wrong about these examples is that even if parametric types were covariant,
> this wouldn't make sense because 4 <: Any is never going to be true because
> 4 is not a type, it's a value:
>
> julia> 4 <: Any
> ERROR: TypeError: subtype: expected Type{T}, got Int64
> in eval at ./boot.jl:265
>
>
> The fact that you can write NTuple{Any,Int} at all seems to be a bug:
>
> julia> NTuple{Any,Int}
> ERROR: TypeError: NTuple: in parameter 1, expected Int64, got Type{Any}
> in eval at ./boot.jl:265
>
> julia> NTuple{ANY,Int}
> NTuple{ANY,Int64}
>
>
> I'm not sure what's going on with that, but I've filed an issue: #14607.
>
> On Fri, Jan 8, 2016 at 2:00 PM, 'Jamie Brandon' via julia-users
> <[email protected]> wrote:
>>
>> > If you don't want to specialize on the length of the array why include
>> > it in the type at all?
>>
>> I built a HAMT using normal Julia arrays and found that the extra size
>> and extra pointer hop made them around 2x larger and 4x slower than
>> the totally naive Rust equivalent. (If you want excruciating amounts
>> of detail, see
>> https://github.com/jamii/imp/blob/master/diary.md#baseline).
>> I'm now trying to implement fixed-length mutable arrays, much like
>> https://github.com/JuliaLang/julia/issues/12447
>>
>> type NArray{N,T}
>> contents::NTuple{N,T}
>> end
>>
>> If I take the size out it will just box the ntuple.
>>
>> I can work around the constructor. I'm more interested in
>> understanding how ANY affects variance so I know in what cases I can
>> use it:
>>
>> julia> NTuple{4, Int64} <: NTuple{ANY, Int64}
>> true
>> julia> Hamt.NArray{4,Int64} <: Hamt.NArray{ANY,Int64}
>> true
>>
>> julia> Type{NTuple{4,Int64}} <: Type{NTuple{ANY,Int64}}
>> true
>> julia> Type{Hamt.NArray{4,Int64}} <: Type{Hamt.NArray{ANY,Int64}}
>> false
>>
>> julia> Tuple{NTuple{4,Int64}} <: Tuple{NTuple{ANY,Int64}}
>> true
>> julia> Tuple{Hamt.NArray{4,Int64}} <: Tuple{Hamt.NArray{ANY,Int64}}
>> true
>>
>> julia> Vector{NTuple{4,Int64}} <: Vector{NTuple{ANY,Int64}}
>> true
>> julia> Vector{Hamt.NArray{4,Int64}} <: Vector{Hamt.NArray{ANY,Int64}}
>> false
>>
>> >> julia> arr = Hamt.NArray{10, Int64}()
>> >> ERROR: MethodError: `convert` has no method matching
>> >> convert(::Type{Hamt.NArray{10,Int64}})
>> >> This may have arisen from a call to the constructor
>> >> Hamt.NArray{10,Int64}(...),
>> >> since type constructors fall back to convert methods.
>> >> Closest candidates are:
>> >> convert{T}(::Type{T}, ::T)
>> >> Hamt.NArray{N,T}(, ::Any)
>> >> call{T}(::Type{T}, ::Any)
>> >> in call at essentials.jl:57
>> >>
>> >> julia> arr = Hamt.Array{Int64}()
>> >> ERROR: argument is an abstract type; size is indeterminate
>> >> in call at /home/jamie/code/imp/src/Hamt.jl:23
>> >>
>> >> I have this doing exactly what I want with the bare types eg:
>> >>
>> >> Base.getindex{T}(narray::NArray{ANY,T}, ix::Integer)
>> >>
>> >> I'm just struggling getting the same behaviour from the constructor
>> >> because of the way Type varies.
>> >
>> >
>> > So one issue here is that using ANY like this doesn't mean what you want
>> > it
>> > to – it means that the first parameter of NArray is the literal value
>> > ANY.
>> > So when you write call{T}(t::Type{Array{T}}) it literally means
>> > call{T}(t::Type{NArray{ANY,T}}) – which is not what you want. Instead,
>> > you'd
>> > want a typealias like this:
>> >
>> > typealias TArray{T,n} NArray{n,T}
>> >
>> > call{T}(t::Type{TArray{T}}) = ...
>> >
>> >
>> > But I'm getting a little confused about what you're trying to accomplish
>> > with that type parameter for the number of elements in the first place.
>>
>> On 8 January 2016 at 18:23, Stefan Karpinski <[email protected]> wrote:
>> > On Fri, Jan 8, 2016 at 1:12 PM, 'Jamie Brandon' via julia-users
>> > <[email protected]> wrote:
>> >>
>> >> > Yes, it's like any other parametric type that way.
>> >>
>> >> Are tuples treated specially? eg:
>> >
>> >
>> > Yes, tuples types are covariant while everything else is invariant.
>> >
>> >> > ANY is a hack to let you hint to the compiler that it should not
>> >> > specialize a method on an argument.
>> >>
>> >> That's exactly what I'm trying to achieve. I really don't want my
>> >> array functions to specialize on the length of the array :)
>> >
>> >
>> > If you don't want to specialize on the length of the array why include
>> > it in
>> > the type at all?
>> >
>> >>
>> >> > Currently you have to use a typealias...
>> >>
>> >> I'm not having any luck with this.
>> >>
>> >> typealias Array{T} NArray{ANY,T}
>> >>
>> >> call{T}(t::Type{Array{T}}) = begin
>> >> tp = pointer_from_objref(t)
>> >> size = sizeof(t)
>> >> ...
>> >> end
>> >>
>> >> julia> arr = Hamt.NArray{10, Int64}()
>> >> ERROR: MethodError: `convert` has no method matching
>> >> convert(::Type{Hamt.NArray{10,Int64}})
>> >> This may have arisen from a call to the constructor
>> >> Hamt.NArray{10,Int64}(...),
>> >> since type constructors fall back to convert methods.
>> >> Closest candidates are:
>> >> convert{T}(::Type{T}, ::T)
>> >> Hamt.NArray{N,T}(, ::Any)
>> >> call{T}(::Type{T}, ::Any)
>> >> in call at essentials.jl:57
>> >>
>> >> julia> arr = Hamt.Array{Int64}()
>> >> ERROR: argument is an abstract type; size is indeterminate
>> >> in call at /home/jamie/code/imp/src/Hamt.jl:23
>> >>
>> >> I have this doing exactly what I want with the bare types eg:
>> >>
>> >> Base.getindex{T}(narray::NArray{ANY,T}, ix::Integer)
>> >>
>> >> I'm just struggling getting the same behaviour from the constructor
>> >> because of the way Type varies.
>> >
>> >
>> > So one issue here is that using ANY like this doesn't mean what you want
>> > it
>> > to – it means that the first parameter of NArray is the literal value
>> > ANY.
>> > So when you write call{T}(t::Type{Array{T}}) it literally means
>> > call{T}(t::Type{NArray{ANY,T}}) – which is not what you want. Instead,
>> > you'd
>> > want a typealias like this:
>> >
>> > typealias TArray{T,n} NArray{n,T}
>> >
>> > call{T}(t::Type{TArray{T}}) = ...
>> >
>> >
>> > But I'm getting a little confused about what you're trying to accomplish
>> > with that type parameter for the number of elements in the first place.
>
>