Adding a init(zeros: Int) constructor to RangeReplaceableCollections composed of AdditiveArithmetics

Now that AdditiveArithmetic is in Swift, what is the opinion on adding a constructor to RangeReplaceableCollection that would leverage this protocol.

extension RangeReplaceableCollection where Element : AdditiveArithmetic {
    public init(zeros count: Int) {
        self.init(repeating: .zero, count: count)
    }
}

I'ts quite useful.

Do you find this significantly clearer at the point of use than the existing repeating: init? It's not really obvious to me what the win is. (To be clear, I'm also not really opposed, but this seems like a very minor improvement at first glance).

4 Likes

It’s a minor improvement but if you are dealing with fixed size buffers, it’s a lot more ergonomic. Numpy and Julia both have something like this

https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.zeros.html

https://docs.julialang.org/en/v1/base/arrays/index.html#Base.zeros

This argues for putting a .zero or .zeros on your fixed-size buffer type, rather than generically on RRC.

Putting it on RRC mimics numpy semantics.

NumPy .zeros isn't available on arbitrary RangeReplaceableCollections; it's available on the concrete ndarray type.

(Again, to be clear, I'm basically neutral on this, but I'm trying to push you to make a compelling case for why it's needed on RRC specifically.)

It mimics the semantics of zeros where you pass in the size.

Where would you want to put it? You can’t put it on collection or mutable collection.

What type(s) do you actually use it with?

You mean element types or collection types?

Collection types, mainly, but element types would also be interesting here.

What I personally would like to see is a few well-motivated examples of this in use, with a comparison to what it would look like using the existing T(repeating: 0, count: n).

Also, this can be defined for all RRCs, but does the naming and functionality make sense for all of them, or should it be more narrowly constrained? Should Data have a .zeros(count:), for example?

w.r.t. element types I'm particularly interested in why you want to target AdditiveArithmetic instead of Numeric. Do you expect to use this initializer on, e.g. an Array of TensorFlow ShapedArrays?

Array or custom wrappers around split collections (similar to DSPSplitComplex). I might have more than just complex array, maybe I have a quaternion array (where each dimension is a single 1D array).

struct ComplexArray {
    var real: [Double]
    var imag: [Double]
    var split: DSPDoubleSplitComplex


}

Here's a minor refactoring I did yesterday trimmed whitespace + refactoring by adamnemecek · Pull Request #4 · SusanDoggie/Doggie · GitHub

I find it cleaner.

Also, this can be defined for all RRCs, but does the naming and functionality make sense for all of them, or should it be more narrowly constrained? Should Data have a .zeros(count:) , for example?

I think it make sense only as an extension on collections of AdditiveArithmetic.

w.r.t. element types I'm particularly interested in why you want to target AdditiveArithmetic instead of Numeric . Do you expect to use this initializer on, e.g. an Array of TensorFlow ShapedArray s?

AdditiveArithmetic makes the most sense. Would you be more in favor of this if this were on Numeric?

My first impulse would be to constrain it to Element: ExpressibleByIntegerLiteral, but I think one can make arguments for either Numeric or AdditiveArithmetic.

My question about RRC or something narrower is well explained by Data, which is an RRC with an element type of UInt8, so any of the element restrictions would let you do:

let x = Data(zeros: 15)

This is well defined, but not obviously useful or desired. It might make more sense to restrict the collection requirement further.

I feel like ExpressibleByIntegerLiteral is somewhat orthogonal to my needs. I find myself reaching for .zero quite a bit, it corresponds to C++ default constructible which is inspired by Alexander Stepanov's ideas, I believe.

I agree with Data, that is a somewhat strange consequence. It's the same as Data(count: ) fundamentally.

1 Like