Also, the following doesn't work:
DO System.out.println("arg=" + arg + ", class=" + arg.getClass());
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 !
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
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:
- 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.
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.
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 ?