3

The following code:

protocol SomeProtocol {}
class SomeClass: SomeProtocol {}

private func doSomethingWith(inout someVar: SomeProtocol) {}

private var someGlobalVar = SomeClass() // inferring SomeClass's type

doSomethingWith(&someGlobalVar)

produces the following error:

Cannot invoke 'doSomethingWith' with an argument list of type '(inout SomeClass)'

Changing the penultimate line to private var someGlobalVar: SomeProtocol = SomeClass() resolves the error.

Subj.

mesmerizingr
  • 1,417
  • 1
  • 18
  • 25
  • I'm surprised this question does not have more views! It seems like something more people would run into...then again, maybe people aren't mutating objects through functions with protocol parameters any more. :) – Ray Toal May 15 '16 at 16:14
  • @RayToal perhaps that's because `inout` variables isn't so popular choice when designing your architecture ;) – mesmerizingr May 15 '16 at 18:15
  • 1
    True, and it's for the better. The class-only protocol solves this problem beautifully, but it's not obvious. – Ray Toal May 15 '16 at 21:03

2 Answers2

5

In addition to what @Sulthan said, there are two more possible solutions, depending on what your function needs to do.

You can make the function generic:

func doSomethingWith<T : SomeProtocol>(inout someVar: T) {}

Now you can pass an instance of any class conforming to the protocol:

var someGlobalVar = SomeClass()
doSomethingWith(&someGlobalVar)

If you only work with instances of a class and the function only modifies properties of the object pointed-to by the instance, then you don't need an inout-parameter at all, since classes are reference types. You only need to mark the protocol as a "class protocol":

protocol SomeProtocol : class {
    var name : String { get set }
}
class SomeClass: SomeProtocol {
    var name : String = ""
}

func doSomethingWith(someVar: SomeProtocol) {
    // Modify the object:
    someVar.name = "modfied"
}

var someGlobalVar = SomeClass()
doSomethingWith(someGlobalVar)
print(someGlobalVar.name) // "modified"
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
3

When you assign a SomeClass instance to a variable while declaring, the variable type is inferred to be SomeClass. The same as writing

private var someGlobalVar: SomeClass = SomeClass()

However, when passing to an inout parameter, the function can assign another instance to that variable, e.g.

private func doSomethingWith(inout someVar: SomeProtocol) {
    someVar = OtherClass()
}

Now you have a type mismatch. The error you are seeing is Swift preventing you getting a similar problem.

In other words: if you are passing a variable to a function and you know that the function can assign any instance adopting SomeProtocol to that variable, you have to use a variable that can actually hold any instance adopting SomeProtocol:

private var someGlobalVar: SomeProtocol
Sulthan
  • 128,090
  • 22
  • 218
  • 270