Skip to content

Conversation

timotheecour
Copy link
Member

@timotheecour timotheecour commented May 17, 2021

finally gotten around to publishing a PR for this.

this is essentially D's static foreach (https://dlang.org/spec/version.html#staticforeach), which is very useful, but more flexible, and implemented in library code.

by design, it:

  • unrolls in caller scope, but the template/gensym/inject rules apply, see examples.
  • allows unrolling not just values, but also types, undefined idents, etc...

examples

  runnableExamples:
    var msg = ""
    for T in staticUnroll([int, float]):
      var a: T # a is gensym'd so won't cause a redefinition error
      proc fn() {.gensym.} = discard # gensym needed here
      proc fn2(a: T): auto = a # regular overloading here
      msg.add $T & " "
    assert msg == "int float "
    assert fn2(1.1) == 1.1 # `staticUnroll` is evaluated in caller scope

    # with 2 loop parameters, the 1st one is a const int indexing the element
    for i, T in staticUnroll([int, float, string]):
      when i == 0: assert T is int
      elif i == 1: assert T is float
      else: assert T is string

  runnableExamples:
    # example showing nested loops
    var msg = ""
    proc fn1(a: auto) = msg.add $("fn1", a)
    proc fn2(a: auto) = msg.add $("fn1", a)
    for fn in staticUnroll([fn1, fn2]):
      for T in staticUnroll([int, float]):
        fn(T.default)
    assert msg == """("fn1", 0)("fn1", 0.0)("fn1", 0)("fn1", 0.0)"""

  runnableExamples:
    # example showing passing untyped arguments to define variables
    for i, name in staticUnroll([name0, name1]):
      const name = i
    assert name1 == 1

note 1

I didn't name it unroll to avoid confusion with the deprecated {.unroll.}, and which could also be revived as a library solution, but has slightly different semantics

@Varriount
Copy link
Contributor

Varriount commented May 17, 2021

What differences are there between this and using a template, like so:

template foo(a): untyped =
  ...

for a in [int, float]:
  foo(a)

?

And is this applicable to while?

@timotheecour
Copy link
Member Author

What differences are there between this and using a template, like so:

for a in [int, float]: is not valid code

And is this applicable to while?

that wouldn't make much sense. staticUnroll unrolls the code

@Varriount
Copy link
Contributor

Varriount commented May 19, 2021

  • What are some concrete situations the proposed function would be used for, and why are existing approaches (static, macros, templates, etc.) inadequate?
  • Do these situations occur often enough to warrant the addition of this function to the standard library?
  • Rather than creating a one-off utility function for this specific situation, is there a way to make this kind of logic possible through the language, and satisfy a broader set of circumstances? Would it make semantic sense to allow conditional constructs present in a runtime context to evaluate static expressions at compile time?
    const types = [string, int]
    for T in types:
      var x {. gensym .}: T
    

In general, it seems to me like a number of PRs regarding additions to the standard library often revolve around "utility functions". The fact that it is felt that the standard library requires so many of these utility functions hints at implementation or design flaws present in the language and/or the standard library. Rather than being indirectly papered over, they should be directly addressed, ideally in a way that is natural for a newcomer to the language.

@Araq
Copy link
Member

Araq commented May 31, 2021

Let this one ripe as a Nimble module first.

@Araq Araq closed this May 31, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants