[PITCH] Improve Optional Chain Assignment on Tuple Assignment

Hi all,

I have come up an improvement point about Optional Chain Assignment

1. Optional Chain Assignment not working with tuple assignment

optional chain assignment only work for directly assignment, not working with tuple assignment.

For example:

struct ListNode {
    var next: ListNode?
}

var previous: ListNode?
var current: ListNode? = ListNode()

//original version
let temp = current?.next
current?.next = previous
previous = current
current = temp

// tuple assignment version (currently compiler error)
(current?.next, previous, current) = (previous, current, current?.next)

error: cannot assign to immutable expression of type '_?'
(current?.next, previous, current) = (previous, current, current?.next)
~~~~~~~~~~~~~ ^

Should we improve this situation?

Thanks!

Hi all,

I have come up an improvement point about Optional Chain Assignment

1. Optional Chain Assignment not working with tuple assignment

optional chain assignment only work for directly assignment, not working with tuple assignment.

For example:

struct ListNode {
    var next: ListNode?
}

var previous: ListNode?
var current: ListNode? = ListNode()

//original version
let temp = current?.next
current?.next = previous
previous = current
current = temp

// tuple assignment version (currently compiler error)
(current?.next, previous, current) = (previous, current, current?.next)

error: cannot assign to immutable expression of type '_?'
(current?.next, previous, current) = (previous, current, current?.next)
~~~~~~~~~~~~~ ^

Should we improve this situation?

Optional chain assignment normally prevents the RHS of the assignment from being evaluated if the chain is aborted. What do you recommend as the semantics here? What if the optional element is later in the sequence?

I’m actually quite surprised by that behavior, and I consider this a gotcha I’ll have to keep in mind in the future. I would expect the rvalue calculation to execute, and if the lvalue ends up being nil it should just be ignored as if assigning to nil.property in objective C.

In particular, the following behavior is surprising to me:

func die<T>() -> T { fatalError() }

var x: Int? = nil
x = die() // Fatal trap, as expected

class C {
    var x: Int? = nil
}
var c: C? = nil
c?.x = die() // No trap!?
print("Still here") // Executes

And similarly,

func foo(_ c: C?) -> Never {
    c?.x = fatalError()
}

Obviously this doesn’t compile right now because of the type mismatch [Int? <- Never], but once `Never` becomes the universal subtype the type theorists have been rooting for, I’d expect it to compile but never return. However, given your ignore-rvalues evaluation it would still not compile. “But I’m calling fatalError, how can it possibly return?”

···

On Dec 15, 2017, at 11:24 PM, John McCall via swift-dev <swift-dev@swift.org> wrote:

On Dec 16, 2017, at 2:21 AM, Cao, Jiannan via swift-dev <swift-dev@swift.org <mailto:swift-dev@swift.org>> wrote:

John.
_______________________________________________
swift-dev mailing list
swift-dev@swift.org
https://lists.swift.org/mailman/listinfo/swift-dev

Optional chain assignment normally prevents the RHS of the assignment from being evaluated if the chain is aborted. What do you recommend as the semantics here? What if the optional element is later in the sequence?

John.

···

On Dec 16, 2017, at 2:21 AM, Cao, Jiannan via swift-dev <swift-dev@swift.org> wrote:

Hi all,

I have come up an improvement point about Optional Chain Assignment

1. Optional Chain Assignment not working with tuple assignment

optional chain assignment only work for directly assignment, not working with tuple assignment.

For example:

struct ListNode {
    var next: ListNode?
}

var previous: ListNode?
var current: ListNode? = ListNode()

//original version
let temp = current?.next
current?.next = previous
previous = current
current = temp

// tuple assignment version (currently compiler error)
(current?.next, previous, current) = (previous, current, current?.next)

error: cannot assign to immutable expression of type '_?'
(current?.next, previous, current) = (previous, current, current?.next)
~~~~~~~~~~~~~ ^

Should we improve this situation?