3

In Swift 4.0, the following code doesn't compile:

var str: String!
func someFunc(_ s: inout String?) {}
someFunc(&str)

Now I imagine that str is of type String? in actuality, and the Swift compiler seems to agree:

Cannot pass immutable value of type 'String?' as inout argument

I can fix this by either changing the the variable to type String? or the function parameters to (_ s: inout String!) but I don't understand why I have to. Swift already seems to agree that var str : String! is "of type 'String?'" — so why won't it let me pass it in here?

Is there another option I can use to keep my variable implicitly unwrapped, but still pass it to a function that modifies an optional?

I tried someFunc(&(str?)) and that just makes things weirder — then Swift complains:

Cannot pass immutable value of type 'String!' as inout argument".

So str is a String? but can't be passed as a String?, while str? is a String!?!

That code was actually:

var str: String!
func someFunc(_ x: inout String!) {}
someFunc(&(str?))

So maybe Swift is mistakenly saying the type of the parameter, rather than the value passed, in its error message…or something?

natevw
  • 13,661
  • 7
  • 58
  • 81
  • 1
    Why would you use an unsafe construct like an IUO? – Cristik Feb 15 '18 at 19:09
  • Probably an artifact of how IUO is implemented in the compiler. – Kevin Feb 15 '18 at 19:27
  • 3
    I agree your first example should compile under the rules set out by [SE-0054](https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md), that fact that it doesn't is a bug. It does compile using the latest 4.1 snapshot though, so looks like it has already been fixed. – Hamish Feb 15 '18 at 19:28
  • @Hamish Thanks — the example in this question did get fixed after upgrading to Xcode 9.3. But it turns out the actual function call wasn't an `inout` but rather an `UnsafeMutablePointer` which is apparently still broken…? See https://stackoverflow.com/questions/49928472/why-cant-i-pass-an-implicitly-unwrapped-optional-as-an-unsafemutablepointer for updated question. – natevw Apr 19 '18 at 19:08

1 Answers1

1

This is a known bug in the swift compiler. Hamish says in a comment this is fixed in a Swift 4.1 snapshot, so it may be fixed in the next Xcode release (9.3).

You can work around this by getting rid of the implicitly-unwrapped optional (IUO), which should be avoided anyway. Depending on why it's currently an IUO, either:

var str: String?
func someFunc(_ x: inout String?) {}
someFunc(&str)

or

var tmp: String?
func someFunc(_ x: inout String?) {}
someFunc(&tmp)
let str = tmp!

I strongly recommend the first, avoid force-unwrapping unless absolutely necessary.

Kevin
  • 48,059
  • 14
  • 92
  • 127
  • Thanks! In my case I wanted an IUO because its optionality was really just an artifact of a lower-level API I was using. Something ± like `var str : CFString!; let r = LowLevelGetter(&str); assert(r == noErr); NSLog("\(str)")` where, so long as there wasn't an error, the value is never `nil` once it is fetched. – natevw Feb 15 '18 at 19:54