[swift-evolution] Proposal: Add replace(_:with:) function to the stdlib

ilya ilya.nikokoshev at gmail.com
Mon Dec 14 01:36:45 CST 2015


That's a useful pattern, but the implementation above creates a function
that has both a return value and a side effect, which is likely to be
unexpected for many readers.

public func replace<T>(inout a: T?, with b: T?, andCleanOldValue
clean:T->()) { ... }

replace(&prop, with: newValue) { oldValue in
    oldValue.clean()
}

As a bonus one can automatically unwrap nil.

Although in real life I tend to move this logic to property accessors, e.g.

// Currently executing task. This property manages task state.

var task: NSURLSessionTask? {
  willSet { task?.cancel() }
  didSet { task?.resume() }
}

On Mon, Dec 14, 2015 at 7:59 AM, Dave Abrahams via swift-evolution <
swift-evolution at swift.org> wrote:

>
> On Dec 13, 2015, at 2:21 PM, Kevin Ballard via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> A function I find myself defining in a lot of my projects looks like the
> following:
>
> /// Replace the value of `a` with `b` and return the old value.
> public func replace<T>(inout a: T, with b: T) -> T {
>     var value = b
>     swap(&a, &value)
>     return value
> }
>
> This is a pretty simple function, and useful in a wide variety of
> circumstances, so I'd love to get it into the standard library. It doesn't
> actually enable any behavior that wasn't previously possible, but it does
> shrink some common code patterns, and I find the shorter code easier to
> read.
>
> An example of a place where I use it often is in replacing an optional
> property with a new value (or with nil) and cleaning up the previous value.
> Assuming a property like
>
> var task: NSURLSessionTask?
>
> This replaces
>
> if let task = self.task {
>     task.cancel()
> }
> task = nil
>
> with
>
> replace(&task, with: nil)?.cancel()
>
> Or sometimes I use it like
>
> if let value = replace(&prop, with: newValue) {
>     // multi-line cleanup
> }
>
> This is particularly nice if it's a COW value that I want to mutate, as it
> means I don't have to worry about getting unwanted copies due to the
> property still holding the old value while I muck with it.
>
>
> This is a generalization of the postincrement pattern (mutate a value and
> return the original) and given that we're moving away from that I'm not
> sure it's something we want to enshrine in the standard library. That said,
> here's a question: looking at your use cases, how many of them are using
> something other than nil (or some moral equivalent) as the second
> argument?  If this is effectively a non-destructive move in nearly all
> cases, I'd rather support that more directly.
>
> If cases other than "nondestructive move" are common *enough*, I'd
> consider something like this syntax instead:
>
>   (task <- nil).cancel()
>
> But I strongly suspect this isn't a common enough pattern to warrant
> introducing an operator.
>
> Question: For trivial backwards-compatible API changes like this, does a
> proposal PR need to be submitted to the swift-evolution repo, or is
> discussion on this ML sufficient before submitting a patch?
>
>
> A proposal is needed for all new/changed API.
>
> -Dave
>
> _______________________________________________
> 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/20151214/b48773bf/attachment.html>


More information about the swift-evolution mailing list