josh
josh

Reputation: 1554

Use pattern matching in function parameters

I am wondering if it's possible to specify the exact constructor of a node that is being passed as a parameter to a function. For example if, in the lang::java::m3::AST::Declaration ADT, I'm passing a node that I know has to be a \class() to a function is there a way to specify this?

Right now I have:

public void foo(lang::java::m3::AST::Declaration dec) { ... }

But I would like something akin to:

public void foo(lang::java::m3::AST::\class(a,b,c,d) dec) { ... }

This way I wouldn't have to do a match inside of foo to get to portions of the class node.

Or, is there a different and more effective way to do this.

Thanks!

Upvotes: 2

Views: 230

Answers (1)

Jurgen Vinju
Jurgen Vinju

Reputation: 6696

Certainly, and moreover you can have full pattern matching as parameters and you don't necessarily have to mention the full path:

void foo(class(str a, str b, str c, list[Decl] d)) { ... }

or to also bind e to the full class declaration:

void foo(Decl e:class(str a, str b, str c, list[Decl] d)) { ... }

Note that the open variables in a pattern need to be typed (unlike when the pattern is nested inside the body of the function), this is because we do not wish to propagate type errors beyond function boundaries.

Or, you might want to match more deeply and select only certain declarations:

void foo(class("MyClass", str _, str _, list[Decl] _)) { ... }

Or, a nested deep match matching all classes which have an equals method:

void foo(class(str name, str _, str _, /method("equals",_,_)) {  ... }

The essence of Rascal function definitions is that they may be overloaded and that dispatch is done dynamically based on pattern matching. You are required as the programmer to make the patterns mutually exclusive, or if that is impossible you can use a default modifier to force a partial ordering.

For example, this is illegal because the pattern 0 overlaps with int n:

int f(0) = 1;
int f(int n) = f(n - 1) * n;

You can write this however:

int f(0) = 1;
default f(int n) = f(n - 1) * n;

Next to mutually exclusive, overloaded functions also need to be complete. This means for your class case that you will need a default definition for the other cases you don't match:

default void foo(Decl d) {
  throw "did not implement foo for <d>";
}

More information can be found here:

Upvotes: 2

Related Questions