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
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.