Scala 3: defining custom control structures

Viewed 61

I want to define my own C++-17-like if statement. (It's an exercise in metaprogramming.) I easily could define:

inline def xif[T](inline cond: Boolean)(inline body: T) = if cond then body

and/or

def yif[T](cond: Boolean)(body: => T) = if cond then body

so that these three definitions output the same numbers:

def testxif =
  for i <- 0 until 10 do
    xif {val j = i*3; j%2==0} {println(i)}

def testyif =
  for i <- 0 until 10 do
    yif {val j = i*3; j%2==0} {println(i)}

def testif =
  for i <- 0 until 10 do
    if ({val j = i*3; j%2==0}) {println(i)}

It is remarkable that xif and if generate the same code, good job, Scala! (The inline parameter is indeed inlined, while the "by-name" parameter (marked with "equals-greater" =>) is invoked as a lambda.)

public void testxif() {
    .MODULE$.until$extension(scala.Predef..MODULE$.intWrapper(0), 10).foreach((i) -> {
        int j = i * 3;
        if (j % 2 == 0) {
            scala.Predef..MODULE$.println(BoxesRunTime.boxToInteger(i));
        }

    });
}

public void testyif() {
    .MODULE$.until$extension(scala.Predef..MODULE$.intWrapper(0), 10).foreach((i) -> {
        int j = i * 3;
        this.yif(j % 2 == 0, () -> {
            this.testyif$$anonfun$1$$anonfun$1(i);
            return BoxedUnit.UNIT;
        });
    });
}

public void testif() {
    .MODULE$.until$extension(scala.Predef..MODULE$.intWrapper(0), 10).foreach((i) -> {
        int j = i * 3;
        if (j % 2 == 0) {
            scala.Predef..MODULE$.println(BoxesRunTime.boxToInteger(i));
        }

    });
}

private final void testyif$$anonfun$1$$anonfun$1(final int i$1) {
    scala.Predef..MODULE$.println(BoxesRunTime.boxToInteger(i$1));
}

I could easily define ifElse, but this would be rather lame. I want an optional xelse part, probably on the next line.

And I want values defined in the if part to be visible in the then part. In C++ 17, we can write:

#include <stdio.h>

int main() {
  for(int i=0; i<10; i++) {
    if(int j=i*3; j%2==0) {
      printf("%d %d\n",i,j);
    }
  }
}

(note that j is defined in the if part)

But in Scala 3 this does not work, neither with my current xif nor with the out-of-box if:

def testxif2 =
  for i <- 0 until 10 do
    xif {val j = i*3; j%2==0} {println(i + " " + j)}
//                                               ^
//                                               Not found: j

Questions:

Given all this Scala-3 metaprogramming,

  1. How do I implement an optional else part? (Let us call it xelse)
  2. How do I make the values defined in the if part visible in the then and else parts?
0 Answers
Related