Passing an optional first argument to sequence(first:next:)


(Braeden Profile) #1

Okay, I’m actually confused about the current state of things.

Earlier, this was introduced:

// This function is silly,
// but useful functions may take a similar form
func foo(x: Int?) -> Int? {
  guard let x = x else { return 0 }
  return x > 12 ? nil : x + 1
}

let a: Int? = nil
for i in sequence(first: a, next: { foo($0) })
{
  // This is a pretty useless thing to do,
  // but there are useful things that can be done
  // without checking whether `i == nil`
  print(i)
}

…and it returns 14 lines of output. But this doesn’t make sense. I expected the anonymous closure for next in sequence(first: Int?, next: (Int?) -> Int??) to raise (foo($0)) to (Optional(foo($0))) to avoid having the type signature end up being (Int?) -> Int?. In that case, the result of (foo($0)) would always be encapsulated in Optional.Some(), so at the 15th run, it would return (Optional.Some(nil)). Yet it stops when foo returns nil. Why is this?

And if you replace "next: { foo($0) }" with "next: foo", then it compiles with the same result. Replacing it with “next: { Optional(foo($0)) }” gives the result I originally expected.

This actually would have made more sense to me if the signature was “func sequence<T>(first: T?, next: (T) -> T?) -> UnfoldFirstSequence<T>”, and “let a = nil" would have caused an empty sequence. I understand that this is a situation that would change unexpectedly if this stdlib change occurred, but I sure think the changed sequence(first:next:) function makes for a more understandable result.


(Xiaodi Wu) #2

Okay, I’m actually confused about the current state of things.

Earlier, this was introduced:

// This function is silly,
// but useful functions may take a similar form
func foo(x: Int?) -> Int? {
  guard let x = x else { return 0 }
  return x > 12 ? nil : x + 1
}

let a: Int? = nil
for i in sequence(first: a, next: { foo($0) })
{
  // This is a pretty useless thing to do,
  // but there are useful things that can be done
  // without checking whether `i == nil`
  print(i)
}

…and it returns 14 lines of output. But this doesn’t make sense. I
expected the anonymous closure for next in sequence(first: Int?, next:
(Int?) -> Int??) to raise (foo($0)) to (Optional(foo($0))) to avoid having
the type signature end up being (Int?) -> Int?. In that case, the result
of (foo($0)) would always be encapsulated in Optional.Some(), so at the
15th run, it would return (Optional.Some(nil)). Yet it stops when foo
returns nil. Why is this?

Yeah, I think that's a bug :slight_smile: Which means it should be fixed whether we
change the function signature or not.

···

On Tue, Aug 16, 2016 at 7:34 PM, Braeden Profile via swift-evolution < swift-evolution@swift.org> wrote:

And if you replace "next: { foo($0) }" with "next: foo", then it compiles
with the same result. Replacing it with “next: { Optional(foo($0)) }”
gives the result I originally expected.

This actually would have made more sense to me if the signature was “func
sequence<T>(first: T?, next: (T) -> T?) -> UnfoldFirstSequence<T>”, and
“let a = nil" would have caused an empty sequence. I understand that this
is a situation that would change unexpectedly if this stdlib change
occurred, but I sure think the changed sequence(first:next:) function makes
for a more understandable result.

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


(Xiaodi Wu) #3

Okay, I’m actually confused about the current state of things.

Earlier, this was introduced:

// This function is silly,
// but useful functions may take a similar form
func foo(x: Int?) -> Int? {
  guard let x = x else { return 0 }
  return x > 12 ? nil : x + 1
}

let a: Int? = nil
for i in sequence(first: a, next: { foo($0) })
{
  // This is a pretty useless thing to do,
  // but there are useful things that can be done
  // without checking whether `i == nil`
  print(i)
}

…and it returns 14 lines of output. But this doesn’t make sense. I
expected the anonymous closure for next in sequence(first: Int?, next:
(Int?) -> Int??) to raise (foo($0)) to (Optional(foo($0))) to avoid having
the type signature end up being (Int?) -> Int?. In that case, the result
of (foo($0)) would always be encapsulated in Optional.Some(), so at the
15th run, it would return (Optional.Some(nil)). Yet it stops when foo
returns nil. Why is this?

Yeah, I think that's a bug :slight_smile: Which means it should be fixed whether we
change the function signature or not.

I take that back. Not a bug. `next` would have type `@escaping (Int?) ->
Int??`.

When the result of `foo($0)` is `nil` (i.e. `Optional<Int>.none`) and
that's used as the return value for `next`, it gets promoted to
`Optional<Optional<Int>>.none`, not to `Optional<Optional<Int>>.some(nil)`.
It makes sense, despite looking like gibberish.

···

On Tue, Aug 16, 2016 at 7:44 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Tue, Aug 16, 2016 at 7:34 PM, Braeden Profile via swift-evolution < > swift-evolution@swift.org> wrote:

And if you replace "next: { foo($0) }" with "next: foo", then it compiles
with the same result. Replacing it with “next: { Optional(foo($0)) }”
gives the result I originally expected.

This actually would have made more sense to me if the signature was “func
sequence<T>(first: T?, next: (T) -> T?) -> UnfoldFirstSequence<T>”, and
“let a = nil" would have caused an empty sequence. I understand that this
is a situation that would change unexpectedly if this stdlib change
occurred, but I sure think the changed sequence(first:next:) function makes
for a more understandable result.

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