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

Matthew Johnson matthew at anandabits.com
Sat May 28 21:59:07 CDT 2016


> On May 28, 2016, at 9:29 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
> 
>>> You are trying to call `mutating` methods on an *immutable* value, the return value of `withCopy`. Normally, the compiler would reject that.
>> 
>> You are right, there would need to be an exception for method cascades.  That might be a reasonable exception to make because we already know the temporary is not just the subject of mutation but also the result of the expression.  The method cascade just operates on the temporary in-place before being used in the surrounding expression or statement .
>> 
>>> Perhaps you could say that method cascades operate on a copy if the receiver is immutable
>> 
>> This isn’t necessary with the previously mentioned exception for allowing mutating method cascades on temporaries.
> 
> I don't understand what you mean by "temporary”.

I mean a return value.

> Are you saying that Swift should distinguish between things which could be mutable but don't happen to be (variables and subscripts), and things which cannot ever be mutable (functions and methods)?

No.  I’m saying that whether the return value temporary is immutable or mutable is something the language defines (not something the user declares anywhere).  The language rules for method cascades could be defined such that they create a contextual type environment that allows the return value temporary to be mutable to allow the method cascade to operate on the temporary in place before it is used in the surrounding expression.  This makes sense for method cascades because by definition they return the original value.  It does not make sense for arbitrary operations because they will not return the original value.

Applying mutating method cascades to temporary value could be very handy.  You have an expression that returns a value and mutate the result before storing it in a binding or returning it from your function.  You can do this by binding the result to an explicit temporary and giving it a name.  Allowing you to do it with method cascades on the implicit temporary is great syntactic sugar and a big argument for making them work well with value types, not just reference types IMO.


> Will this distinction hold up when we get `inout`-returning functions?

What I describe above would mean return values behave like a `var` argument used to (before they were removed) when the return value has a method cascade attached to it.  `inout` return values would work differently, writing back to the source storage.

> 
> Basically, what principled rule makes Swift treat this:
> 
> 	immutableVariable..mutatingMethod()
> 
> And this:
> 
> 	functionCall()..mutatingMethod()
> 
> Differently?

The rule is that it is safe to mutate a return value temporary copy in place without impacting the semantics of any code that relies on immutability.  The mutation happens prior to any code getting a chance to do anything with the value.  The mutation is really part of the expression itself and the method cascade provides a safe syntactic and semantic environment for allowing this mutation.

> 
> Or is the distinction between this:
> 
> 	immutableVariable..mutatingMethod()
> 
> And this:
> 
> 	mutableVariable..mutatingMethod()
> 
> And if so, how is that not going to lead to bugs when people move code around?

That distinction is absolutely critical.  The former is not allowed.  I am not suggesting allowing calling mutating methods on any `let` constants.  What I am saying is that the semantics of method cascades allow them to be safely used with return value temporaries even when they mutate the temporary.

-Matthew

> 
> -- 
> Brent Royal-Gordon
> Architechies
> 



More information about the swift-evolution mailing list