[swift-evolution] Class mutation model and value-constrained protocols
Dave Abrahams
dabrahams at apple.com
Tue Jul 5 16:11:38 CDT 2016
on Tue Jul 05 2016, Jonathan Hull <jhull-AT-gbis.com> wrote:
> Comments inline
>> A “mutating” keyword on a protocol method is only useful if
>> you can reason about the mutation in generic code.
>>
>> protocol P {
>> mutating func changeMe()
>> func noChange() -> Int
>> }
>>
>> In other words, given x of some type conforming to P, it should be
>> meaningful that this is an error:
>>
>> func f<T: P>(x: T) {
>> immutable.changeMe() // can't mutate a "let" binding
>> }
>
> Agreed.
>
>> which means that you shouldn't be able to get around that meaning by
>> writing:
>>
>> func g<T: P>(x: T) {
>> var mutable = x
>> mutable.changeMe() // OK
>> }
> Now I am confused. Why should this be illegal? Doesn’t this work with structs right now? (you are working on a mutable copy)
What I meant by “you shouldn't be able get around that” was that the
code shouldn't change the value of x.
>> Also, you should be able to reason that both of the following print the same
>> thing twice, for types whose methods have no external side-effects:
>>
>> func gg<T: P>(x: T) {
>> print(x)
>> x.noChange()
>> print(x)
>> }
>>
>> func ggg<T: P>(x: T) {
>> print(x)
>> var y = x
>> y.changeMe()
>> print(x)
>> }
> I see the issue here. Though, it seems to me it is just a more easily
> discoverable version of an entire class of problem with reference
> types in general. X could be changed on a different thread too, for
> example. or in a nested function call.
>
> You would also still have the same problem with 'let y = x'.
>
>> When T is a class type, it can easily violate *all* of these
>> expectations. In other words, classes naturally bypass the mutation
>> model.
>>
>> If we are going to maintain source stability after Swift 3, it seems
>> that we either need to address this now, or decide that it won't be
>> addressed, because of the “viral const” problem.
>>
>> One idea that Jordan and I have floated is that protocols with mutating
>> methods should be constrained to applying to non-class types. That
>> would be a step in the right direction, but, that still leaves cases
>> like gg able to easily violate expectations when the protocol in
>> question has no mutating methods.
>
> I really *dislike* the approach of disallowing class types for
> protocols with mutating methods, unless an additional reference type
> is added. I have several protocols which have conforming classes and
> structs and that that lets you choose reference vs value semantics.
How do you write generic code that works on both reference and value
types conforming to such a protocol?
> I would much rather have us mark class methods as mutating when they
> change the class’s value, and just having the concept be separate from
> let/var in that case.
>
>>
>> Another possibility would be to formalize the idea of value semantics in
>> protocol declarations, so that non-class protocols were only allowed to
>> apply to values.
>
> I would like to have a way to require value semantics in a protocol
> (similar to how we can require ‘class' now). I still really want/need
> the ability to have a protocol which can be adhered to by both value
> and class types though...
I really want to see examples of generic code that isn't terribly tricky
to write correctly so it will work on both kinds of type.
>> It's also possible that I've overestimated the seriousness of the issue
>> and we actually can afford to postpone thinking about it until after
>> Swift 4.
>>
>> Thoughts?
>
> I would vote to postpone to swift 4, and have it be part of a larger
> discussion involving the marking of side-effects and thread safe
> mutability.
>
> If you need a stop-gap for Swift 3, I would be in favor of adding the
> ability to mark a particular protocol as needing to be a value type
> (not every protocol… just those that are marked as such). That should
> give you the guarantees you need for particular projects.
That's a reasonable stopping point.
--
Dave
More information about the swift-evolution
mailing list