Skip to content

Latest commit

 

History

History
128 lines (81 loc) · 5.39 KB

File metadata and controls

128 lines (81 loc) · 5.39 KB

ZeroDimensionalArrays

Build Status Package version Package dependencies Coverage PkgEval Aqua

A tiny software package for the Julia programming language, providing zero-dimensional array types. Ref-killer.

Exports these zero-dimensional subtypes of AbstractArray, differing on topics such as mutability and identity:

  • ZeroDimArray

  • Box

  • BoxConst

  • ZeroDimArrayInTypeParameter

See their doc strings for more info!

Any zero-dimensional array is an iterator containing exactly one element (this follows from the zero-dimensional shape). Ref, too, is a zero-dimensional iterator, however it's not an array. Even though Ref supports being indexed like a zero-dimensional array is commonly indexed, without an index: x[].

The motivation for creating this package is:

  • To prevent the frequent confusion regarding Ref vs Base.RefValue by offering a replacement that makes Ref unnecessary in many use cases. Previous discussion:

  • To provide "mutable wrapper" functionality:

    • Box can be a good choice. Examples:

      • make a const binding that's mutable:

        const some_const_binding = Box(0.2)
      • make a field within an immutable struct mutable (warning: it's usually more efficient to change the entire struct into a mutable struct)

        struct SomeImmutableType
            immutable_bool::Bool
            immutable_float::Float64
            mutable_int::Box{Int}
        end
    • previous discussion:

  • To provide a boxing feature, for example for data deduplication to avoid excessive memory use. Either Box or BoxConst might be a good choice here, depending on whether mutability is desired. Compare:

    • julia> large_data = ntuple(identity, 8)
      (1, 2, 3, 4, 5, 6, 7, 8)
      
      julia> for _  1:4
                 large_data = (large_data, large_data)
             end
      
      julia> Base.summarysize(large_data)
      1024
      
      julia> Base.summarysize([large_data for _  1:1000])  # duplicates `large_data` a thousand times
      1024040
      
      julia> using ZeroDimensionalArrays
      
      julia> large_data_reference = Box(large_data);
      
      julia> Base.summarysize([large_data_reference for _  1:1000])  # `large_data` isn't stored inline
      9064
  • To provide a wrapper type for treating a value as a scalar in broadcasting:

    • ZeroDimArray can be a good choice:

      julia> using ZeroDimensionalArrays
      
      julia> isa.([1,2,3], [Array, Dict, Int])
      3-element BitVector:
       0
       0
       1
      
      julia> isa.(ZeroDimArray([1,2,3]), [Array, Dict, Int])  # now escape the vector from broadcasting using `ZeroDimArray`
      3-element BitVector:
       1
       0
       0

      The other types, Box or BoxConst would work for this use case, too, as would any zero-dimensional array, but ZeroDimArray is more likely to have zero cost for performance.

    • previous discussion regarding Ref:

Comparison with other potential solutions

  • Zero-dimensional Array:

    • fill(x), creating a zero-dimensional Array containing x as its element, is often used instead of Ref(x).

    • Array{T, 0} where {T} is very similar to Box, albeit less efficient. The inefficiency is due to the fact that the implementation of Array supports resizeability (even though that's currently only available to users in the one-dimensional case of Vector), implying extra indirection, leading to extra pointer dereferences and extra allocation.

  • FixedSizeArrays.jl:

    • Less heavy than Array, but still may be less efficient than Box.
  • FillArrays.jl:

    • Zero-dimensional Fill, constructible with Fill(x), is equivalent to ZeroDimArray.