Regards (From mobile)
> On May 22, 2016, at 9:23 PM, Matthew Johnson via swift-evolution > <swift-evolution@swift.org> wrote: > > >> On May 22, 2016, at 1:10 PM, Dave Abrahams via swift-evolution >> <swift-evolution@swift.org> wrote: >> >> >> on Mon May 16 2016, Matthew Johnson <swift-evolution@swift.org> wrote: >> >>>> On May 16, 2016, at 1:39 AM, Dave Abrahams <dabrah...@apple.com> wrote: >>>> >>>> >>>> on Sun May 15 2016, Tyler Fleming Cloutier <cloutiertyler-AT-aol.com >>>> <http://cloutiertyler-at-aol.com/>> wrote: >>>> >>> >>>>> On May 15, 2016, at 11:48 AM, Dave Abrahams via swift-evolution >>>>> <swift-evolution@swift.org> wrote: >>>>> >>>>> on Mon May 09 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote: >>>>> >>>>> On May 8, 2016, at 1:51 AM, Dave Abrahams <dabrah...@apple.com> >>>>> wrote: >>>>> >>>>> on Sat May 07 2016, Andrew Trick <atrick-AT-apple.com> wrote: >>>>> >>>>> On May 7, 2016, at 2:04 PM, Dave Abrahams >>>>> <dabrah...@apple.com> wrote: >>>>> >>>>> 2. Value types are not "pure" values if any part of >>>>> the aggregate >>>>> contains a >>>>> reference whose type does not have value semantics. >>>>> >>>>> Then Array<Int> is not a “pure” value (the buffer >>>>> contained in an >>>>> Array<Int> is a mutable reference type that on its own, >>>>> definitely does >>>>> *not* have value semantics). I don't think this is what >>>>> you intend, and >>>>> it indicates that you need to keep working on your >>>>> definition. >>>>> >>>>> It sounds like you’re changing the definition of value >>>>> semantics to make it >>>>> impossible to define PureValue. >>>>> >>>>> Not on purpose. >>>>> >>>>> Does Array<T> have value semantics then only if T also has >>>>> value >>>>> semantics? >>>>> >>>>> This is a great question; I had to rewrite my response four >>>>> times. >>>>> >>>>> In my world, an Array<T> always has value semantics if you >>>>> respect the >>>>> boundaries of element values as defined by ==. That means that >>>>> if T is >>>>> a mutable reference type, you're not looking through >>>>> references, because >>>>> == is equivalent to ===. >>>>> >>>>> Therefore, for almost any interesting SomeConstraint that >>>>> doesn't refine >>>>> ValueSemantics, then >>>>> >>>>> Array<T: SomeConstraint> >>>>> >>>>> only has value semantics if T has value semantics, since >>>>> SomeConstraint >>>>> presumably uses aspects of T other than reference identity. >>>>> >>>>> The claim has been made that Array always has value >>>>> semantics, >>>>> implying that the array value’s boundary ends at the >>>>> boundary of it’s >>>>> element values. >>>>> >>>>> Yes, an array value ends at the boundary of its elements' >>>>> values. >>>>> >>>>> That fact is what allows the compiler to ignore mutation of >>>>> the >>>>> buffer. >>>>> >>>>> I don't know what you mean here. >>>>> >>>>> It's perfectly clear that Array<T> is a PureValue iff T is >>>>> a PureValue. >>>>> PureValue is nothing more than transitive value semantics. >>>>> >>>>> You're almost there. “Transitive” implies that you are going >>>>> to look at >>>>> the parts of a type to see if they are also PureValue's. So >>>>> which parts >>>>> of the Array struct does one look at, and why? Just tell me the >>>>> procedure for determining whether a type is a PureValue. >>>>> >>>>> We look at the observable parts. >>>>> >>>>> That begs the question. The “parts” of an Array are the observable >>>>> features that are considered by equality. >>>>> >>>>> We do not look at unobservable parts because we want flexibility to >>>>> use things like CoW, shared immutable references, etc in our >>>>> implementation. >>>>> >>>>> IMO the important thing when it comes to functional purity is not what >>>>> you *can* observe, but what you *do* observe. >>>>> >>>>> Can you share your definition of value semantics? >>>>> >>>>> Explaining it well and in sufficient detail for this discussion takes >>>>> some doing, but I think John Lakos and I share an understanding of value >>>>> semantics and he has a really detailed explanation in >>>>> https://www.youtube.com/watch?v=W3xI1HJUy7Q and >>>>> https://www.youtube.com/watch?v=0EvSxHxFknM. He uses C++ in places, >>>>> but it's not particularly advanced, and the fundamental ideas apply just >>>>> as well to Swift. >>>>> >>>>> Super interesting talk! >>>>> >>>>> But consider: isn't a single value type able to represent *multiple* >>>>> ethereal types? >>>> >>>> “ethereal?” Does he really use that term? I don't know what it means. >>>> >>>>> >>>>> std::vector is a good example. What are the salient attributes of this >>>>> type? In the talk John says that >>>>> >>>>> 1. the size is >>>>> 2. the values in the vector are >>>>> 3. the capacity, however *is not* >>>> >>>> Yup, just like Array. Thus the equality test for arrays ignores >>>> capacity. >>>> >>>>> in which case std::vector would be an approximation of an ethereal >>>>> type which has a list of values, and the capacity is just an artifact >>>>> of the approximation. But you could also imagine an ethereal type >>>>> which *does* depend of the capacity of the object, and std::vector >>>>> unwittingly approximates that type too! In this case someone, >>>>> unfamiliar with the implementation might use it under the assumption >>>>> that capacity *is* part of the ethereal type and by extension the >>>>> equality of std::vector. >>>>> >>>>> John avoids the problem by saying that this must specified in the >>>>> documentation. >>>> >>>> Yes. >>>> >>>>> I tend to see this as breaking encapsulation since you need to know >>>>> the implementation of the equality operator to be able to determine if >>>>> a public property, the capacity, is part of the ethereal type. >>>> >>>> No, you just need documentation. >>>> >>>>> It’s not always the case that you have access to either the >>>>> documentation or the implementation. >>>> >>>> Without the documentation, you're lost. We go a lot further with naming >>>> conventions in Swift than typical C++ does, but even in Swift you can't >>>> expect to fully understand semantics without documentation. >>>> >>>>> This implies, therefore, that if salient attributes *define* the >>>>> immutability of the value type, then the public interface is not >>>>> guaranteed to be immutable, since it is allowed to include non-salient >>>>> attributes. For example, a vector’s capacity could change at any time, >>>>> by virtue of it being stored via a reference. >>>>> >>>>> What I am saying is that a PureValue is a value type whose public >>>>> interface comprises *only* salient attributes. And I also claim that >>>>> this is a useful distinction amongst value types. >>>> >>>> Then Array<Int> is not a PureValue because it exposes capacity?! That >>>> sounds crazy to me, since the Array's capacity in no sense has reference >>>> semantics. >>>> >>>>> John also says that a salient attribute must derive *only* from the >>>>> state of a particular instance of a type. This by extension implies >>>>> that a salient attribute must derive exclusively from pure >>>>> values. However, this also means that without some “indirect” keyword, >>>>> PureValues are restricted to acyclic and non-recursive structures. >>>>> >>>>> I also claim that equality can be automatically generated for >>>>> PureValues by equating each of there salient attributes. >>>> >>>> That's true for almost any value, provided we define equality for >>>> reference types properly. >>>> >>>>> I really apologize if this seems like rambling again, but I am very >>>>> interested in this problem. >>>> >>>> I'm glad you are! Few programmers dig far enough to understand value >>>> semantics at a deep level. >>>> >>>> All that said, I still think PureValue is a red herring. Unless I'm >>>> forgetting something that happened in the thread two weeks ago, nobody >>>> has shown me code that relies on PureValue but could not equally well be >>>> written by using a Value constraint. >>> >>> Looking forward to hearing your thoughts on the code I just posted. >>> >>> In addition to that, I think it is also important to note that >>> contained within the notion of PureValue is thread safety. For >>> example, in CSP PureValues would can be sent as messages on a channel. >>> Clearly sending Array<MutableReferenceType> over a channel is >>> something you would not do in CSP. >> >> Not if you were interested in anything other than the identities of the >> elements. But I can easily imagine representing a selection as a Set<T> >> and passing that across threads, where T might be a mutable reference >> type (using my default definition of == and hashValue for all >> references). > > Hmmm. My understanding of CSP is that it is intended to prevent mutable > state from being visible in more than one “process” at the same time. > Synchronization happens by sending values across channels, not with the usual > thread-oriented synchronization mechanisms like locks and semaphores, etc. > > I realized I overstated the case a bit here. There are certainly cases where > you might want to transfer ownership of a reference through a channel. It’s > a shame that Swift doesn’t yet have the ability to talk about owned > references and transfer of ownership. I’m happy that Chris is supportive of > eventually introducing an ownership system of some kind. > There was a recent talk about some changes to the structure of the ISA pointer and brief mention about where some thread info could be added >> >>> You can also freely share a ImmutableBox<MyPureValue> and read from it >>> in any thread you wish without any trouble. You cannot do that with >>> ImmutableBox<Array<MutableReferenceType>>. In the latter, you cannot >>> mutate the array, but you can still mutate the objects it contains >>> references to. >> >> Again, it depends on what you look at. We could create a value type >> that distinguishes object identities, e.g. >> >> struct Identity<SomeClass : AnyObject> : Hashable, Comparable { >> >> let subject: SomeClass >> init(subject: SomeClass) { self.subject = subject } >> ... >> } >> >> func == <X>(lhs: Identity<X>, rhs: Identity<X>) -> Bool { >> return lhs === rhs >> } >> >> then you could write: >> >> ImmutableBox<Array<Identity<MutableReferenceType>>> >> >> But would you really make it *impossible* to observe the subject of an >> Identity? We could, but I'm not sure I would. >> It would come at a cost >> to efficiency in those places where you have a collection of Identity's >> and you happen to know they're not shared across threads, which I think >> is probably an important use-case. > > I’m not trying to argue that you shouldn’t be able to do things like this if > you want to. > > What I am arguing for is the ability to distinguish aggregates which are > logically isolated from aggregates which contain salient references to shared > mutable state. To be honest, I am really struggling to understand why this > distinction seems unimportant to you. > >> >>>> >>>>> Tyler >>>>> >>>>> It may be helpful >>>>> if we start there and refine your definition to exclude impure value >>>>> types like Array<UIView>. >>>>> >>>>> In the meantime I’ll take another shot: >>>>> >>>>> 1. Scalars are pure values. >>>>> >>>>> 2. Any aggregate type with value semantics is a pure value iff all >>>>> observable parts of the aggregate are pure values. >>>>> >>>>> -- >>>>> -Dave >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> swift-evolution@swift.org >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> >>>> >>>> -- >>>> -Dave >>> >>> _______________________________________________ >>> swift-evolution mailing list >>> swift-evolution@swift.org >>> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> -- >> -Dave >> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org >> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > swift-evolution@swift.org > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution