[swift-evolution] [Review] SE-0024 "Optional Value Setter `??=`"

Pyry Jahkola pyry.jahkola at iki.fi
Tue Feb 16 13:44:21 CST 2016


Below is my -1 on the proposal. But before that:

> On 16 Feb 2016, at 20:26, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I think a more expressive alternative approach to this problem would be to extend Dictionary with a `subscript(_:orDefault:)` member:
> 
> extension Dictionary {
>   subscript(key: Key, orDefault value: Value) -> Value { … }
> }


I think it's really a shortcoming in Dictionary's interface, where the general use case of updating a key in place usually asks for a lot of boilerplate. Thinking outside the box somewhat, one way to make all kinds of updates—"upserts", accumulating the value, but also removals—possible would be to extend Optional's interface with this simple addition:

extension Optional {
    public mutating func rewrap(@noescape transform: Wrapped? throws -> Wrapped?) rethrows {
        self = try transform(self)
    }
}

Conditionally inserting a key would then be:

var dict = [2: "two"]
dict[1].rewrap {$0 ?? "one"}
dict[2].rewrap {$0 ?? "deux"} // no-op
// dict == [2: "two", 1: "one"]

Maintaining a set of counters:

var counts = [String: Int]()
let increment: Int? -> Int? = {($0 ?? 0) + 1}
let decrement: Int? -> Int? = {
    let n = ($0 ?? 0) - 1
    return n == 0 ? nil : n
}
counts["Söze"].rewrap(increment)
counts["Kujan"].rewrap(increment)
counts["Kint"].rewrap(increment)
counts["Söze"].rewrap(decrement) // poof… he's gone
counts["Kint"].rewrap(increment)
// counts == ["Kujan": 1, "Kint": 2]

Originally I thought calling it simply update, however rewrap has a closer correspondence to Optional's Wrapped, and might thus be less ambiguous.

— — —

What comes to the proposal then…

> What is your evaluation of the proposal?

-1.

> Is the problem being addressed significant enough to warrant a change to Swift?

I don't think this is the problem to be addressed. The issue here is that even after the update, the result is still an optional, so there's no promise that it'll have a non-nil value. I have a feeling guard could be used in most of these use cases for a better design. And lazy loading or set-once properties might help a bit too.

> Does this proposal fit well with the feel and direction of Swift?

It's true that we have the in-place mutating op= variant of many operators op which happen to return the same type as their first argument. However, I see ?? as two overloads ((T?, T) -> T and (T?, T?) -> T?), the one returning non-optional being the more official one which is somewhat against the current practice.

I also feel the use of this operator would leave too many T? hanging around where T would do.

> If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

Ruby comes in mind. Ruby is different in that it does nothing to prevent the Billion Dollar Mistake that they coincidentally call nil.

> How much effort did you put into your review? A glance, a quick reading, or an in-depth study?


I've followed the conversation for a couple of days and read through the proposal quickly. I've thought about the problem domain a lot before though.

— Pyry Jahkola
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160216/3628014e/attachment.html>


More information about the swift-evolution mailing list