Protocol Extension, Mutating Function

Protocol Extension, Mutating Function

If you intend to use the protocol only for classes then you can make
it a class protocol (and remove the mutating keyword):

protocol ColorImpressionableProtocol : class {

// ...

func adoptColorsFromImpresion(impresion: ColorImpressionableProtocol?)
}

Then

init(impresion: ColorImpressionableProtocol?){
super.init(nibName: nil, bundle: nil)
adoptColorsFromImpresion(impresion)
}

compiles without problems.

Swift 2 Error using mutating function in Protocol extension Cannot use mutating member on immutable value: 'self' is immutable

The problem is that, in the protocol you mark the function as mutating, which you need to do if you want to use the protocol on a struct. However, the self that is passed to testFunc is immutable (it's a reference to a instance of the class) and that is tripping up the compiler. This would make sense if testClass was actually a struct and you could make the function mutating to resolve the issue.

I can see two work arounds:

  1. make the protocol class only

    protocol MTKAnimateValueDelegate: class { ...
  2. Make testClass a struct and mark testFunc as mutating.

Either way, I think this is a bug that needs to be reported to Apple.

Edit


  1. Another way around it is to make a mutable copy of self
func testFunc() {
var animValue = MTKAnimateValue(fromValue: 10, toValue: 20, inSeconds: 2)
animValue.isAnimating = true
var mutableSelf = self
mutableSelf.mtkAnimQueAppend(animValue)
}

Since mutableSelf is a reference, any changes the mutating function makes will still be reflected in self's state.

What happens when a Class conforms to a protocol, which contains mutating function?

I don't see what the "confusion" is. You've elucidated the rules beautifully! A struct may implement a protocol's mutating function as nonmutating, but it may not implement a protocol's nonmutating function as mutating. Once you've said those rules, there's nothing to be "confused" about. The rules are the rules.

Classes don't have mutating functions so your investigations there are sort of irrelevant. If you had declared your protocol as a class protocol, your mutating annotation in the protocol would have been illegal.

Swift: Can't use mutating method in Protocol Extension

This code:

extension myViewController: ScreenSizeProtocolExt {    
let imageToUse = setupBG()
// Here is get an error: 'Use of instance member 'setupBG' on type 'inout Self'; did you mean to use a value of type 'inout self' instead?
let image = UIImage(named: imageToUse)
imageView.image = image
}

isn't legal. The main thing is that extensions can't add new stored properties -- so you can't do:

let imageToUse = setupBG()

In an extension.

Also, this line:

imageView.image = image 

Is illegal outside of a func.

As to what you need here, this all seems like overkill. Why extend this to the viewControllers with protocols? You have a function that returns an imageName -- that could be anywhere (just a free func, not in a class).

Then, in the viewControllers, just set the image view's image to the name returned by this function.

Extensions are a way to give more interface to a class -- you can't make the class call the methods automatically just via extension.

Why does a mutating method in a Swift protocol infinitely recurse unless only an extension method?

With your change in the second example, by including the m in the protocol definition, that instructs Swift to employ dynamic dispatch. So when you call p.m(), it dynamically determines whether the object has overridden the default implementation of the method. In this particular example, that results in the method recursively calling itself.

But in the first example, in the absence of the method being part of the protocol definition, Swift will employ static dispatch, and because p is of type P, it will call the m implementation in P.


By way of example, consider where the method is not part of the protocol definition (and therefore not in the “protocol witness table”):

protocol P {
// func method()
}

extension P {
func method() {
print("Protocol default implementation")
}
}

struct Foo: P {
func method() {
print(“Foo implementation")
}
}

Because the foo is a P reference and because method is not part of the P definition, it excludes method from the protocol witness table and employs static dispatch. As a result the following will print “Protocol default implementation”:

let foo: P = Foo()
foo.method() // Protocol default implementation

But if you change the protocol to explicitly include this method, leaving everything else the same, method will be included in the protocol witness table:

protocol P {
func method()
}

Then the following will now print “Foo implementation”, because although the foo variable is of type P, it will dynamically determine whether the underlying type, Foo, has overridden that method:

let foo: P = Foo()
foo.method() // Foo implementation

For more information on dynamic vs static dispatch, see WWDC 2016 video Understanding Swift Performance.

Why can't I change variables in a protocol extension where self is a class?

Your example doesn't compile because MyProtocol isn't class-bound, and as such can have mutating requirements and extension members. This includes property setters, which are by default mutating. Such members are free to re-assign a completely new value to self, meaning that the compiler needs to ensure they're called on mutable variables.

For example, consider:

public protocol MyProtocol {
init()
var i: Int { get set } // implicitly `{ get mutating set }`
}

extension MyProtocol {
var i: Int {
get { return 0 }
// implicitly `mutating set`
set { self = type(of: self).init() } // assign a completely new instance to `self`.
}
}

public protocol MyProtocol2 : class, MyProtocol {}

public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // error: Cannot assign to property: 'self' is immutable
}
}

final class C : MyProtocol2 {
init() {}
}

let c = C()
c.a()

If this were legal, calling c.a() would re-assign a completely new instance of C to the variable c. But c is immutable, therefore the code is not well formed.

Making MyProtocol class bound (i.e protocol MyProtocol : AnyObject or the deprecated spelling protocol MyProtocol : class) works because now the compiler knows that only classes can conform to MyProtocol. Therefore it imposes reference semantics by forbidding mutating requirements and extension members and therefore prevents any mutations of self.

Another option at your disposal is to mark the setter for the requirement i as being nonmutating – therefore meaning that it can only be satisfied by a non-mutating setter. This makes your code once again well-formed:

public protocol MyProtocol {
init()
var i: Int { get nonmutating set }
}

public protocol MyProtocol2 : class, MyProtocol {}

public extension MyProtocol2 where Self : AnyObject {
func a() {
i = 0 // legal
}
}


Related Topics



Leave a reply



Submit