> On May 7, 2016, at 3:03 PM, Dave Abrahams <dabrah...@apple.com> wrote: > > > on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote: > >> This depends on the type. For types representing resources, etc it works just >> fine. But for models it does not work unless the model subgraph is entirely >> immutable and instances are unique. >> I agree that it isn't a good idea to provide a default that will >> certainly be wrong in many cases. > > Please show an example of a mutable model where such an equality would > be wrong.
This is somewhat orthogonal to the main points I have been making in this thread. I have been focused on discussion about reference types that have value semantics and the distinction between value semantics and pure values. In any case, here you go: let a: NSMutableArray = [1, 2, 3] let other: NSMutableArray = [1, 2, 3] let same = a === other // false let equal = a == other // true Reference equality does not match the behavior of many existing mutable model types. You seem to be making a case that in Swift it should. But that is a separate discussion from the one I am trying to engage in because mutable reference types *do not* have value semantics. > >> I assume what is meant by "PureValue", is any object A, whose own >> references >> form a subgraph, within which a change to any of the values would >> constitute >> a change in the value of A (thus impermissible if A is immutable). Thus >> structs would quality as “PureValues”. >> >> As you noted in a followup, not all structs qualify. Structs that whose >> members >> all qualify will qualify. References to a subgraph that doesn't allow for any >> observable mutation (i.e. deeply immutable reference types) also qualify. >> >> This means the following qualify: >> >> * primitive structs and enums >> * observable immutable object subgraphs >> * any type composed from the previous >> >> It follows that generic types often conditionally qualify depending on their >> type arguments. >> >> I also assume that enforcing immutability on an object graph, via CoW or >> otherwise, would be unfeasible. You could enforce it on all values >> accessible by traversing a single reference for reference types, however. >> >> This is why I don’t really buy the argument that there is no such this as >> deep vs shallow copy. Deep copy means copying the whole “PureValue” or >> subgraph, shallow copy means traversing a single reference and copying all >> accessible values. >> >> I don’t mean to imply that it is the *only* valuable >> property. However, it I (and many others) do believe it is an >> extremely >> valuable >> property in many cases. Do you disagree? >> >> I think I do. What is valuable about such a protocol? What generic >> algorithms could you write that work on models of PureValue but >> don't >> work just as well on Array<Int>? >> >> Array<Int> provides the semantics I have in mind just fine so >> there >> wouldn’t be >> any. Array<AnyObject> is a completely different story. With >> Array<AnyObject> you cannot rely on a guarantee the objects >> contained >> in the array will not be mutated by code elsewhere that also >> happens >> to have a reference to the same objects. >> >> Okay then, what algorithms can you write that operate on PureValue >> that >> don't work equally well on Array<AnyObject>? > > You haven't answered this question. How would you use this protocol? I answered elsewhere but I’ll repeat that one use that immediately comes to mind is to constrain values received in the initializer of a (view) controller to ensure that the observable state will not change over time. This is not an algorithmic use but is still perfectly valid IMO. If I read Andrew’s post correctly it sounds like it may also be of use to the optimizer in some cases. > >> let t = MyClass() >> foo.acceptWrapped(Wrap(t)) >> t.mutate() >> >> In this example, foo had better not depend on the wrapped instance >> not >> getting >> mutated. >> >> foo has no way to get at the wrapped instance, so it can't depend >> on >> anything about it. >> >> Ok, but this is a toy example. What is the purpose of Wrap? Maybe >> foo >> passes the >> wrapped instance back to code that *does* have visibility to the >> instance. My >> point was that shared mutable state is still possible here. >> >> And my point is that Wrap<T> encapsulates a T (almost—I should >> have >> let >> it construct the T in its init rather than accepting a T >> parameter) >> and >> the fact that it's *possible* to code something with the structure >> of >> Wrap so that it has shared mutable state is irrelevant. >> >> The point I am trying to make is that the semantic properties of >> Wrap<T> depend >> on the semantic properties of T (whether or not non-local mutation >> may be >> observed in this case). >> >> No they do not; Wrap<T> was specifically designed *not* to depend on >> the >> semantic properties of T. This was in answer to what you said: >> >> A struct wrapping a mutable reference type certainly doesn’t >> “feel” value semantic to me and certainly doesn’t have the >> guarantees usually associated with value semantics (won’t >> mutate behind your back, thread safe, etc). >> >> I have been trying to get you to nail down what you mean by PureValue, >> and I was trying to illustrate that merely being “a struct wrapping a >> mutable reference type” is not enough to disqualify anything from >> being >> in the category you're trying to describe. What are the properties of >> types in that category, and what generic code would depend on those >> properties? > > Again, the key questions are above, asked a different way. > > -- > -Dave _______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution