difference in semantics between interpreted and compiled-to-Java Stratego code
I found that the following piece of Stratego code works fine when it is run from the .ctree file and fails when it is compiled to Java:
signature
constructors
elem : String -> Xrules
fetch-elem(|name) = fetch(?x@elem(name)); !x
run-test:
t -> None()
with
test-suite(
!“test suite”,
apply-test(
!" when given one element, fetch-elem works as expected",
fetch-elem(|“fixedType”),
![elem("fixedType")],
!elem(“fixedType”)
);
apply-test(
!" when given two elements, fetch-elem works as expected",
fetch-elem(|“fixedType”),
![elem("category"), elem("fixedType")],
!elem(“fixedType”)
)
)The first test succeeds both in the .ctree and .jar cases, the second test succeeds in the .ctree case and fails in the .jar case (fetch-elem strategy fails).
Initially I thought it might have to do with string sharing, but the first test seems to exclude that.Tested with Spoofax 0.6.0.2.
Submitted by Tobi Vollebregt on 3 January 2011 at 13:24
Issue Log
Note that this is a strange cornercase: your fetch-elem strategy doesn’t scope the
x
variable, and doesn’t specify whether to first bind bothx
or first matchname
. A better strategy may be:
fetch-elem(|name) = fetch(?elem(name); ?x); !xor
fetch-elem(|name) = getfirst(?elem(name))As for the inconsistent semantics, it looks like the compiled
.jar
version first binds and then matches, causing it to fail the second tests. The interpreter first matches and then binds. I’m not sure how ordering is determined here (left-to-right, binding first, …?) but I assume that the.jar
version is the “correct” one, as it should correspond to the original compiler.
Ah right, thanks! The scoping rules keep biting me occasionally ;-)
At least that solves the issue at hand for me; will still leave this open as it may be good to fix the semantics of the interpreter at some point. (unless this construct has undefined behaviour by design maybe?)
We should probably be bug-for-bug compatible with the old strc, but I personally find the match-then-bind to be the most logical (and that might indeed be why the interpreter does it that way).
Would we break the world if we switched to match-then-build?
That was my thought too when reading the issue. I guess I defined the desugaring
|[ x@t ]| -> |[ ?x; ?t ]|
It seems natural to invert ?x and ?t. However, there might be some subtle interactions with embedded matches in t. For example,
?x@Foo( x)
would no longer work, since x would be unbound, whereas currently it is bound.
As an experiment you could change the definition and see what breaks; would need to be an extensive test though.
As a reference point: what is the semantics of the operation in Haskell and Scala?
I don’t think it’s actually the desugaring though, since the interpreter also works on a desugared
ctree
. So it must really be that the interpreter gives precedence to matching over binding. The interpreter’s semantics does seem more intuitive, but I’m not sure if it’s worth changing it. Code that relies on the ordering like this is Bad anyway. Breaking Bad code that hasn’t been written yet is a minor nuisance, but breaking all the old Bad code that probably already exists out there seems like a more significant problem.
Quite right. I’ll close the issue then.
Well, it would still be good to fix the interpreter to be consistent with the compiler w.r.t. this issue. I’m moving it to Stratego/XT and reopening it.
Log in to post comments