0

I have a question about the some built-in primitives. Is possible to use the built-ins: difference, min, max, sum also for DateTime types or it is better to create custom built-ins for this purpose? They work fine with integer and float but it seems not for DateTime types (or maybe the syntax I have used is wrong).

Stanislav Kralin
  • 11,070
  • 4
  • 35
  • 58
user3563844
  • 113
  • 1
  • 8

1 Answers1

0

Your syntax isn't incorrect. First, we can jump over to Builtin's javadoc in order to identify what Builtins exist.

Selecting Max, as per your mention of it, can we go ahead and look up it's fully qualified class name on GrepCode. Once we get there, we notice that the parimary method that it implements is bodyCall(Node[], int, RuleContext), so let's take a look at it's implementation (as of 2.11.0) and see why it's behaving the way it is:

@Override
public boolean bodyCall(Node[] args, int length, RuleContext context) {
    checkArgs(length, context);
    BindingEnvironment env = context.getEnv();
    Node n1 = getArg(0, args, context);
    Node n2 = getArg(1, args, context);
    if (n1.isLiteral() && n2.isLiteral()) {
        Object v1 = n1.getLiteralValue();
        Object v2 = n2.getLiteralValue();
        Node res = null;
        if (v1 instanceof Number && v2 instanceof Number) {
            Number nv1 = (Number)v1;
            Number nv2 = (Number)v2;
            if (v1 instanceof Float || v1 instanceof Double 
            ||  v2 instanceof Float || v2 instanceof Double) {
                res = (nv1.doubleValue() > nv2.doubleValue()) ? n1 : n2;
            } else {
                res = (nv1.longValue() > nv2.longValue()) ? n1 : n2;
            }
            return env.bind(args[2], res);
        }
    }
    // Doesn't (yet) handle partially bound cases
    return false;
}

The important thing to note here is that the method will only bind a value if once of the instances are a derivative of java.lang.Number.

Note that if we look at the implementation (as of 2.11.0) of LessThan#bodyCall(Node[], int, RuleContext), we can trace it's behavior to use of Util that is sensitive to date/time objects.

If you have a rule that uses max(?a ?b ?c) to bind the maximum value to ?c, you can sometimes (if your rule has nice symmetry) use lessThan(?a ?b) to just limit the ways in which the rule gets bound (thus, achieving the same result). In the lessThan case, the rest of the rule can go on assuming that ?b was the greater value, all along. Again, this requires that your rule have a nice symmetry that, elsewhere, allows the binding of ?a and ?b without other constraints.

If you need an equivalent of Max that can use XSDDateTime literals, then you, indeed, may have to make some yourself. Thankfully, as the code for these Builtins show, it can actually be quite easy to create them.

On a more philosohpical note, I am uncertain whether this was a conscious decision by the developers or if it was, perhaps, a small oversight. I imagine that the comparison utilities (Util) used by LessThan may actually be newer than the Max builtin, so Max wasn't implemented in terms of it.

Rob Hall
  • 2,693
  • 16
  • 22