How to add a new keyword ?

51 views
Skip to first unread message

Jonathan MERCIER

unread,
Dec 12, 2014, 12:33:02 PM12/12/14
to drools-de...@googlegroups.com
Dear I would like to add a new keyword like is done for 'IsA'

so created a class org.drools.core.base.evaluators.AsEvaluatorDefinitions.java code here


But when I try to use 'as' keyword they are this error:

java.lang.RuntimeException: Error while creating KieBase[Message [id=1, level=ERROR, path=org/drools/examples/base/as.drl, line=8, column=0
   text=[ERR 102] Line 8:25 mismatched input 'as' in rule "Object can walk"], Message [id=2, level=ERROR, path=org/drools/examples/base/as.drl, line=0, column=0
   text=Parser returned a null Package]]
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.getKieBase(KieContainerImpl.java:366)
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:515)
    at org.drools.compiler.kie.builder.impl.KieContainerImpl.newKieSession(KieContainerImpl.java:486)2014-12-12 18:23:55,322 [AWT-EventQueue-0] ERROR Unable to build KieBaseModel:AsKB
[8,25]: [ERR 102] Line 8:25 mismatched input 'as' in rule "Object can walk"
[0,0]: Parser returned a null Package


Any help are welcome


Thanks

Davide Sottara

unread,
Dec 12, 2014, 1:28:24 PM12/12/14
to drools-de...@googlegroups.com
Jonathan, you need to register the evaluator

KnowledgeBuilderConfiguration builderConf;
builderConf.setOption( EvaluatorOption.get( "as", new AsEvaluatorDefinition() ) );

how you do it depends on whether you use the programmatic APIs, the kmodule, or else

If you are trying to work with casts, maybe in combination with traits, I'd like to know
more about your requirements and approach. This may be something useful to contribute
back to the main codebase.

FYI, Drools does have an inline cast operator, "#":
Person( address#LongAddress( streetName == "..." ) )
but I doubt this would work with traits since it's internally rewritten using a normal Java cast

Thanks
Davide


--
You received this message because you are subscribed to the Google Groups "Drools Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-developm...@googlegroups.com.
To post to this group, send email to drools-de...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/drools-development/b8b912fa-22f5-44e3-9c0d-3efeecab5b80%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Jonathan MERCIER

unread,
Dec 13, 2014, 6:21:30 PM12/13/14
to drools-de...@googlegroups.com
Thanks Davide,

What I would like to get:


interface Walkable  { void walk(); }
interface Swimmable { void swim(); }
interface Quackable { void quack(); }
interface Duck implements
Walkable, Swimmable, Quackable {}

Rule "is a duck"
  when
    $o: Object( this as Walkable.class and  this as Swimmable.class and  this as Quackable.class
  then
    don( $o, Duck.class )
end

================
Where IsA keyword is registered ?

Mark Proctor

unread,
Dec 13, 2014, 8:27:22 PM12/13/14
to drools-de...@googlegroups.com
Didn't we discuss this on irc? I suggested you create a static invoked method on each interface, that reflects to see if the method exists, caches the result, and calls it if it does.

Object( Walkable.walk(this) )

Where walk with this arg is the static method. Java 8 supports static methods as part of the interface.
--
You received this message because you are subscribed to the Google Groups "Drools Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-developm...@googlegroups.com.
To post to this group, send email to drools-de...@googlegroups.com.

Jonathan MERCIER

unread,
Dec 14, 2014, 7:05:58 AM12/14/14
to drools-de...@googlegroups.com
Yes I remember yous advice, just i miss understand how to do it. I will take a look to this new feature

Thanks

Davide Sottara

unread,
Dec 14, 2014, 1:09:00 PM12/14/14
to drools-de...@googlegroups.com
To be honest, I see this as a feature deserving a dedicated operator.




On Sun, Dec 14, 2014 at 5:05 AM, Jonathan MERCIER <bioinfo...@gmail.com> wrote:
Yes I remember yous advice, just i miss understand how to do it. I will take a look to this new feature

Thanks

--
You received this message because you are subscribed to the Google Groups "Drools Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-developm...@googlegroups.com.
To post to this group, send email to drools-de...@googlegroups.com.

Mark Proctor

unread,
Dec 14, 2014, 1:59:49 PM12/14/14
to drools-de...@googlegroups.com
As these are method calls with potential arguments and not setter/getters that won't be possible. 

Mark

Davide Sottara

unread,
Dec 14, 2014, 2:07:21 PM12/14/14
to drools-de...@googlegroups.com
I didn't see the discussion on IRC, so I may be missing some of the requirements,
but why wouldn't we be able to compare two signatures?

Mark Proctor

unread,
Dec 14, 2014, 2:15:39 PM12/14/14
to drools-de...@googlegroups.com
What he's doing is not using accessors, so he can't use traits or custom evaluators. They are general methods.

You could potentially do something like the null safe operator, and have a reflection safe operator. But it will need a lot of thought and this is a very much an edge case  and we risk too many symbols. We could look to see what type safe groovy does for untypical safe method calls. 

It's also easy for people to create static method calls as a work around for this, for now. 

Typically traits or inline casts are enough for more common use cases, involving accessors.

Davide Sottara

unread,
Dec 14, 2014, 2:19:42 PM12/14/14
to drools-de...@googlegroups.com

My understanding was that this is not a cast, but a static comparison between the class and the interface. That is, "as" returns true if the donning would only require hard fields, false otherwise. Generalizing to methods with args only requires a type compatibility check then.
If as returns true, then he would Don. I think that traits already shadow hard methods when available.
I'll be on Skype in 1hr or so

Jonathan MERCIER

unread,
Dec 14, 2014, 7:06:54 PM12/14/14
to drools-de...@googlegroups.com
Exactly

Davide Sottara

unread,
Dec 14, 2014, 7:50:05 PM12/14/14
to drools-de...@googlegroups.com
Mark and I chatted briefly and clarified the problem and the possible solutions.

We do have the "isA" operator, which checks whether an object has a trait. There is a pending ticket to make it ALSO behave like "instanceOf",
which I haven't committed yet
https://issues.jboss.org/browse/DROOLS-603
---------------------------------------------------------------------------

What is being discussed here is a new operator, that returns "true" if and only if an object has all the methods - with compatible arg types -
that would be required by a public interface, so that the "donning" of that interface would only involve "hard" fields and existing methods.
Mark and I agree that "as" could, erroneously, make the user believe that some kind of dynamic cast is involved. This is NOT the case.
Maybe this operator should be better called "behavesAs", or "fits" (open for alternatives)
---------------------------------------------------------------------------

The idea of a "cast", for which "as" would be a better name, is actually already present in Drools. We can do inline casts with the "#" operator:

Person( this#Worker( wage > 1000 ) )

This operator, however, is rewritten using instanceOf and so would not work with traits. In this example, however, it may be desirable
to overload "#" to check if the current Person,say, has the Worker trait. In fact, the constraint would have to be rewritten as

Person( ((TraitableBean) this).hasTrait( Worker.class ) && (TraitableBean) this).getTrait( Worker.class ).getWage > 1000 ) )

along the lines of the instanceOf / cast we already use for the inline cast.
Notice that for this to work, the Person should HAVE ALREADY been donned with Worker.
---------------------------------------------------------------------------

In general, LHS operators should NOT have heavy side-effects such as type inference, or involve reflection for performance reasons.
I believe that this was the reason for Mark's initial concern in pulling this feature into the engine natively.

I will open three separate tickets in JIRA (2 new + the existing 603) as feature requests and comment there on the feasibility, performance implications
and development status.

Jonathan and Mark, thanks for the feedback, very interesting discussion. If you also want to contribute to the development, PRs are welcome ;)

