[swift-evolution] Optional safe subscripting for arrays

Thorsten Seitz tseitz42 at icloud.com
Thu Feb 4 23:49:38 CST 2016


> Am 04.02.2016 um 21:24 schrieb Maximilian Hünenberger via swift-evolution <swift-evolution at swift.org>:
> 
> I just realized that the normal setter for failable lookups is very nice in case of assigning/swapping:
> 
>> extension Array {
>>     subscript(ifExists idx: Index) -> Element? {
>>         get { return (startIndex ..< endIndex) ~= idx ? self[idx] : nil }
>>         set { if (startIndex ..< endIndex) ~= idx && newValue != nil { self[idx] = newValue! } }
>>     }
>> }
> 
> 
>         // array[index1] is only set if both indexes are valid
>         array[ifExists: index1] = array[ifExists: index2] 
> 
> 
> if array is of type [Int?] and the special setter for optional Elements would have been added:
> 
> array[index1] would be set to "nil" if array[index2] is nil or index2 is not valid which is unfortunate.

Why is that unfortunate? Isn't it exactly what you specified in your assignment?

-Thorsten 


> - Maximilian
> 
>> Am 01.02.2016 um 22:34 schrieb davesweeris at mac.com:
>> 
>> Really, it should allow the nil to go through for any type that conforms to NilLiteralConvertible, not just Optionals. This code compiles on its own, but fails when you try to use it with an optional type:
>> extension Array {
>>     subscript(failableLookup idx: Index) -> Element? {
>>         get { return (startIndex ..< endIndex) ~= idx ? self[idx] : nil }
>>         set { if (startIndex ..< endIndex) ~= idx && newValue != nil { self[idx] = newValue! } }
>>     }
>> }
>> extension Array where Element: NilLiteralConvertible {
>>     subscript(failableLookup idx: Index) -> Element? {
>>         get { return (startIndex ..< endIndex) ~= idx ? self[idx] : nil }
>>         set {
>>             if (startIndex ..< endIndex) ~= idx {
>>                 switch newValue {
>>                 case .None:         self[idx] = nil
>>                 case .Some(let nv): self[idx] = nv
>>                 }
>>             }
>>         }
>>     }
>> }
>> var optarr: [Int?] = [1,2,3]
>> print(optarr)
>> optarr[failableLookup: 2] = nil // Ambiguous use of 'subscript(failableLookup:)'
>> 
>> I don’t understand why the compiler thinks it’s ambiguous, though. Int? is NilLiteralConvertible, so the compiler should send it to the more specialized subscript. At least I thought that was how it was supposed to work. It might be a compiler bug, though, because it’s quite confused… It claims its two choices are:
>> EquationTests.swift:29:9: Found this candidate
>> EquationTests.swift:29:9: Found this candidate
>> 
>> and that’s the same line that tripped the error in the first place: optarr[failableLookup: 2] = nil
>> 
>> Astute readers will notice two things: First, the two candidates are identical, so there’s actually only one candidate. Second, optarr[failableLookup: 2] = nil does not define a subscript function, ambiguous or otherwise.
>> 
>> Anyway, that’s as far as I got with it.
>> 
>> - Dave Sweeris
>> 
>>> On Feb 1, 2016, at 00:53, Rudolf Adamkovič via swift-evolution <swift-evolution at swift.org> wrote:
>>> 
>>> Hi Maximilian,
>>> 
>>> ah, I see. This is a show stopper then!
>>> 
>>> From what I imagine, this should not type-check:
>>> 
>>> var array = [1]
>>> array[ifExists: 0] = nil
>>> 
>>> … and this should set array[0] to nil:
>>> 
>>> var array: [Int?] = [1]
>>> array[ifExists: 0] = nil
>>> 
>>> Is it not possible to implement such setter in Swift?
>>> 
>>> R+
>>> 
>>>> On 1 Feb 2016, at 00:07, Maximilian Hünenberger <m.huenenberger at me.com> wrote:
>>>> 
>>>> The setter of the subscript should be:
>>>> 
>>>> set {
>>>>     if self.indices ~= index && newValue != nil {
>>>>         self[index] = newValue!
>>>>     }
>>>> }
>>>> 
>>>> Since "newValue" is of type "Element?".
>>>> 
>>>> It seems that this subscript could also be added to "CollectionType" and "MutableCollectionType".
>>>> 
>>>> The setter is weird because you can use an optional element:
>>>> 
>>>> var arr = [1]
>>>> // is valid but doesn't set the first element
>>>> arr[ifExists: 0] = nil
>>>> 
>>>> var arr2: [Int?] = [1]
>>>> arr2[ifExists: 0] = nil // changes nothing
>>>> arr2[ifExists: 0] = .Some(nil) // sets first element to nil : arr2 == [nil]
>>>> 
>>>> I don't know whether a setter should be added at all.
>>>> 
>>>> - Maximilian
>>>> 
>>>>> Am 31.01.2016 um 23:38 schrieb Rudolf Adamkovič via swift-evolution <swift-evolution at swift.org>:
>>>>> 
>>>>> All right, I put together a proposal:
>>>>> 
>>>>> https://github.com/salutis/swift-evolution/blob/master/proposals/XXXX-runtime-safe-array-subscripting.md
>>>>> 
>>>>> … and opened a PR:
>>>>> 
>>>>> https://github.com/apple/swift-evolution/pull/133
>>>>> 
>>>>> Let’s see how this goes.
>>>>> 
>>>>> R+
>>> 
>>> _______________________________________________
>>> swift-evolution mailing list
>>> swift-evolution at swift.org
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160205/782aa1e1/attachment.html>


More information about the swift-evolution mailing list