Inline if statement mutating inout parameter in a

2019-02-25 07:04发布

问题:

I've run into a somewhat weird (compile time) error that I cannot make any sense out of. The error is given for the following snippet:

/* error: type 'Int1' does not conform to protocol 'BooleanType' */
let closure1 : (inout foo: Int) -> () = {
    foo -> () in
    (foo<0 ? (foo = -1) : (foo = 1))
}

Error: type 'Int1' does not conform to protocol 'BooleanType'

Note that Int1 is not a typo here.

Question 1: Why am I not allowed to use a single inline if statement (with result '()') as the implicit return type of a void return closure?

Question 2: Out of curiosity, what is the Int1 type? (Curiously enough the same error message, Int1 ... is given even if modifying the closure above to operate on different types in a similar manner).

Why is this of interest for me? I have a few closures that I would like to use in the anonymous form similar of closure1Anon below, but due to this error I can't.

Details and my own (non-fruitful) investigation into the matter follow below.


As described above, the error is prompted when---within a void return closure---using a single inline if statement which includes assignments to an inout parameter.

We can verify that result of an inline statement is the empty tuple value, (), consider e.g.:

var foo = -4
print((foo<0 ? (foo = -1) : (foo = 1)).dynamicType) // ()
print(foo)                                          // -1

... so it should be OK to use as return statement for a void return closure (see e.g. the assignment-followed-by-return example closure4 below).

Below follows the erroneous closure (closure1, closure1Explicit, closure1Anon) as well as five very similar/associated closures that work fine (closure2 through closure7).

/* error: type 'Int1' does not conform to protocol 'BooleanType' */
let closure1 : (inout foo: Int) -> () = {
    foo -> () in
    (foo<0 ? (foo = -1) : (foo = 1))
}

/* same error */
let closure1Explicit : (inout foo: Int) -> () = {
    foo -> () in
    return (foo<0 ? (foo = -1) : (foo = 1))
}

let closure1Anon : (inout foo: Int) -> () = { ($0<0 ? ($0 = -1) : ($0 = 1)) }

Ok:

/* The following are all OK */
let closure2 : (inout foo: Int) -> () = {
    (inout foo: Int) -> () in
    (foo<0 ? (foo = -1) : (foo = 1))
} // thanks @MartinR

let closure3 : (inout foo: Int) -> () = {
    foo -> () in
    let _ = (foo<3 ? (foo = 1) : (foo = 2))
}

let closure4 : (inout foo: Int) -> () = {
    foo -> () in
    (foo<3 ? (foo = 1) : (foo = 2))
    return ()
}

let closure5 : (inout foo: Int) -> () = {
    foo -> () in
    let bar = (foo<3 ? (foo = 1) : (foo = 2))
    return bar
}

/* Error must be related to inout as the two
   following closures works fine */
let closure6 : () -> () = {
    () -> () in
    var a = 0
    return (a<0 ? (a = -1) : (a = 1))
}

var globalVar = 1
let closure7 : () -> () = {
    () -> () in
    (globalVar<0 ? (globalVar = -1) : (globalVar = 1))
}

I can't for the world figure out why closure1/closure1Explicit/closure1Anon above yields this error. Possibly someone can shed some light on this for me?


Final note: the following seemingly similar SO thread seems non-relevant in this case:

  • Type 'Int' does not conform to protocol 'BooleanType'

I'm using Swift 2.1.1 and Xcode 7.2.1.

回答1:

(Adding this thin answer to close the no-longer-relevant question)

The bug described in the question above is no longer present in Swift 2.2 (Xcode 7.3) nor in the Swift 3.0-dev at IBM Sandbox; so the issue seems to have been fixed in with the release of Swift 2.2.