NonEmpty<NonEmpty<C>>
doesn't mean the collection has at least 2 values
#45
Replies: 4 comments 5 replies
-
Originally, struct NonEmpty<C: Collection>: Collection {
var head: C.Element
var tail: C
} This was changed in #26 for performance, bug-avoidance, and added functionality, to the following: struct NonEmpty<C: Collection>: Collection {
var rawValue: C
// ... validated non-empty via init
} But if I'm understanding correctly, your suggestion is something more like the following? struct NonEmpty<C: Collection>: Collection {
var head: C.Element
var tail: Slice<C>
} This is definitely interesting! In addition to the functionality you mention, it also avoids some of the issues we aimed to address in #26. The main gotchas I can think of is that the value of |
Beta Was this translation helpful? Give feedback.
-
I also thought about other features that could be added at the same time. Basically, What we could do is something like this (pseudo Swift code) extension NonEmpty<NonEmpty<C>> {
var second: C.Element { tail.first }
}
extension NonEmpty<NonEmpty<NonEmpty<C>>> {
var third: C.Element { tail.second }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>> {
var fourth: C.Element { tail.third }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>> {
var fifth: C.Element { tail.fourth }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>> {
var sixth: C.Element { tail.fifth }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>> {
var seventh: C.Element { tail.sixth }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>>> {
var eighth: C.Element { tail.seventh }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>>>> {
var ninth: C.Element { tail.eighth }
}
extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>>>>> {
var tenth: C.Element { tail.ninth }
} Now we can safely access indexes 1 to 10, but not above. I had an idea though (still pseudo Swift code): extension NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>>>>>> {
var drop10: NonEmpty<C> { get }
} This way, we can do |
Beta Was this translation helpful? Give feedback.
-
Another problem I stumbled upon is the actual failing initializer ( let myOptionalCollectionWithAtLeast4Elements = NonEmpty(rawValue: elements)
.flatMap(NonEmpty.init(rawValue:))
.flatMap(NonEmpty.init(rawValue:))
.flatMap(NonEmpty.init(rawValue:)) I don't know why you chose The throwing initializer would allow avoiding optional chaining, like so: let myOptionalCollectionWithAtLeast4Elements = try? NonEmpty(NonEmpty(NonEmpty(NonEmpty(elements)))) |
Beta Was this translation helpful? Give feedback.
-
If you accept my previous two propositions (about typealias AtLeast2<C> = NonEmpty<NonEmpty<C>>
extension AtLeast2 {
var second: C.Element { get }
}
typealias AtLeast3<C> = NonEmpty<NonEmpty<NonEmpty<C>>>
extension AtLeast3 {
var third: C.Element { get }
}
// ...
typealias AtLeast10<C> = NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<NonEmpty<C>>>>>>>>>>
extension AtLeast10 {
var tenth: C.Element { get }
}
extension NonEmpty {
static func atLeast2<C>(_ c: C) -> AtLeast2<C>
static func atLeast3<C>(_ c: C) -> AtLeast3<C>
// ...
static func atLeast10<C>(_ c: C) -> AtLeast10<C>
}
This would remove the necessity to use It would also also replace Finally, like |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I really like the safety of
NonEmpty
. I am writing a fully type-safe geographical library, also providing GeoJSON mapping, and I need to store arrays that have at least four values for example (see RFC 7946, section 3.1.6 for example).I thought I'd use
NonEmpty<NonEmpty<NonEmpty<NonEmpty<[MyType]>>>>
, but I was surprised to se it's not how the library works. NonEmpty.swift#L9-L10 shows that the collection is stored as-is, not cut into a head value and a tailSlice
.Is it a conscious choice? Wouldn't it be semantically better to make
NonEmpty
behave as I thought?Beta Was this translation helpful? Give feedback.
All reactions