3

Currently I'm working on my new App written with Swift 2.0. Today I faced two strange errors in Xcode beta 5. I'd love if someone with a previous beta version of Xcode can confirm if I'm right or not. I also could misunderstand something, so I'll appreciate any feedback.

Here is some example code that made me struggle a while:

// Frist bug
protocol SomeProtocol {
 var someArray: [String] { get set } // #1 bug
}
extension SomeProtocol {
 func someFunction(someString: String) {
 self.someArray.append(someString) // #1: Immutable value of type '[String]' only has mutating members named 'append'
 }
}
// Second bug
protocol SomeInterfaceProtocol {
 var someBool: Bool { get set } // #2 bug
}
class SomeClass: SomeInterfaceProtocol {
 var someBool: Bool = false
 func returnInterface() -> SomeInterfaceProtocol {
 return self
 }
}
let someInstance = SomeClass()
// can't set the value
someInstance.returnInterface().someBool = true // #2: Cannot assign to property: function call returns immutable value
asked Aug 16, 2015 at 19:53

2 Answers 2

2

The first error can be solved if you add the modifier mutating before the extension func declaration like this:

mutating func someFunction(someString: String) {

I suspect that's a change in the language.

The other one puzzles me as well. At least, here's a work-around:

var c = someInstance.returnInterface()
c.someBool = true
answered Aug 16, 2015 at 20:21
Sign up to request clarification or add additional context in comments.

6 Comments

Solved the first one with this, I fully forgot that my protocol could also be a structure type. Another way to solve the first problem is to say the protocol it should be for classes only protocol SomeProtocol: class { /*...*/ } and it just works. My bad on that one. :D The second workaround works, but I assume this one is a real bug of the beta.
Yes, I'd also consider that a bug. Do us all a favor and go to bugreporting.apple.com and write it up.
I will, which product should I choose? I posted 3 other Swift 2.0 bugs at Xcode 7 beta 3 times as Sample Code, but nothing happened yet.
I post them as "Developer Tools" issues. Also, if you post interesting issues, it's nice to also post them on openradar.appspot.com - and yes, it can take its time until Apple fixes them, if ever :)
I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }. Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.
|
2

I think the second one isn't a bug as well for the same reason that you can't modify an item in a dictionary directly, or that you can't change elem in for elem in array { ... }.

Something has to be saved to be able to change it. Because you're returning the protocol type, the compiler can't know whether it's a struct or a class, whereas if it's a struct the operation of changing it would have no effect because it's not persisted in any way and structs aren't passed by reference. That's why Thomas' workaround works. Maybe it'll work too if returnInterface returned a class instance, instead of the protocol type.

EDIT: Just tried it out: Indeed it works either if you return SomeClass instead of SomeInterfaceProtocol or if you change the protocol to a class protocol, as it can't be a struct

protocol SomeInterfaceProtocol : class {
 var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
 var someBool: Bool = false
 func returnInterface() -> SomeInterfaceProtocol {
 return self
 }
}

or

protocol SomeInterfaceProtocol {
 var someBool: Bool { get set }
}
class SomeClass: SomeInterfaceProtocol {
 var someBool: Bool = false
 func returnInterface() -> SomeClass {
 return self
 }
}

both work

answered Aug 16, 2015 at 20:53

5 Comments

Oh my, I did the same mistake twice. The first one solved my problem. So this isn't a bug at all. It's my stupidness. Thank you.
Well, it still makes no sense to me why the immediate result from returnInterface() causes a different reaction from the compiler than going through a helper variable. That's not logical in my book.
@ThomasTempelmann Consider the following example which throws an error: func get() -> Int { return 1 }; get()++ What should the ++ change? The 1 in the function? If you change it to var x = get(); x++ it works. The general rule is: You cannot use a changing operation without the var keywords. An even simpler example than the one above would be 1++ (throws an error as well)
Out of curiosity, what is the purpose of the returnInterface() function? It seems it is redundant at best and adds unwanted restrictions for the compiler at worst. Instantiating an instance of SomeClass and setting someBool on that instance works fine, so why the middle man?
Another way to fix the second error is to tell the compiler that the protocol only applies to classes protocol SomeInterfaceProtocol: class {... That way it knows that returnInterface() returns a reference type and it is safe to call mutating methods.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.