[swift-dev] Value-type bound protocols?

Joe Groff jgroff at apple.com
Tue Sep 19 11:31:25 CDT 2017



> On Sep 19, 2017, at 5:19 AM, David Zarzycki via swift-dev <swift-dev at swift.org> wrote:
> 
> 
> 
>> On Sep 18, 2017, at 17:54, Ben Cohen via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>> 
>> 
>> 
>>> On Sep 13, 2017, at 1:06 PM, David Zarzycki via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>>> 
>>> 
>>> 
>>>> On Sep 13, 2017, at 15:23, Matthew Johnson via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>>>> 
>>>> 
>>>> 
>>>> Sent from my iPhone
>>>> 
>>>>> On Sep 13, 2017, at 11:56 AM, David Zarzycki via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>>>>> 
>>>>> 
>>>>> 
>>>>>> On Sep 13, 2017, at 13:53, David Sweeris <davesweeris at mac.com <mailto:davesweeris at mac.com>> wrote:
>>>>>> 
>>>>>> 
>>>>>>> On Sep 13, 2017, at 09:54, David Zarzycki via swift-dev <swift-dev at swift.org <mailto:swift-dev at swift.org>> wrote:
>>>>>>> 
>>>>>>> Hello,
>>>>>>> 
>>>>>>> As a part of a research project that I’m working on, I’ve started bumping into the need for value-type bound protocols (as opposed to the existing class bound protocols). Is this something that would be worth proposing formally? Or should I just keep the patch I have on my research branch?
>>>>>> 
>>>>>> I think it'd be worth a proposal, especially if can talk about why you needed it.
>>>>> 
>>>>> While I look forward to talking about my research, I’m not ready to do in the near future.
>>>>> 
>>>>> That being said, value-type bound protocols seem independently useful and that is why I emailed the list.
>>>>> 
>>>>> I think the use case for this is generic algorithms. Why? Because it can be hard to impossible to write *robust* generic code when you don’t know whether an abstract type copies by value or by reference during assignment/initialization. With class-bound protocols, you can guarantee reference semantics, but there is no analogous feature for ensuring value semantics. I have a small (~150 line) patch that fixes this.
>>>> 
>>>> Value types and value semantics are not the same.  Most people who have asked for this capability actually want a constraint for value semantics, not value types.  Is that what you're asking for as well?
>>> 
>>> The patch that I’m ready to put forth is only a value-type bound. In other words only structs and enums would be able to conform to a value-type bound protocol. Enforcing value semantics is arguably a separable language goal.
>>> 
>> 
>> But knowing something is a value type isn’t particularly useful, given it doesn’t guarantee value semantics. It could even do more harm than good, by being confusable with enforcing value semantics. 
>> 
>> Can you go into the use cases you have where you would use the knowledge that a type is a value type?
> 
> 
> Hi Ben,
> 
> As a part of a much larger goal, I’m experimenting with enforced value *semantics* and I found that value-type bound protocols are a wholly separable and independently useful prerequisite. Here is a contrived but representative example:
> 
> protocol ValueThingy : !class { // From the patch sent to the list
>   mutating func increment()
> }
> 
> func incrementByCopy<T : ValueThingy>(_ arg : T) -> T {
>   var copy = arg
>   copy.increment()
>   return copy
> }
> 
> Without value-type bound protocols, generic code cannot ensure that required copies are actually happening. This is independently useful and good.

As others have noted, this doesn't by itself guarantee anything. Value semantics is a property of an operation, not of a type. You can use an Int as a reference:

var counters: [Double]

extension Int: ValueThingy {
  mutating func increment() {
    counters[self] += 1.0
  }
}

which, despite "using value types everywhere", violates the contract you're looking for without warning. On the other hand, a class can also serve as a value:

protocol Incrementable {
  var incremented: Self { get }
}

extension ValueThingy where Self: Incrementable {
  mutating func increment() {
    self = self.incremented
  }
}

class IndirectInt: ValueThingy, Incrementable {
  var value: Int
  init(value: Int) { self.value = value }

  var incremented: Int { return IndirectInt(value: value + 1) }
}

The more fundamental thing I think we're looking for in this space is a "pure" restriction for functions and methods, meaning they only access non-shared-mutable data. Any annotation at the type level is not going to give strong enough guarantees to build sound abstractions on top of.

-Joe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-dev/attachments/20170919/c4aa6acf/attachment.html>


More information about the swift-dev mailing list