Review Extra: Jess 7.0 and JBoss Rules 3.2 code examples

The old CLIPS syntax used by Jess has its place, but the more English-like rule language used by JBoss Rules will be much easier for non-technical analysts to grasp

One big difference between Jess and JBoss Rules, the top two open source rule-based systems (reviewed here by James Owen), is the degree of friendliness of their rule languages to ordinary mortals. Venerable Jess is pithy and cryptic, owing to its roots in artificial intelligence research. JBoss Rules, the new kid on the block, offers a more natural syntax that business users will find easier to grasp. A bit of history from James:

Jess opened the door for expert systems (especially rule-based systems) to move from LISP to C to C++ to Java. After all, CLIPS ran as a C/C++ compiler that was nothing more than an extension of LISP/OPS (ListProcessing/Official Production Systems, "production" being a rule) to C then to C++. Jess was just the next logical extension. Dr. Ernest Friedman-Hill wanted to keep in lock-step with CLIPS which wanted to stay in lock-step with OPS which still has that same, archaic syntax. Unfortunate, because it isn't what the Java guys wanted. 

But the EE guys picked it right up, the plant production people (oil patch guys) used it, and so did I and a few academics who could get it for free. (I had to pay my $100 for the source code just like everyone else.) Jess was and is a great system, but it hasn't caught on with many in the business and financial world. After all, the business analysts make the rules, the IT guys have to write them in whatever language they can master, and Jess was not on the top of the list until about three or four years ago.

The Jess code for the assignSeat or find_seating rule (same code, different names) of the Miss Manners benchmark is shown below. As you can imagine, the old CLIPS syntax will present a steep learning curve to most business analysts. However, programmers will find it much more concise than the equivalent code in JBoss Rules or some other BRMS engines.

(defrule find_seating
   ?ctxt <- (Context (state assign_seats))
   (Seating (seat1 ?seat1) (seat2 ?seat2) (name2 ?n2) (id ?id)
      (pid ?pid) (pathDone yes))
   (Guest (name ?n2) (sex ?s1) (hobby ?h1))
   (Guest (name ?g2) (sex ~?s1) (hobby ?h1))
   ?count <- (Count (c ?c))
   (not (Path (id ?id) (name ?g2)))
   (not (Chosen (id ?id) (name ?g2) (hobby ?h1)))
   (assert (Seating (seat1 ?seat2) (name1 ?n2) (name2 ?g2) 
      (seat2 (+ ?seat2 1)) (id ?c) (pid ?id) (pathDone no)))
   (assert (Path (id ?c) (name ?g2) (seat ( + ?seat2 1))))
   (assert (Chosen (id ?id) (name ?g2) (hobby ?h1)))
   (modify ?count (c (+ ?c 1)))
   (printout t seat " " ?seat2 " " ?n2 " " ?g2 crlf)
   (modify ?ctxt (state make_path)))

Compare the above with the same code (the now-famous Miss Manners assignSeat or find_seat rule) for JBoss Rules shown below. The JBoss Rules code is easy and familiar enough that most business analysts could learn it in only a day’s time (with a bit of help from a Java programmer).

rule findSeating
      context : Context( state == Context.ASSIGN_SEATS )
      Seating( seatingId:id, seatingPid:pid, 
         pathDone == true, seatingRightSeat:rightSeat,
         seatingRightGuestName:rightGuestName )
      Guest( name == seatingRightGuestName, 
         rightGuestSex:sex, rightGuestHobby:hobby )
      Guest( leftGuestName:name , sex != rightGuestSex,
         hobby == rightGuestHobby )
      count : Count()
      not ( Path( id == seatingId, 
         guestName == leftGuestName) )
      not ( Chosen( id == seatingId, 
         guestName == leftGuestName,
      hobby == rightGuestHobby) )
      int rightSeat = seatingRightSeat.intValue();
      int seatId = seatingId.intValue();
      int countValue = count.getValue();
      Seating seating = new Seating( countValue, seatId,
         false, rightSeat, seatingRightGuestName,
         rightSeat + 1, leftGuestName );
      assert( seating );
      Path path = new Path( countValue, rightSeat + 1,
         leftGuestName  );
      assert( path );
      Chosen chosen = new Chosen( seatId, leftGuestName,
         rightGuestHobby );
      assert( chosen  );
      System.err.println( "find seating : " + seating 
         + " : " + path + " : " + chosen);
      count.setValue(  countValue + 1 );
      modify( count );
      context.setState( Context.MAKE_PATH );
      modify( context );