Is missing
a DSL? Because missing == missing -> missing
which is not a Bool. Why is missing
special? Should interfaces allow for specifically having a different rule on one concrete type, or should the rule have to apply to all types?
I would argue that if we have to single out specific types in the rule for which the rule doesn’t apply to, we’ve got the rule wrong and should go back to the drawing board. We’ve always said Base isn’t special, we could do things in a package, but here is a case where MyMissings.jl
would not be possible by definition. Are we okay with losing that fundamental tenant of Julia for a simpler interface on this function?
It’s not entirely, it’s actually quite ambiguous.
size(A)
: Returns a tuple containing the dimensions of A
Are those dimensions supposed to be scalar? Or for example with a ragged array, should it be a tuple of vectors for the dimensions of each vector?
Base code generally assumes that size(A)
is a tuple of scalars, but it’s not actually in the interface definition.
getindex(A, i::Int): (if IndexLinear
) Linear scalar indexing
Should A[i]::T
where eltype(A)==T? That isn’t required in the definition of the interface, but much of Base code relies on the idea that scalar indexing always gives something of eltype(A)
. A classic type which violated this was always Tracker.jl’s TrackedArray, which stated eltype(A) == Float64
but a[i] == TrackedReal{Float64}
.
And for that matter, is eltype(::AbstractArray{T,N}) where {T,N} = T
supposed to be true? Because the interface does not specify how eltype
works.
getindex(A, I::Vararg{Int, N})
: (if IndexCartesian
, where N = ndims(A)
) N-dimensional scalar indexing
Is the identity getindex(A, Base.Cartesian.CartesianIndex(i)) == getindex(A, i)
expected to hold? Because that’s not specified.
setindex!(A, v, i::Int): (if IndexLinear
) Scalar indexed assignment
julia> a = rand(2)
2-element Vector{Float64}:
0.8135346986182869
0.7300081330807777
julia> a[1]= 2
2
Is it expected that setindex!(A, v::T, i::Int)::T
, i.e. that it also returns v
? Again there is some Base code in the AbstractArray that relies on this, but it’s not necessarily stated as something that should be true for all AbstractArrays
length(A): Default definition prod(size(A))
Is this expected to be true, or just a default? There are some codes (IIRC broadcast is one?) that assumes this is true.
similar(A)
: Return a mutable array with the same shape and element type
Is CuArray
considered mutable if allowscalar
is false? Because then A[1] = v
always errors. How do we define “mutable” here: that A[i] = v
is a valid non-erroring operation? Since if it’s the latter, similar(A::CuArray)::CuArray
is not correct.
Other functions aren’t even mentioned. Is zero(x::T)::T
an identity we expect for array types? The only case I know that violates that is Measurements.jl.
I highly encourage folks to think beyond their own immediate codes when thinking about interface definitions and think holistically about how it applies to other codes and the downstream effects. When doing so, you get some not necessarily an easy questions to answer, and its okay for us to document the current limitations of our knowledge and understand that we commonly get interface definitions wrong or ambiguous.