> I'm unfamiliar with `tap` but it looks
> similar to method cascading, which is on hold for Swift 4.

I *am* familiar with `tap`. It's basically `with(_:update:)`, but as a method 
and not `inout`, which usually doesn't matter for Ruby since everything is an 
object in that language. Typically, though, `tap` is not used to mutate at all; 
instead, it's used to access an intermediate value in a method chain, for 
instance to log it.

I am very much in favor of `with(_:update:)`. Fundamentally, it is an operation 
which applies a mutating method to a copy to make it nonmutating; this seems 
like a very useful thing to have in the standard library. I could easily 
imagine the standard library itself using it to reduce boilerplate. For 
instance, if the FloatingPoint protocol currently offers this:

        extension FloatingPoint {
                func adding(_ other: Self) -> Self {
                        var selfCopy = self
                        selfCopy.add(other)
                        return selfCopy
                }
        }

`with(_:update:)` would allow us to instead shorten it to:

        extension FloatingPoint {
                func adding(_ other: Self) -> Self {
                        return with(self) { $0.add(other) }
                }
        }

I also think this is fairly future-proof. Many of the future proposals in this 
area, like `self` shadowing, will interoperate with `with(_:update:)` 
perfectly. Others, like method cascading, would supplant it in some uses, but 
still leave many others (like the `FloatingPoint` example above) untouched. But 
even without any other changes at all, this is a good, useful thing to have in 
the language.

I don't agree with those who argue that this should be a method. When Swift 
offers an operation on any instance, it very rarely does so as a member (and 
`dynamicType`, one of the few exceptions, seems to be going away); instead, it 
uses either a free function or an initializer on the result type, depending on 
the circumstance. A `with(_:update:)` free function thus matches a broader 
pattern in the language.

There are also implementation reasons not to go the method route. A free 
function can be trivially implemented in the standard library with no language 
changes at all. A method, on the other hand, would either have to be 
implemented as a keyword specially recognized by the parser and handled by the 
language (as `dynamicType` is), or would require us to allow the currently 
forbidden extension of `Any`. Either of these is vastly more difficult and 
risky than using a free function.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to