[swift-evolution] Preserving non-mutability of methods of an existential or generic object

Hooman Mehr hooman at mac.com
Wed Jan 3 19:33:54 CST 2018


Thank you Slava, it is a very insightful answer. 

It also reveals a potential source for hard to track bugs. To make it easier to see, lets add state to class C:

class D: C { var state = 0 }

var d = D() // Bad but common habit of declaring objects as var
for i in 1...5 { d.f(i); d.state += 1 }
print(d.state) // Prints 1

The result is surprising because a typical programmer does not expect an object to have mutating methods (that replace the object itself with a different one).

I think this is a bug in Swift compiler. It should not let a class “inherit” a mutating method in this manner. Compiler should require a non-mutating declaration of `f()` to satisfy `P` conformance for a class type.

If we fix the above, it should be possible to do what I asked in my post: When compiler knows an existential is an object, it should know all methods are non-mutating and accept `let` declaration despite calls to nominally mutating methods. Also, if a protocol refines another protocol to be class-bound, compiler should automatically refine all of its inherited mutating methods to be non-mutating and allow `let` declaration of an existential of that protocol even if there are calls to those originally mutating methods. 

Hooman

> On Dec 21, 2017, at 10:59 PM, Slava Pestov <spestov at apple.com> wrote:
> 
> Hi Hooman,
> 
> Since the protocol P is not class-bounded, the requirement can be witnessed by a protocol extension method which re-assigns ‘self’:
> 
> protocol Initable {
>   init()
> }
> 
> extension P where Self : Initable {
>   mutating func f(_ x: Int) -> Int {
>     self = Self()
>     return x
>   }
> }
> 
> class C : P, Initable {
>   required init() {}
> }
> 
> Now imagine you could do this,
> 
> let x: P & AnyObject
> 
> x.f(12)
> 
> This would be invalid because ‘x’ is a let binding but the requirement ‘f’ is witnessed by the protocol extension method, which performs a mutating access of ‘self’.
> 
> Slava
> 
>> On Dec 21, 2017, at 6:01 PM, Hooman Mehr via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> The title is confusing, let me clarify by example:
>> 
>> We have this protocol with a mutating method:
>> 
>> protocol P { mutating func f(_ x: Int) -> Int }
>> 
>> And a conforming class (which has to conform with a non-mutating method):
>> 
>> class C: P { func f(_ x: Int) -> Int { return x } }
>> 
>> An instance of this class can be used with a let constant:
>> 
>> let c = C()
>> c.f(1) // OK
>>  
>> If we make it an existential object conforming to P, the immutability of the method will be erased:
>> 
>> let c: AnyObject & P = C()
>> c.f(1) // Cannot use mutating member on immutable value: 'c' is a 'let' constant
>> 
>> A generic context has the same issue:
>> 
>> func f<T: AnyObject & P>(_ arg: T)-> Int { return arg.f(1) } // Cannot use mutating member on immutable value: ‘arg' is a 'let' constant
>> 
>> My question: 
>> 
>> Is it too much work to preserve method non-mutability in in these cases?
>> 
>> The workaround I am using is this:
>> 
>> protocol Q: class, P { func f(_ x: Int) -> Int } // 'Refine' it to be non-mutating.
>> extension C: Q {}
>> 
>> // Now these work:
>> let c: Q = C()
>> c.f(1) // OK
>> func f<T: Q>(_ arg: T)-> Int { return arg.f(1) } // OK
>> 
>> This workaround creates a lot of duplication and is hard to maintain. It is not something that I do often, but when I do, it is pretty annoying. 
>> 
>> Supplemental questions:
>> 
>> Have you guys ever ran into this?
>> Is there already a bug tracking this? 
>> 
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 

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


More information about the swift-evolution mailing list