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

Matthew Johnson matthew at anandabits.com
Mon May 9 18:07:09 CDT 2016

> On May 8, 2016, at 1:19 AM, Dave Abrahams <dabrahams at apple.com> wrote:
> on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com <http://matthew-at-anandabits.com/>> wrote:
>>    On May 7, 2016, at 4:04 PM, Dave Abrahams <dabrahams at apple.com> wrote:
>>    on Sat May 07 2016, Matthew Johnson <matthew-AT-anandabits.com> wrote:
>>        I've been thinking about this further and can now state my position more
>>        clearly
>>        and concisely.
>>        1. If we're going to have reference types with value semantics the
>>        boundary of
>>        the value must extend through the reference to the value of the object.
>>        Two
>>        instances may have the same logical value so reference equality is not
>>        good
>>        enough.
>>    My (radical) position has been that we should decree that if you really
>>    want this thing to have value semantics, it should be a struct. That
>>    is, wrap your reference type in a struct and provide an == that looks at
>>    what's in the instance. This radically simplifies the model because we
>>    can then assume that value types have value semantics and reference
>>    types only have value semantics if you view their identitity as their
>>    value.
>> I agree with this longer term, but it is too soon for that. 
> We don't have much longer to establish the programming model.  It needs
> to happen soon or it will be too late.
>> Rather than suggest wrapping the reference in a struct I would suggest that most
>> of the time just making it a struct in the first place is the right
>> path. 
> Well of course.  But if you already have a reference type and aren't
> ready to rewrite it, this is how you do it.
>> The problem with this is that it can lead to excessive copying,
>> reference counting, etc if you’re not careful. I argue that mainstream
>> developers should not need to bother with writing a reference type and
>> wrapping it in a struct just to get around this. 
> Sure, maybe our codegen could be smarter about this, but that shouldn't
> hold back the programming model.
>> It would be nice if there were better, less boilerplate-y solutions to
>> this in the future.
>>        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.
>> I have elaborated elsewhere as to why Array<Int> does meet my notion of “pure”
>> value. I understand that it contains a buffer pointer, etc that does not have
>> value semantics. But that is an implementation detail and is not externally
>> observable. I believe that implementation strategies like this are extremely
>> important. I am only concerned with the externally observable semantics and
>> behavior of the type, not the implementation. 
>> Just as the internal mutable reference type does not disqualify Array<Int> from
>> having value semantics, it also does not disqualify it from being a “pure
>> value".
> As I've indicated, then, you need a different definition than the one
> above.  And you have to get the definition all together in one place so
> it can be evaluated.
>>        Purity must include the entire aggregate. Array<UIView> has value
>>        semantics but it is not a pure value.
>>    In what sense does it have value semantics? Unless we can define
>>    equality for Array<UIView> it's hard to make any claim about its value
>>    semantics.
>> Well it should have value semantics using reference equality of the views
>> because UIView has reference semantics so reference identity is the appropriate
>> definition of equality. Isn’t that your position as well? 
> Yes.  
>>        The primary reasons I can think of for creating reference types with
>>        value
>>        semantics are avoiding copying everything all the time or using
>>        inheritance. (I
>>        could also list pre-existing types here but am not as concerned with
>>        those)
>>        One could argue that you can avoid copying by writing a struct with a
>>        handle and
>>        one can simulate inheritance by embedding and forwarding. The problem is
>>        that
>>        this involves a lot of boilerplate and makes your code more complex. 
>>    The “forwarding boilerplate problem” is something we need to solve in
>>    the language regardless. 
>> Yes I agree that it needs to be solved regardless. In fact, you might remember
>> that I invested quite a bit of effort into drafting a proposal on the topic. I
>> shelved it mostly because I became very busy with client work, but also partly
>> due to the lukewarm reaction.
>>    The fact that we don't have an answer today
>>    shouldn't prevent us from adopting the right model for values and
>>    references.
>> I think that depends on what you mean by this. If you mean providing a default
>> equality of reference identity for reference types I disagree. I think that
>> should wait until the language reaches a place where there is no good reason to
>> write value semantic reference types. And I believe the boilerplate currently
>> required to wrap them in a struct is sufficiently burdensome that this is not
>> the case yet.
> As I've said, we can't wait.  We should make the change and use that to
> drive development of the necessary features to reduce the burden of
> writing optimized code.  

I suppose that’s a fair position.

> Remember that the only value semantic reference types are immutable, so
> the struct rendition of such types has only immutable properties.
> Personally, I don't think that transforming
>        struct X {
>          ...
>        private:
>          let prop1: Type1
>          let prop2: Type2
>          let prop2: Type3
>        }
> into
>        struct X {
>           ...
>        private:
>          class Storage {
>            let prop1: Type1
>            let prop2: Type2
>            let prop2: Type3
>          }
>          let value: Storage
>        }
> is so awful if you find you need to optimize away some reference
> counting manually; you just need to add “.value” to property accesses in
> X's methods, and this doesn't require any forwarding.

It’s not too awful but it does expose implementation details.  If we’re going to hide the implementation details maybe it’s worth taking advantage of the type by making the props var and using CoW.

What do you think about a proposal to enhance “indirect” for value types and / or instances of them.  I can think of a few approaches to this that we could consider.  I would be much more comfortable with what you want to do if we tackle that as well.

>>    So far, I still don't believe that introducing a “pure values”
>>    distinction is adding simplicity and clarity. To me it looks like
>>    a needless wrinkle.
>> Fair enough. I suspect that many folks who have been strongly influenced by
>> functional programming may have a different opinion (btw, I don’t mean to imply
>> anything about the degree to which functional programming has or has not
>> influenced your opinion).
> -- 
> -Dave

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20160509/ce8680bf/attachment.html>

More information about the swift-evolution mailing list