> Jamie, that diary of yours is great reading, btw. Thanks :)
> I'm pretty intrigued by the mystery of why the Julia version is 2x slower. Me too. I'm trying to systematically remove anything that might cause a difference, hence these fixed-length arrays. I want to be able to rule out the extra logic inside the Julia arrays as a cause. On 8 January 2016 at 20:12, Stefan Karpinski <ste...@karpinski.org> wrote: > 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 <ste...@karpinski.org> > 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 >> <julia-users@googlegroups.com> 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 <ste...@karpinski.org> >>> wrote: >>> > On Fri, Jan 8, 2016 at 1:12 PM, 'Jamie Brandon' via julia-users >>> > <julia-users@googlegroups.com> 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. >> >> >