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)
> 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.
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...
> 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.
Thanks,
Jon
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution