Sent from my iPad

> On Aug 19, 2017, at 8:16 AM, Michel Fortin via swift-evolution 
> <swift-evolution@swift.org> wrote:
> 
>>> For instance, has Array<UIView> value semantics?
>> 
>> By the commonly accepted definition, Array<UIView> does not provide value 
>> semantics.
>> 
>>> You might be tempted to say that it does not because it contains class 
>>> references, but in reality that depends on what you do with those UIViews.
>> 
>> An aspect of the type (“does it have value semantics or not”) should not 
>> depend on the clients.  By your definition, every type has value semantics 
>> if none of the mutating operations are called :-)
> 
> No, not mutating operations. Access to mutable memory shared by multiple 
> "values" is what breaks value semantics. You can get into this situation 
> using pointers, object references, or global variables. It's all the same 
> thing in the end: shared memory that can mutate.
> 
> For demonstration's sake, here's a silly example of how you can give 
> Array<Int> literally the same semantics as Array<UIView>:
> 
>       // shared UIView instances in global memory
>       var instances: [UIView] = []
> 
>       extension Array where Element == Int {
> 
>               // append a new integer to the array pointing to our UIView 
> instance
>               func append(view: UIView) {
>                       self.append(instances.count)
>                       instances.append(newValue)
>               }
> 
>               // access views pointed to by the integers in the array
>               subscript(viewAt index: Int) -> UIView {
>                       get {
>                               return instances[self[index]]
>                       }
>                       set {
>                               self[index] = instances.count
>                               instances.append(newValue)
>                       }
>               }
>       }
> 
> And now you need to worry about passing Array<Int> to other thread. ;-)
> 
> It does not really matter whether the array contains pointers or wether it 
> contains indices into a global table: in both cases access to the same 
> mutable memory is accessible through multiple copies of an array, and this is 
> what breaks value semantics.
> 
> Types cannot enforce value semantics. Its the functions you choose to call 
> that matters. This is especially important to realize in a language with 
> extensions where you can't restrict what functions gets attached to a type.

This gets deeper into the territory of the conversation Dave A and I had a 
while ago.  I think this conflates value semantics with pure functions, which I 
think is a mistake.  

I agree that if you assume away reference counting a function that takes 
Array<UIView> but never dereferences the pointers can still be a pure function. 
 However, I disagree that Array<UIView> has value semantics.

The relationship of value semantics to purity is that value semantics can be 
defined in terms of the purity of the "salient operations" of the type - those 
which represent the meaning of the value represented by the type.  The purity 
of these operations is what gives the value independence from copies in terms 
of its meaning.  If somebody chooses to add a new impure operation in an 
extension of a type with value semantics it does not mean that the type itself 
no longer has value semantics.  The operation in the extension is not "salient".

This still begs the question: what operations are "salient"?  I think everyone 
can agree that those used in the definition of equality absolutely must be 
included.  If two values don't compare equal they clearly do not have the same 
meaning.  Thread safety is also usually implied for practical reasons as is the 
case in Chris's manifesto.  These properties are generally considered necessary 
for value semantics.

While these conditions are *necessary* for value semantics I do not believe 
they are *sufficient* for value semantics.  Independence of the value is also 
required.  When a reference type defines equality in terms of object identity 
copies of the reference are not truly independent.  

This is especially true in a language like Swift where dereference is implicit. 
 I argue that when equality is defined in terms of object identity copies of 
the reference are *not* independent.  The meaning of the reference is 
inherently tied up with the resource it references.  The resource has to be 
considered "salient" for the independence to be a useful property.  On the 
other hand, if all you really care about is the identity and not the resource, 
ObjectIdentifier is available and does have value semantics.  There is a very 
good reason this type exists.

I'm happy to see this topic emerging again and looking forward to seeing value 
semantics and pure functions eventually receive language support.  There are a 
lot of subtleties involved.  Working through them and clearly defining what 
they mean in Swift is really important.

> 
> 
>>> If you treat the class references as opaque pointers (never dereferencing 
>>> them), you preserve value semantics. You can count the elements, shuffle 
>>> them, all without dereferencing the UIViews it contains. Value semantics 
>>> only end when you dereference the class references. And even then, there 
>>> are some exceptions.
>> 
>> I agree with you that the model could permit all values to be sent in actor 
>> messages, but doing so would give up the principle advantages of mutable 
>> state separation.  You’d have to do synchronization, you’d have the same 
>> bugs that have always existed, etc.
> 
> What the compiler should aim at is enforcing useful rules when it comes to 
> accessing shared mutable state.
> 
> 
> -- 
> Michel Fortin
> https://michelf.ca
> 
> _______________________________________________
> 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

Reply via email to