[Idea] NonEmptyArray

I've come across multiple cases, where you simply know the array is never empty and hence the optionality on first, last and behavior of a few other members is slightly different. Also, there are cases where you want to declare that you shouldn't pass an empty array e.g. into an initializer.

I was wondering whether Swift could have a specialized NonEmptyArray that could be used throughout the stdlib - e.g. String.components(separatedBy:) would return NonEmptyArray.

Thoughts?

1 Like

I've tried to make such a type a few times... The struct itself isn't hard ("var first:T; var tail:[T]"), but I never could figure out how to make `NonEmptyArray` conform to `ExpressibleByArrayLiteral` (because the protocol doesn't allow for failable inits) without just crashing if there wasn't at least one element.

Anyway, I'm not opposed to adding it, as long as there's a non-crashy way to assign array literals to them.

- Dave Sweeris

···

On Jan 17, 2017, at 03:40, Charlie Monroe via swift-evolution <swift-evolution@swift.org> wrote:

I've come across multiple cases, where you simply know the array is never empty and hence the optionality on first, last and behavior of a few other members is slightly different. Also, there are cases where you want to declare that you shouldn't pass an empty array e.g. into an initializer.

I was wondering whether Swift could have a specialized NonEmptyArray that could be used throughout the stdlib - e.g. String.components(separatedBy:) would return NonEmptyArray.

Thoughts?

Is a failable initialiser the way to go? Could we do something with some kind of compiler attribute?

For example:

  struct MyNonEmptyArray<E> : ExpressibleByArrayLiteral {
    typealias Element = E
    @minParameters(1) init(arrayLiteral:Element…) { … }
  }

In this case the @minParameters attribute tells the compiler how many parameters must be present in direct calls to this method, however, for cases where this isn't possible to check it would still trigger a runtime error, but that would only be for more unusual cases like trying to handle this type as a generic ExpressibleByArrayLiteral.

Just trying to think whether there might be a more flexible way to do this, as if you can support arrays with at least 1 element, then why not 2 or 3 etc.? In the worst case this would just become a runtime error, which is how we would have to handle right now, but in more common cases the compiler can give an error right away.

···

On 17 Jan 2017, at 09:57, David Sweeris via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 17, 2017, at 03:40, Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've come across multiple cases, where you simply know the array is never empty and hence the optionality on first, last and behavior of a few other members is slightly different. Also, there are cases where you want to declare that you shouldn't pass an empty array e.g. into an initializer.

I was wondering whether Swift could have a specialized NonEmptyArray that could be used throughout the stdlib - e.g. String.components(separatedBy:) would return NonEmptyArray.

Thoughts?

I've tried to make such a type a few times... The struct itself isn't hard ("var first:T; var tail:[T]"), but I never could figure out how to make `NonEmptyArray` conform to `ExpressibleByArrayLiteral` (because the protocol doesn't allow for failable inits) without just crashing if there wasn't at least one element.

Anyway, I'm not opposed to adding it, as long as there's a non-crashy way to assign array literals to them.

Ad-hoc compiler attributes won't go far. What about arrays with even number of elements? Sorted arrays? Reverse-sorted arrays?

I think support for such feature has to wait for a macro system. Then, the topic of non-empty arrays will come back, stronger than ever.

Gwendal

···

Le 17 janv. 2017 Ă  14:14, Haravikk via swift-evolution <swift-evolution@swift.org> a Ă©crit :

On 17 Jan 2017, at 09:57, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Jan 17, 2017, at 03:40, Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I've come across multiple cases, where you simply know the array is never empty and hence the optionality on first, last and behavior of a few other members is slightly different. Also, there are cases where you want to declare that you shouldn't pass an empty array e.g. into an initializer.

I was wondering whether Swift could have a specialized NonEmptyArray that could be used throughout the stdlib - e.g. String.components(separatedBy:) would return NonEmptyArray.

Thoughts?

I've tried to make such a type a few times... The struct itself isn't hard ("var first:T; var tail:[T]"), but I never could figure out how to make `NonEmptyArray` conform to `ExpressibleByArrayLiteral` (because the protocol doesn't allow for failable inits) without just crashing if there wasn't at least one element.

Anyway, I'm not opposed to adding it, as long as there's a non-crashy way to assign array literals to them.

Is a failable initialiser the way to go? Could we do something with some kind of compiler attribute?

For example:

  struct MyNonEmptyArray<E> : ExpressibleByArrayLiteral {
    typealias Element = E
    @minParameters(1) init(arrayLiteral:Element…) { … }
  }

In this case the @minParameters attribute tells the compiler how many parameters must be present in direct calls to this method, however, for cases where this isn't possible to check it would still trigger a runtime error, but that would only be for more unusual cases like trying to handle this type as a generic ExpressibleByArrayLiteral.

Just trying to think whether there might be a more flexible way to do this, as if you can support arrays with at least 1 element, then why not 2 or 3 etc.? In the worst case this would just become a runtime error, which is how we would have to handle right now, but in more common cases the compiler can give an error right away.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

I've come across multiple cases, where you simply know the array is never empty and hence the optionality on first, last and behavior of a few other members is slightly different. Also, there are cases where you want to declare that you shouldn't pass an empty array e.g. into an initializer.

I was wondering whether Swift could have a specialized NonEmptyArray that could be used throughout the stdlib - e.g. String.components(separatedBy:) would return NonEmptyArray.

Thoughts?

I've tried to make such a type a few times... The struct itself isn't hard ("var first:T; var tail:[T]"), but I never could figure out how to make `NonEmptyArray` conform to `ExpressibleByArrayLiteral` (because the protocol doesn't allow for failable inits) without just crashing if there wasn't at least one element.

Anyway, I'm not opposed to adding it, as long as there's a non-crashy way to assign array literals to them.

Is a failable initialiser the way to go? Could we do something with some kind of compiler attribute?

For example:

  struct MyNonEmptyArray<E> : ExpressibleByArrayLiteral {
    typealias Element = E
    @minParameters(1) init(arrayLiteral:Element…) { … }
  }

In this case the @minParameters attribute tells the compiler how many parameters must be present in direct calls to this method, however, for cases where this isn't possible to check it would still trigger a runtime error, but that would only be for more unusual cases like trying to handle this type as a generic ExpressibleByArrayLiteral.

I personally agree that I wouldn't make it failable. The compiler should be able to detect making of a NonEmptyArray with 0 literals and there's nothing against marking an empty initializer as @available(*, unavailable) - it will conform to the necessary protocols, but you won't be able to invoke it.

Just trying to think whether there might be a more flexible way to do this, as if you can support arrays with at least 1 element, then why not 2 or 3 etc.? In the worst case this would just become a runtime error, which is how we would have to handle right now, but in more common cases the compiler can give an error right away.

I have thought about this, but to be honest, even math-wise, an empty set (or array) is a special case... So I began wondering whether it would make sense to add something that explicitely states that the array is not empty. If I'm not mistaken, since it would change the return type of a few stdlib methods, the time to discuss it would be now...

It's true that you can handle this with assertions, as I've noted, was just wondering if there's a better way...

···

On Jan 17, 2017, at 2:14 PM, Haravikk <swift-evolution@haravikk.me> wrote:

On 17 Jan 2017, at 09:57, David Sweeris via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
On Jan 17, 2017, at 03:40, Charlie Monroe via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

100% agree with this proposal

Like we can have values that are optionals and others that not, ensuring that a value is there, arrays/collections must provide a non-optionally-populated or not-empty-ensured version.

I think is a common mathematicall condition to have "a non empty set" a "1:n relation" (but 0:n) etc.

Maybe it is tricky to figure out a layer over existing types to accomplish it easely.

Thinking about it, what really is a an Optional array? If there is not array (.none) you can create an empty one, and nothing changes. No content, no values are changed, you can go on.

And in the other side, if there's an array value there (.some), what matters in case it is empty? If it's empty you can do nothing with it, only apply operations that will really do nothing, beacuse there is no data. The same you could do in case there was .none array.

It make more sense when working with immutable data structures, in a declarative style. But, in generall it would worked well to use Optional over array types to address it (with an aditional method to ensure the array is there emptyOrPopulated whenever it's needed).

Since we have already resurrected this old thread, pointfreeco/swift-nonempty is a non-empty collection implemented as a third-party library. I haven’t used it, so I can’t comment about the pros and cons, but I guess any implementation is welcome to prototype the idea.

1 Like