[swift-evolution] [Pitch] Circling back to `with`

Brent Royal-Gordon brent at architechies.com
Wed May 25 16:28:19 CDT 2016

> 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
			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

More information about the swift-evolution mailing list