Skip to content

Instantly share code, notes, and snippets.

@smarr
Last active April 3, 2018 08:09
Show Gist options
  • Save smarr/7233c332ef9fba63bc35ed5fa711a859 to your computer and use it in GitHub Desktop.
Save smarr/7233c332ef9fba63bc35ed5fa711a859 to your computer and use it in GitHub Desktop.
Specializations, Types, and subsumption

Truffle Specializations do not automatically have exclusive semantics. Instead, the rules of the Java type system apply.

Let's take the following node with three specializations as example. Note, I return an int here, usually you'd return a boolean, but the int allows me to get the point across more precisely in the later tests.

@NodeChild(value = "e", type = ExprNode.class)
public abstract class IsNumberNode extends Node {

  public abstract Object executeGeneric(VirtualFrame frame);

  public abstract int executeEvaluated(Object o);

  @Specialization
  public final int isInt(final int o) {
    return 1;
  }

  @Specialization
  public final int isDouble(final double o) {
    return 2;
  }

  @Specialization
  public final int isObject(final Object o) {
    return 3;
  }
}

It is important to realize that isObject(Object) is more general than isInt(int) and isDouble(double), which means, it is expected to subsume the more specific specializations. This can be made explicit with @Specialization(replaces = {"isInt", "isDouble"}), which has the effect of disabling previously activated specializations.

Anyway, to demonstrate the semantics, here a test:

public class TestAdd {
  @Test
  public void testIsNumberOneAfterAnother() {
    IsNumberNode n = IsNumberNodeGen.create(null);
    assertEquals(1, n.executeEvaluated(42));
    assertEquals(2, n.executeEvaluated(44.3));
    assertEquals(3, n.executeEvaluated(new Object()));
    assertEquals(2, n.executeEvaluated(44.3));
  }
  
  @Test
  public void testIsNumberStartingWithTheMostGeneral() {
    IsNumberNode n = IsNumberNodeGen.create(null);
    assertEquals(3, n.executeEvaluated(new Object()));
    assertEquals(3, n.executeEvaluated(44.3));
    assertEquals(3, n.executeEvaluated(42));
  }
}
@eregon
Copy link

eregon commented Mar 30, 2018

And so to have isObject only handle "objects" and not the other specializations' types, it is needed to add guards like:

  @Specialization(guards = { "!isInteger(o)", "!isDouble(o)" })
  public final int isObject(final Object o) {
    return 3;
  }

@smarr
Copy link
Author

smarr commented Mar 30, 2018

Using @Fallback instead of @Specialization with guards can work in this specific case, too.

@fniephaus
Copy link

What's the "better" pattern here? Using guards as suggested by @eregon seems to require lots of boilerplate code (e.g. many guard methods), but it's clear how the specialization works. I still don't feel very comfortable using @Fallback, and it's seems others do, too. Also, can anyone think of an example where you'd need more than one @Fallback (which you can't have)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment