[swift-evolution] Proposal: Add SequenceType.first

Kevin Ballard kevin at sb.org
Sat Jan 2 18:58:36 CST 2016


On Sat, Jan 2, 2016, at 12:13 PM, Brent Royal-Gordon wrote:
> > Why should we absolutely add methods with unclear meanings or behavior, when there are already perfectly clear, if verbose, alternatives? seq.generate().next() may not be nice, but no one can get fooled by it.
> 
> Well, for one thing, because it doesn't work. You can't call a mutating method directly on a return value without assigning it to a variable first. And put simply, a temporary variable seems a bridge too far to me.

Exactly. If `seq.generate().next()` worked, I'd be perfectly happy with that. I'd be tempted to submit a proposal saying this should be legal, but I believe that disallowing mutating methods on temporaries is an intentional decision that was intended to prevent the user from writing code that looks like it's mutating something that it isn't.

For example, given the following interface:

struct Foo {
    var ary: [Int] { get }
}

Allowing mutating of temporaries would let me write code like

func foo(x: Foo) -> Int? {
    return x.ary.popLast()
}

and yet this won't actually mutate the array at all (and it will incur an unwanted copy of the array storage that is immediately thrown away).

We could try and come up with some workaround, like maybe an attribute on `mutating func next()` that says "this may be called on a temporary", but it seems kind of hacky. And I can't think of anything other than `GeneratorType.next` that actually wants this behavior anyway (the closest alternative I can think of is passing a scalar as an UnsafePointer or UnsafeMutablePointer to a C function where you don't actually care about the output, where in C you can actually say something like `&(int){42}` if you want, but I haven't actually hit that case in Swift yet and it's pretty rare anyway).

Incidentally, the same rule is also what prohibits arrays from being passed to an inout parameter where a downcast is required. Arrays implicitly downcast as needed to simulate covariance on its element type, e.g. if U <: T then [U] can be used where a [T] is expected because an implicit downcasted copy is made. But you cannot pass a [U] to a function that expects an inout [T] because temporaries are immutable (and implicit array conversion produces a temporary).

-Kevin Ballard


More information about the swift-evolution mailing list