5 Replies Latest reply on Jan 11, 2013 3:55 AM by Bela Ban

    METHOD with interface as formal parameter doesn't work

    Bela Ban Master

      Hi,

       

      I have a class Person implementing Human and a rule file (see below).

       

      I want to intercept the copy constructor of Person, and added line

      METHOD <init>(bla$Human)

      to the rule file.

       

      However, this doesn't work and the rule isn't called !

       

      If I change the line to use bla$Person instead of bla$Human, it works. Is this a bug ?

       

      I also tried (to no avail):

      - Changing the copy constructor in the code to accept a Human instead of a Person and narrow it

      - Using ^bla$Human, analogously to the CLASS / INTERFACE rule (although there's nothing in the docs re args) to catch all impls of Human

       

      If did NOT try to do with with a regular method (instead of a ctor), or with a non-inner class, but I suspect the result will be the same...

       

      If this is a bug, should I create an issue in JIRA ?

       

       

      public class bla {

       

          public static interface Human { }

       

          protected static class Person implements Human {

              protected final String name;

              protected final int age;

       

              public Person(String name, int age) {

                  this.name = name;

                  this.age = age;

              }

       

              public Person(Person p) {

                  this(p.name, p.age);

              }     

       

              @Override

              public String toString() {

                  return "I'm " + name + " and I'm " + age + " years old";

              }

          }

       

          public static void main(final String[] args) throws Exception {

              Person p=new Person("Bela",  46);

              System.out.println("p = " + p);

       

              Person alter_ego=new Person(p);

              System.out.println("alter_ego = " + alter_ego);

          }

      }

       

      and the following rule file:

       

      RULE demo

      CLASS bla$Person

      #METHOD <init>(bla$Person)

      METHOD <init>(^bla$Human)

      METHOD <init>(bla$Human)

      IF TRUE

        DO System.out.println("ctor was called");

      ENDRULE

        • 1. Re: METHOD with interface as formal parameter doesn't work
          Bela Ban Master

          Also, the following doesn't work:

           

          RULE demo

          ...

          METHOD <init>

          BIND arg=$2;

          IF TRUE

            DO System.out.println("arg=" + arg + ", class=" + arg.getClass());

          ENDRULE

           

          The exception is: invalid method getClass for target class bla$Human. I believe this is incorrect as the target *is* actually an instance of bla$Person !

          • 2. Re: METHOD with interface as formal parameter doesn't work
            Andrew Dinn Master

            HI Bela,

            Bela Ban wrote:

             

            I have a class Person implementing Human and a rule file (see below).

             

            I want to intercept the copy constructor of Person, and added line

            METHOD <init>(bla$Human)

            to the rule file.

             

            However, this doesn't work and the rule isn't called !

             

            If I change the line to use bla$Person instead of bla$Human, it works. Is this a bug ?

             

            Your class definition includes two constructors Person(Person) and Person(String, int) but does not include a constructor Person(Human). No type coercion is performed when looking for a target method to match the value supplied in the METHOD clause. It must specify the actual type names used in the intended target method. That's because in the context of the METHOD clause the supplied value is a specification and it would be inappropriate to adopt a method with a different specification. The only concession made to allow ambiguity and/or incompleteness in the METHOD specification is that you can omit the package qualification or omit the signature altogether and that's really just for convenience/brevity.

             

            This differs from type checking, say,  a method call in the rule body (IF or DO clauses). In these body rule elements the type checker will match a call with a given argument type against a method with a compatible parameter type i.e. where an argument type is Person it will plant a call to a method with type Human -- so long as this type coercion is unambiguous of course. That's because in this context it is type checking something which is going to be evaluated and type coercion is appropriate in such cases just as it is in Java. n.b. the type checker also uses unambiguous coercions in evaluation contexts to infer types for expressions.

             

             

            Bela Ban wrote:

             

            I also tried (to no avail):

            - Changing the copy constructor in the code to accept a Human instead of a Person and narrow it

            - Using ^bla$Human, analogously to the CLASS / INTERFACE rule (although there's nothing in the docs re args) to catch all impls of Human

             

            If did NOT try to do with with a regular method (instead of a ctor), or with a non-inner class, but I suspect the result will be the same...

             

            Well, if there is a constructor on Person which accepts a Human then specifying CLASS Person METHOD <init>(bla$Human) should match that constructor.  If not then this is a bug. I'll check what is happening in this case using your class definitions.

             

            I will need to check what happens if you specify INTERFACE Human METHOD <init>(bla$Person) when there is a constructor Person(Person). I think it might actualy match but then I don't quite know how it would require the body to be type-checked -- specifying a constructor METHOD (<init>) for an INTERFACE rule is slightly odd. I think it probably ought to mean that in the rule $0 has to be lexically typed using the interface type and that's maybe a little weird when you are executing an init method where $0 clearly has the dynamic type of the actual class which owns the constructor.

             

            Using the ^ syntax for the value supplied in the CLASS or INTERFACE clause is a red herring. It will make no difference to the matchign or type checking given your class definiiton.

             

            regards

             

             

            Andrew Dinn

            • 3. Re: METHOD with interface as formal parameter doesn't work
              Bela Ban Master

              Your class definition includes two constructors Person(Person) and Person(String, int) but does not include a constructor Person(Human).

               

              I actually tried that (see further down in my post), to no avail.

               

              I will need to check what happens if you specify INTERFACE Human METHOD <init>(bla$Person) when there is a constructor Person(Person)

               

              If this worked, it would seem counter-intuitive to me: I'm not interested in intercepting an interface, but a real class (bla$Person). It just so happens that the formal parameter to a method is an interface. The actual argument will be a Person.

              • 4. Re: METHOD with interface as formal parameter doesn't work
                Bela Ban Master

                Because of this problem, I've resorted to creating my own instanceof() and narrow() methods in a corresponding helper class. Suffice it to say that this is crap, and I should not have to do it ! :-)

                 

                But if I do, how about adding 2 additional expressions to byteman ?

                 

                #1 boolean instanceof obj

                 

                #2 The cast operator, either as () or a method (cast() ?)

                 

                I know that you added downcasts in BIND, but is it available in expressions as well ?

                 

                 

                Cheers,