Davide



On Sun, Dec 14, 2014 at 5:06 PM, Jonathan MERCIER <bioinfo...@gmail.com> wrote:
Exactly

--
You received this message because you are subscribed to the Google Groups "Drools Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-developm...@googlegroups.com.
To post to this group, send email to drools-de...@googlegroups.com.

Jonathan MERCIER

unread,
Dec 15, 2014, 5:48:51 AM12/15/14
to drools-de...@googlegroups.com
Perfect, to add some more information my idea is come when I read the paper 'Object-Oriented and Logic-Based Knowledge Representation - Vladimir Alexiev 1993' .

he explain the power of Object-Oriented-Programming and Logic-Programming separately and give the benefit of Object-Oriented-Logic. But it demonstrate that they are some problems in this approach. From a logic point of view: relation between object are hard-coded ( implements xxx, extends yyy ...)
It explain a new view named Object-Oriented-Knowledge-Based . And I seen that we can get it by adding a duck-typing support.
An human can't hard-code all relation between object when the models is huge, and these relation are not dynamic.
Example we have two class rectangle and square.
case 1:
 - human miss to write the relation between rectangle and square.
Many rules which should to be applied to square will be not ...
case 2:
-  a side of square change his length that is not anymore a square
square rules should not to be allowed for this object instance ( of course you could to retract and create a new object)

They are maybe some others interesting cases

Here a function which check if an object fits an interface. You have maybe a better way, (maybe with java8 I do not know )
 
        @SuppressWarnings("unchecked")
        static <T> boolean fits(Class<T> t, final Object obj) {
            boolean result = true;
            try {
                Proxy.newProxyInstance(t.getClassLoader(), new Class[]{t},
                        new InvocationHandler() {
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                try {
                                    return obj.getClass()
                                            .getMethod(method.getName(), method.getParameterTypes())
                                            .invoke(obj, args);
                                } catch (NoSuchMethodException nsme) {
                                    throw new NoSuchMethodError(nsme.getMessage());
                                } catch (InvocationTargetException ite) {
                                    throw ite.getTargetException();
                                }
                            }
                        });
            } catch (Exception e){
                result = false;
            }
            return result;
        }

Davide Sottara

unread,
Dec 15, 2014, 11:10:29 AM12/15/14
to drools-de...@googlegroups.com
Agree that it's a useful feature. The use cases you mention are supported.

The solution you propose confuses me, though, for it meets a different requirement.
This function will realize that an object does NOT fit a given interface only the first time a non-supported method is invoked.
This makes the system non deterministic - anything can be a Duck until you try to make it quack - and if this is the kind
of behavior you discussed with Mark, I understand his concerns.

What can be done, is take the object's class, the target interface, and do a static comparison of the two signatures.
The result can be cached and indexed using the object's class. This is actually already part of the traiting process,
so I just need to expose it with a dedicated operator



--
You received this message because you are subscribed to the Google Groups "Drools Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email to drools-developm...@googlegroups.com.
To post to this group, send email to drools-de...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages