[swift-evolution] Optional safe subscripting for arrays

Andrew Bennett cacoyi at gmail.com
Fri Feb 5 18:20:15 CST 2016


Has it been considered to just do this:

extension CollectionType {
    func at(index: Index) -> Generator.Element? {
        return self.indices ~= index ? self[index] : nil
    }
    func update(value: Generator.Element, atIndex: Index) -> Generator.Element?
{
        guard self.indices ~= index else { return nil }
        let oldValue = self[index]
        self[index] = value
        return oldValue
    }
}

Compare:
     let x = array[safe: index]
     let y = array.at(index)

It's more concise (for the getter), doesn't have to introduce new syntax,
works in current swift, and it doesn't have ambiguity about nil in a
subscript setter.

There's precedent for the update function in Dictionary:
    public mutating func updateValue(value: Value, forKey key: Key) ->
Value?

It would be a shame (and surprising/unsafe) to have to do this:

    array[safe: index] = .Some(nil) // stores nil
    array[safe: index] = nil        // deletes a value


On Sat, Feb 6, 2016 at 10:58 AM, Maximilian Hünenberger <
swift-evolution at swift.org> wrote:

> You are totally right. The return type is "Int??".
>
> My point was that if we allowed something like this (as suggested by Dave
> Sweeris I think):
>
>         var array: [Int?] = [1]
>         array[ifExists: 0] = nil
>
> To set the element at index 0 to nil instead of doing nothing.
> The next example would also set index 0 to nil even though the getter
> failed:
>
>          array[ifExists: 0] = array[ifExists: 1]
>
>
> - Maximilian
>
> Am 05.02.2016 um 10:20 schrieb Haravikk <swift-evolution at haravikk.me>:
>
>
> On 4 Feb 2016, at 20:24, Maximilian Hünenberger via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> 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.
>
>
> Wouldn’t the return type be Int?? in this case? It’s not as pretty to test
> for as a plain Int? but iirc you can still distinguish a return type of nil
> from an optional that happens to contain nil, which should allow you to
> tell the difference between a nil value and an invalid index, I just can’t
> recall how at the moment (as I design around cases like these like my life
> depends on it ;)
>
>
> _______________________________________________
> 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/20160206/8fc805f2/attachment.html>


More information about the swift-evolution mailing list