2

Why does the following work:

rascal>int increment(int x) = x + 1;
int (int): int increment(int);

rascal>int s = 5;
int: 5

rascal>increment(s);
int: 6

rascal>value vs = s;
value: 5

rascal>increment(vs);
int: 6

...while this fails:

rascal>data Side = leftSide() | rightSide();
ok

rascal>Side swap(leftSide()) = rightSide();
Side (Side): Side swap(Side);

rascal>Side swap(rightSide()) = leftSide();
Side (Side): Side swap(Side);

rascal>Side side = leftSide();
Side: leftSide()

rascal>swap(side)
Side: rightSide()

rascal>value vside = side;
value: leftSide()

rascal>swap(vside)
|stdin:///|(0,11,<1,0>,<1,11>): The called signature: swap(value),
does not match the declared signature:  Side swap(Side); (abstract pattern);  Side swap(Side); (abstract pattern);
pancake
  • 1,923
  • 2
  • 21
  • 42

1 Answers1

2

Excellent question. In fact this is undefined behavior. When the type checker is finished both versions should give a static error, namely: "increment is not fully defined on value, only on int" and "swap is not fully defined on value, only on Side" or something in this vain.

To work around the static error, in the future, you would have to add alternatives like this to complete the functions on the requested types:

default int increment(value _) { 
  throw "??? how to increment something that is not an int???"; 
}

default Side swap(value x) { 
    throw "??? how to swap something that is not a Side???";
}

And then you would have dynamic/run-time errors again, but only if the parameter is dynamically not an int or a Side respectively ;-)

Note that the default is necessary otherwise the value parameter would overlap with the original definition which is statically not allowed.

Jurgen Vinju
  • 6,393
  • 1
  • 15
  • 26
  • Thanks a lot for this answer! Just to be clear on the `default` part: the "input domain" (if you will) of `int f(int x)` overlaps with `int f(value x)`, so one of the two has to be the default? Rascal won't use the most specific pattern that is applicable? (int when called with an int, value when called with something else). Is there a reason this is not allowed? – pancake Dec 30 '13 at 12:34
  • Indeed, default splits an overloaded function into two groups, the default group will be tried only after all alternatives of the non-default group have been tried. Within a group the ordering is undefined, but it may indeed be most specific first. The current Rascal interpreter does a quasi random thing which you should not count on to be stable. – Jurgen Vinju Jan 02 '14 at 11:35
  • The reason is modularity. We do not want the behavior of one module to change if another module adds an alternative to the set of overloaded functions. So, we ask people to make sure that the functions are mutually non-overlapping or otherwise explicitly ordered with default. This choice was made after long nights debugging large term rewriting systems :-) – Jurgen Vinju Jan 02 '14 at 11:37