Jamie, that diary of yours is great reading, btw. I'm pretty intrigued by the mystery of why the Julia version is 2x slower. I would be very interested in getting to the bottom of that.
On Fri, Jan 8, 2016 at 2:37 PM, 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 > <https://github.com/JuliaLang/julia/issues/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. >> > >
