Jess and invocation of overloaded Java static methods

167 views Asked by At

I have some issues calling overloaded functions from Jess and got unexpected results and sometimes exceptions. The results are not too predictable. They seem to depend on, among other things, how many overloaded functions there are.

Are there reliable ways to ensure the correct functions are called? Any feedback will be greatly appreciated. Please, be patient because this is going to be a bit long.

I have the following clp:

(deffunction functionShort (?a1 ?a2 ?a3) (JessOverLoaded.function ?a1 ?a2 ?a3))  
(deffunction functionInteger (?a1 ?a2 ?a3) (JessOverLoaded.function ?a1 ?a2 ?a3))  
(deffunction functionLong (?a1 ?a2 ?a3) (JessOverLoaded.function ?a1 ?a2 ?a3))  

And the Java static methods:

public static boolean function(Integer arg1, Integer arg2, Integer arg3)  
public static boolean function(Short arg1, Short arg2, Short arg3)  
public static boolean function(Long arg1, Long arg2, Long arg3)   
public static boolean function(Double arg1, Double arg2, Double arg3)  
public static boolean function(Float arg1, Float arg2, Float arg3)  

The following calls all end up calling the Long version, function(Long, Long, Long). I was hoping that, by passing Java objects to Jess, it would select the appropriate method to call.

(functionInteger (FunctionsObjectCreator.createInteger)(FunctionsObjectCreator.createInteger) (FunctionsObjectCreator.createInteger))  
(functionShort (FunctionsObjectCreator.createShort)
(FunctionsObjectCreator.createShort) (FunctionsObjectCreator.createShort))  
(functionLong (FunctionsObjectCreator.createLong) (FunctionsObjectCreator.createLong)  (FunctionsObjectCreator.createLong))  

where FunctionsObjectCreator.createXYZ() create Integer, Short and Long objects.

Here is another overloaded sample with Integer as the primary class:

public static boolean inRange(Integer $impliedParameter, Integer lowerBound, Integer upperBound) {  
    System.out.println("inRange Integer 1");  
    return false;  
}  
public static boolean inRange(Integer $impliedParameter, Integer lowerBound, Integer upperBound, Integer[] exclusions) {  
    System.out.println("inRange Integer 2");  
    return false;  
}  
public static boolean inRange(Integer $impliedParameter, Integer[][] listOfRanges, Integer[] exclusions) {  
    System.out.println("inRange Integer 3");  
    return false;  
}  
public static boolean inRange(Integer $impliedParameter, Integer[][] listOfRanges, boolean inclusiveLower, boolean inclusiveUpper, Integer[] exclusions) {  
    System.out.println("inRangeInteger 4");  
    return false;  
}  

To save space, I do not include the overloaded functions with String, Short, Long, Date, Character and Byte.

The clp to invoke some of these static methods:

(deffunction  functionShort1 (?a1 ?a2 ?a3)  
(JessOverLoaded.inRange ?a1 ?a2 ?a3))  

(deffunction  functionInteger1 (?a1 ?a2 ?a3)  
(JessOverLoaded.inRange ?a1 ?a2 ?a3))  

(deffunction  functionLong1 (?a1 ?a2 ?a3)  
(JessOverLoaded.inRange ?a1 ?a2 ?a3))  

(functionInteger1 (FunctionsObjectCreator.createInteger)  (FunctionsObjectCreator.createInteger) (FunctionsObjectCreator.createInteger))  
(functionShort1 (FunctionsObjectCreator.createShort) (FunctionsObjectCreator.createShort)  (FunctionsObjectCreator.createShort))  
(functionLong1 (FunctionsObjectCreator.createLong) (FunctionsObjectCreator.createLong)  (FunctionsObjectCreator.createLong))  

The above invocations either fail to call the correct static methods or receive an exception. One such exception is:

Jess reported an error in routine JessOverLoaded.inRange  
    while executing (JessOverLoaded.inRange ?a1 ?a2 ?a3)  
    while executing deffunction functionInteger1  
    while executing (functionInteger1 (FunctionsObjectCreator.createInteger)   (FunctionsObjectCreator.createInteger) (FunctionsObjectCreator.createInteger)).
  Message: Error during execution.  
  Program text: ( functionInteger1 ( FunctionsObjectCreator.createInteger ) (   FunctionsObjectCreator.createInteger ) ( FunctionsObjectCreator.createInteger ) )  at line  28 in file src/com/softwareag/rules/functions/JessOverloaded.clp.  
    at jess.Funcall.execute(Funcall.java:346)  
    at jess.FuncallValue.resolveValue(FuncallValue.java:29)  
    at jess.Deffunction.call(Deffunction.java:214)  
    at jess.FunctionHolder.call(FunctionHolder.java:35)  
    at jess.Funcall.execute(Funcall.java:338)  
    at jess.Jesp.parseAndExecuteFuncall(Jesp.java:2309)  
    at jess.Jesp.parseExpression(Jesp.java:459)  
    at jess.Jesp.promptAndParseOneExpression(Jesp.java:309)  
    at jess.Jesp.parse(Jesp.java:288)  
    at jess.Batch.batch(Batch.java:132)  
    at jess.Batch.batch(Batch.java:113)  
    at jess.Batch.batch(Batch.java:75)  
    at jess.Batch.batch(Batch.java:40)  
    at jess.Rete.batch(Rete.java:2791)  
    at com.softwareag.rules.functions.parser.JessFunctions.main(JessFunctions.java:18)  
Caused by: java.lang.IllegalArgumentException: Can't convert '64' to required type   [[Ljava.lang.Double;  
    at jess.RU.valueToObject(RU.java:385)  
    at jess.RU.valueToObject(RU.java:289)  
    at jess.SerializableMD.invoke(SerializableMD.java:62)  
    at jess.MethodFunction.call(StaticMemberImporter.java:102)  
    at jess.FunctionHolder.call(FunctionHolder.java:35)  
    at jess.Funcall.execute(Funcall.java:338)  
    ... 14 more  
2

There are 2 answers

0
Ernest Friedman-Hill On

Honestly, if you need to deal with this kind of thing, the easiest way to do it would be to write a Java class to serve as an adapter; the Java class can rename the overloads to disambiguate them, and you can therefore avoid the whole problem. Jess's overload resolution can fall down in complex situations, and this is unlikely to ever be completely fixed. You'll find that other dynamic languages have similar problems (although admittedly some are better than Jess in this regard.)

It's a little better in Jess 8, which is currently in early release, but it's still not perfect.

2
laune On

I cannot reproduce the problem using a simplified version with just one argument of each of the numeric classes.

However, I'm somewhat suspicious of the FunctionsObjectCreator.createInteger you have not shown. Did you make sure (using (java-objectp)) that the results of these methods are indeed Java objects?

Try a call to your overloaded function using e.g.

 (call JessOverLoaded function (new Integer 1)(new Integer 2)(new Integer 3))