Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-6892] lazy sequences are a bit tricky with sometimes sub-optimal overload resolution #49441

Open
weissi opened this issue Feb 1, 2018 · 7 comments
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella

Comments

@weissi
Copy link
Member

weissi commented Feb 1, 2018

Previous ID SR-6892
Radar None
Original Reporter @weissi
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Standard Library
Labels Bug
Assignee None
Priority Medium

md5: 33d7c6781173343b1032a21d8fde0644

Issue Description:

what I want to write is:

Array(((0...).map { $0 * 17 }.prefix(while: { $0 <= 123}))

but done lazily. So my first idea was

Array(((0...).lazy.map { $0 * 17 }.lazy.prefix(while: { $0 <= 123}))

which unfortunately doesn't work as it tries to create an array of all integers first 😉. Then I helped the compiler a little by doing this

Array(((0...).lazy.map { $0 * 17 } as LazyMapSequence<CountablePartialRangeFrom<Int>, Int>).lazy.prefix(while: { $0 <= 123}))

which works fine but is very ugly.

Now it turns out that you can do

Array(((0...).lazy.map { $0 * 17 }.prefix(while: { $0 <= 123}))

which works! The odd thing is that adding an extra lazy makes it less lazy 😃

@lorentey
Copy link
Member

lorentey commented Feb 1, 2018

This looks like a weird wrinkle in overload resolution. FWIW, adding this explicit overload to the stdlib makes the second snippet work as expected:

extension LazyMapSequence {
  public var lazy: LazyMapSequence { return self }
}

(We have the same definition in a conditional extension on LazySequenceProtocol, but sadly that doesn't seem strong enough.)

@moiseev
Copy link
Mannequin

moiseev mannequin commented Feb 1, 2018

/cc @xedin

@moiseev
Copy link
Mannequin

moiseev mannequin commented Feb 1, 2018

FWIW: on current master the double-lazy expression is ambiguous, so the only option is to use the single .lazy, which is an intended use anyway.

@xedin
Copy link
Member

xedin commented Feb 1, 2018

@moiseev Interestingly enough version with two "lazy" doesn't type-check on master because it's ambiguous in both 3 and 4 mode:

(0...).lazy.map { $0 * 17 }.lazy.prefix(while: { $0 <= 123})
error: ambiguous use of 'map'
(0...).lazy.map { $0 * 17 }.lazy.prefix(while: { $0 <= 123})
       ^
Swift.LazySequenceProtocol:5:17: note: found this candidate
    public func map<U>(_ transform: @escaping (Self.Elements.Element) -> U) -> LazyMapSequence<Self.Elements, U>
                ^
Swift._SequenceWrapper:2:17: note: found this candidate
    public func map<T>(_ transform: (Self.Element) throws -> T) rethrows -> [T]
                ^

@moiseev
Copy link
Mannequin

moiseev mannequin commented Feb 1, 2018

@xedin yeah I noticed. And it's great. I nudges the user toward the right solution, i.e. using a single .lazy.

@lorentey
Copy link
Member

lorentey commented Feb 1, 2018

Oh right, I tried my stdlib workaround on a swift-4.1 build.

A direct definition of `LazyMapSequence.lazy` makes the expression compile on master, too. (I don't think we need to add it, though.)

@weissi
Copy link
Member Author

weissi commented Feb 13, 2018

@moiseev filed SR-6991 where the opposite is true (extra .lazy keeps it lazy).

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. standard library Area: Standard library umbrella
Projects
None yet
Development

No branches or pull requests

3 participants