[swift-evolution] Should we rename "class" when referring to protocol conformance?

Tyler Fleming Cloutier cloutiertyler at aol.com
Mon May 16 02:12:28 CDT 2016


> On May 15, 2016, at 11:39 PM, Dave Abrahams <dabrahams at apple.com> wrote:
> 
> 
> on Sun May 15 2016, Tyler Fleming Cloutier <cloutiertyler-AT-aol.com> wrote:
> 
>>    On May 15, 2016, at 11:48 AM, Dave Abrahams via swift-evolution <swift-evolution at 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 <dabrahams at 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 <dabrahams at 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.

He does pretty frequently. He also refers to them as Mathematical Types. He means the logical type that the C++ implementation is supposed to approximate.

An example he gives is int and how it only approximates the logical Integer type, because it is represented in many ways, e.g. short, int, long, long long. None of them are exactly the same the logical type.

> 
>> 
>> 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.

Swift also goes a lot further with enforcing things like immutability by default with let, particularly for value types. I think that with well defined rules you can go further with what’s enforced, and remove the need for documentation, especially since the distinctions with regards to value types can be subtle.

> 
>> 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.

I would argue, rather, that capacity for Array<Int> *is* a salient attribute, by virtue being public and that Array<Int> is a PureValue by virtue of it not having reference semantics. This I propose is valid, because even though it’s not the most intuitive in this case, it is possible that some algorithm interprets capacity to be salient and relies on two arrays with different capacities being not equal.

I can certainly understand the opposing argument here, but at least this way it is unambiguous.

> 
>> 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.

Let me get back to you here. I need to do more investigation!

Gotta watch that second video.

Tyler

> 
>> 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 at swift.org
>>    https://lists.swift.org/mailman/listinfo/swift-evolution
>> 
> 
> -- 
> -Dave



More information about the swift-evolution mailing list