3

It seems that Xcode 9.3 does fix one issue I was having, but in Swift 4.1 the second half of this code still doesn't compile:

var obj: SomeClass!    ; class SomeClass {}

func inoutFunc(_: inout SomeClass?) {}
inoutFunc(&obj)     // works

func pointerFunc(_: UnsafeMutablePointer<SomeClass?>) {}
pointerFunc(&obj)  // <-- COMPILER ERROR

The call to inoutFunc is now fine, but the call to pointerFunc still gives me an error:

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

Or in the original context:

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

Similar to my Swift 4.0 issue (where the inoutFunc didn't compile either) if I change the declaration to var obj: SomeClass? then the second function call compiles without complaint.

Is this another lingering Swift bug related to Implicitly Unwrapped Optionals, or would this UnsafeMutablePointer situation not be expected to work like the inout version now does? Is there a relatively clean workaround?


Background:

In the actual code, the pointerFunc call is an Apple framework function which either initializes the instance or returns an error status.

Since I already guard AppleFrameworkInitializer(&obj) == noErr else { /* … */ }, I don't want to deal with re-assigning from a temporary optional, or have to constantly unwrap obj! in all the code that follows.

That is, this seems like a legitimate use case for Implicitly Unwrapped Optionals and I'm wondering why I still can't use one here.

natevw
  • 13,661
  • 7
  • 58
  • 81
  • Assuming this is still a Swift bug, I added this example as a comment on [SR-3512](https://bugs.swift.org/browse/SR-3512?focusedCommentId=34815#comment-34815). – natevw Apr 19 '18 at 19:17
  • Another lingering bug, I'm afraid. It has already been fixed though (almost certainly as a result of the recent-ish work to completely remove IUOs from the type system) – it compiles in the latest dev snapshots, and therefore will make it into 4.2 (final re-branch from master is April 20). – Hamish Apr 19 '18 at 19:19
  • Thanks for testing, MartinR and Hamish! Glad they're still making progress here beyond the 4.1 release… I guess I'll leave my code TODO for now. (Happy to accept this result as an answer if someone wants to write it up, otherwise I can myself in a few days…) – natevw Apr 19 '18 at 19:22
  • I'll write up an answer in a sec :) The good news at least is that as of Swift 4.2, the vast majority of IUO incompatibility with Optional issues should be all fixed as now IUOs are actually now modelled as Optionals in the type system (previously they were modelled as a separate type with special logic to make them look like Optionals). – Hamish Apr 19 '18 at 19:29

1 Answers1

2

I'm afraid this is another lingering bug around implicitly unwrapped optionals (IUOs).

It has already been fixed though (almost certainly as a result of the recent-ish work to completely remove IUOs from the type system) – it compiles in the latest dev snapshots, and therefore will make it into 4.2 (final re-branch from master is April 20).

Until 4.2 rolls around, one possible workaround would be to use a forwarding computed variable in order to treat the IUO as a strong Optional type:

class SomeClass {}

var obj: SomeClass!
var _optionalObj: SomeClass? {
  get { return obj }
  set { obj = newValue }
}

func pointerFunc(_: UnsafeMutablePointer<SomeClass?>) {}
pointerFunc(&_optionalObj)

(that is, assuming you're okay with having the pointer point to a temporary value – i.e you're not relying on the pointer value being stable or unique, such as you would be if this were to be used, for example, as an associated object key)

Hamish
  • 69,859
  • 16
  • 167
  • 245