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

Cannot pass inline iterator to inline iterator #4516

Open
flyx opened this issue Jul 26, 2016 · 4 comments
Open

Cannot pass inline iterator to inline iterator #4516

flyx opened this issue Jul 26, 2016 · 4 comments
Assignees

Comments

@flyx
Copy link
Contributor

flyx commented Jul 26, 2016

This code works:

iterator test2(it: iterator(): int): int =
  for i in it():
    yield i*2
iterator test1(): int {.closure.} =
  yield 10
  yield 20
  yield 30
for i in test2(test1()):
  echo i

But this does not:

iterator test2(it: iterator(): int {.inline.}): int =
  for i in it():
    yield i*2
iterator test1(): int =
  yield 10
  yield 20
  yield 30
for i in test2(test1()):
  echo i

Error message:

test1.nim(2, 14) Error: type mismatch: got (int)
but expected one of:
iterator items[IX, T](a: array[IX, T]): T
iterator items[](E: typedesc[enum]): E:type
iterator items(a: string): char
iterator items[T](s: Slice[T]): T
iterator items[T](a: openArray[T]): T
iterator items[T](a: seq[T]): T
iterator items[T](a: set[T]): T
iterator items(a: cstring): char

The manual states that:

If the for loop expression e does not denote an iterator and the for loop has exactly 1 variable, the for loop expression is rewritten to items(e)

This seems to happen here although it is an iterator. The manual also states that

Inline iterators are second class citizens; They can be passed as parameters only to other inlining code facilities like templates, macros and other inline iterators.

So it should be possible to pass an inline iterator to another inline iterator. Therefore, I think this is a bug. This issue is originally a StackOverflow question.

@zah zah self-assigned this May 13, 2017
@zah zah added the Iterators label May 13, 2017
@mratsim
Copy link
Collaborator

mratsim commented May 27, 2017

Relevant forum post: https://forum.nim-lang.org/t/2972 and pinging @cooldome who located the issue here in semFor proc.

Adding cooldome test case:

type InlineIterator[T] = iterator: T {.inline.}

let s = @[1, 2, 3, 4, 5]

iterator values: type(s[0]) {.inline.} =
  # Make argumentless iterator
  for val in s:
    yield val


iterator enumerate[T](it: InlineIterator[T]): (int,T) {.inline.} =
  var i = 0
  for val in it():
    yield (i, val)
    inc i

for tup in enumerate(values):
  echo tup

Error

playground_it.nim(17, 21) template/generic instantiation from here
playground_it.nim(13, 16) Error: type mismatch: got (int)
but expected one of:
iterator items[IX, T](a: array[IX, T]): T
iterator items(E: typedesc[enum]): E:type
iterator items(a: string): char
iterator items[T](s: Slice[T]): T
iterator items[T](a: openArray[T]): T
iterator items[T](a: set[T]): T
iterator items[T](a: seq[T]): T
iterator items(a: cstring): char

And my 2 test cases:

let s = @[1, 2, 3, 4, 5]

iterator values[T](s: seq[T]): T {.inline.}=
  # copy of `items` to test without its special meaning
  for val in s:
    yield val

iterator enumerate[T](it: iterator {. inline .}): auto {.inline.}=
  var i = 0
  for val in it:
    yield (i, val)
    inc i

iterator enumerate2[T](s: seq[T], it: iterator(a: seq[T]): T {. inline .}): T {.inline.}=
  var i = 0
  for val in s.it:
    yield (i, val)
    inc i


# for tup in s.values.enumerate:
#   echo tup
# inline_it.nim(21, 20) Error: type mismatch: got (int)
# but expected one of:
# iterator enumerate[T](it: iterator): auto

for tup in enumerate2(s, values):
  echo tup
# inline_it.nim(27, 22) template/generic instantiation from here
# inline_it.nim(16, 15) Error: type mismatch: got (int)
# but expected one of:
# iterator items[IX, T](a: array[IX, T]): T
# iterator items(E: typedesc[enum]): E:type
# iterator items(a: string): char
# iterator items[T](s: Slice[T]): T
# iterator items[T](a: openArray[T]): T
# iterator items[T](a: set[T]): T
# iterator items[T](a: seq[T]): T
# iterator items(a: cstring): char

@mratsim
Copy link
Collaborator

mratsim commented Jul 3, 2018

Related requests for inline iterator chaining on the forum:

@metagn
Copy link
Collaborator

metagn commented Apr 20, 2023

it should be possible to pass an inline iterator to another inline iterator.

I mean it doesn't make much sense as a runtime argument, but you can use it as a compile time argument:

iterator test2(it: static(iterator(): int {.inline.})): int =
  for i in it():
    yield i*2
iterator test1(): int =
  yield 10
  yield 20
  yield 30
for i in test2(test1):
  echo i

@beef331
Copy link
Collaborator

beef331 commented Apr 20, 2023

That works if you only want a specific interface, but really iterable[int] should be pasted where called and be a valid parameter for inline iterators in my opinion.

With #21627 we can atleast write code like https://github.com/beef331/slicerator/blob/itermacros/src/itermacros.nim#L45-L115

That allows abstracting over iterators. As can be seen here https://github.com/beef331/slicerator/blob/itermacros/tests/titermacros.nim

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants