FWIW, in the code I've written over the past few days in a new project, I've already used my local replace(_:with:) 6 times, and I just tried to use it a 7th from within the unit tests and got an error because the function is private >_<
It does turn out that nearly all of my particular uses for this function
end up replacing the value with `nil`, but there certainly are cases
where you'd want to replace a value with some other non-nil value (such
as the example I listed in the proposal about a spot where it might be
used in the stdlib).
-1 from me as well, for the same reason as Dave. In the Dictionary
case, doing a lookup and then a replacement isn't just more verbose;
it's actually less efficient. And I *still* wouldn't embed an
updateValue(_:forKey:) in a larger expression, for clarity's sake.
I'm not recommending that replace(_:with:) be used as a replacement for
Dictionary.updateValue(_:forKey:). I just found it interesting that it
has the exact same semantics (but, as you said, it's less performant).
Now, admittedly, if the assigned-to value were some complicated
expression (e.g. "view.frame.size.height"), the same performance
argument applies. But I still think I'd rather people just use a
temporary variable.
What do you mean? Using `replace(&view.frame.size.height, with:
newHeight)` is no less performant than doing things manually. The
Dictionary.updateValue(_:forKey:) case only differs because
accessing the subscript getter + setter has to look up the key
twice, but `&view.frame.size.height` doesn't have to look up
anything, it just has to read the property and then set it again,
which is exactly what you have to do if you want to read the old
value and assign a new one regardless of whether you're using a
function like replace(_:with:) to do it.
self.task?.cancel() self.task = nil
let oldValue = self.prop self.prop = newValue if let oldValue =
oldValue { // multi-line cleanup }
I'll admit the latter is not as nice, but it's definitely easier for
me to read.
Maybe for you. I find it much easier to read
if let oldValue = replace(&self.prop, with: nil) {
// ...
}
I recognize that many people will prefer the "manual" version, but I'm
sure many people will be like me and prefer the replace(_:with:)
version. I don't find the argument "I think it's easier to read <some
other way>" to be very compelling when it comes to stdlib or language
features, because we already have plenty of precedent for being able to
write the same thing in multiple ways. There's also a middle ground
here, if you just don't like embedding replace(_:with:) in a larger
construct, that still uses a temporary variable but allows you to avoid
duplicating complicated accessor expressions, e.g.
let oldValue =
replace(&self.sections[indexPath.section].rows[indexPath.row].data,
with: newValue)
if let oldValue = oldValue {
// ...
}
I've also found a lot of use for replace(_:with:) in `guard let`
expressions. There especially the "manual" version sucks because it
leaves a second variable lying around that you don't want anymore. In
the library I'm working on right now, I have a bunch of uses of
replace(_:with:) that look like
guard var request = replace(&self.request, with; nil) else {
writeResponse(Response(status: .InternalServerError, text: "Internal
server error: couldn't find active request"))
return
}
(yes, this is actually for an HTTP server written in Swift, which I'm
using to test networking code)
What's your opinion on the alternative <- operator (which IIRC Dave
suggested)? I much prefer replace(_:with:), and I don't think it
conflicts with stdlib conventions (it's no different than a mutating
method that returns a value, it just happens to be a function, but
there's not much of a difference between mutating methods and functions
that take an inout first parameter), but I'd rather have this
functionality as an <- operator than not have it at all. As an example,
the previous two code samples, when written with <-, would look like
let oldValue =
(self.sections[indexPath.section].rows[indexPath.row].data <- newValue)
if let oldValue = oldValue {
// ...
}
and
guard var request = (self.request <- nil) else {
writeResponse(Response(status: .InternalServerError, text: "Internal
server error: couldn't find active request"))
return
}
-Kevin Ballard
···
On Mon, Jan 11, 2016, at 01:22 PM, Jordan Rose wrote:
Jordan
On Jan 9, 2016, at 16:48, Kevin Ballard via swift-evolution <swift- >> evolution@swift.org> wrote:
Proposal PR submitted as
Proposal: Add replace(_:with:) function to the stdlib by lilyball · Pull Request #93 · apple/swift-evolution · GitHub
-Kevin Ballard
On Sun, Dec 13, 2015, at 02:21 PM, Kevin Ballard 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.
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?
-Kevin Ballard
_______________________________________________
swift-evolution mailing list swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution