Ownership with inout parameter

I have found a strange situation possible:

func foo(dict: inout [String: Any]) {
  mergeDict(&dict, with: dict)
}

In general, this occurs when passing inout argument to another function with two arguments when one of them is also inout. This also includes all standard operators like +=, -=, *= ...

For now as I understand, compiler makes implicit copy. In Swift 5.9 borrowing / consuming modifiers can be used. Making borrowing and consuming conventions in func mergeDict explicit, seems that such situation should not be possible.

Should we improve compiler diagnostics to emit a warning in such cases and require an explicit copy of inout parameter?

1 Like

What exactly do you find strange or wrong?

I believe that this fragment:

func mergeDict(_ dict: inout [String: Any], with other: [String: Any]) {
    for (key, value) in other {
        dict[key] = value
    }
}

func foo(dict: inout [String: Any]) {
    mergeDict(&dict, with: dict)
}

is 100% equivalent to this fragment:

func mergeDict(_ dict: inout [String: Any], with other: [String: Any]) {
    var copy = dict
    for (key, value) in other {
        copy[key] = value
    }
    dict = copy
}

func foo(dict: inout [String: Any]) {
    var copy = dict
    mergeDict(&copy, with: dict)
    dict = copy
}
1 Like

This is logically useless operation. I'm trying to understand can we add compiler diagnostics or will adding borrowing modifier prevent this, so:

func foo(dict: inout [String: Any]) {
  mergeDict(&dict, with: dict) // warning or error

  let explicitCopy = dict
  mergeDict(&dict, with: explicitCopy) // ok

  var explicitMutableCopy = dict
  explicitMutableCopy[key] = value
  mergeDict(&dict, with: explicitMutableCopy) // ok

  mergeDict(&dict, with: [:])
}

I see what you mean. So is this:

var x = 42
x |= x

Can you please what |= operator does in this situation?

I mean it's a "no-op" operation compiler doesn't complaining about, same as here:

var x = 42
x = x | x

var y = true
y = y || y