- A Concurrent Affair - https://www.concurrentaffair.org -

Doing More Exciting

Of course, doing something is more exciting than writing about it, so after I stopped writing about my idea to pass method arguments [1] last night, I started looking at the code. Last night I wasn’t able to make much progress, but today I implemented the feature for standard @PredicateLink-style annotations.

I accomplished it by adding a arguments value to the @PredicateLink annotation: By default, it’s set to false, but if it is set to true, then the method arguments will be passed after the value of this (or null in case of a static method), but before the values of the annotation.

This is a very cool feature, as it allows me to write predicates like the one I desperately needed in one of my examples, namely that the two arguments are distinct objects. However, the downside, of course, is that it ties an annotation to a particular signature of a method, making annotations much less universal. It gives the programmer the power to write annotations for specific methods, though, and this at least partially removes the necessity of having annotations for local variables to express invariants for them.

Here’s an example of something I can write now:

public class TCSample12 {
public static class CheckIdentity {
public static boolean check(
Object thisObject, Object o1, Object o2, boolean same) {
return same?(o1==o2):(o1!=o2);
}
}

// calls TCSample12.CheckIdentity.check
// (Object thisObject, Object o1, Object o2, boolean same)
@PredicateLink(value=CheckIdentity.class, arguments=true)
@interface TestIdentity {
boolean same() default true;
}

public static void main(String[] args) {
TCSample12 o = new TCSample12();
System.out.println("main!");
String s = "foo";
String t = "bar";
o.distinct(s, t);
o.same(s, s);
System.out.println("end main!");
}

@TestIdentity(same = false)
public void distinct(Object s, Object t) {
System.out.println("distinct! s = '"+s+"', t = '"+t+"'");
}

@TestIdentity
public void same(Object s, Object t) {
System.out.println("same! s = '"+s+"', t = '"+t+"'");
}

For the same method, the invariant is that both arguments have to be identical; for the distinct method, it’s that both arguments have to be distinct. I have direct access to the method arguments. Pretty cool, huh?

One problem that I still have is that the predicates don’t support any kind of subtyping. The methods same and distinct use Object, and so does the predicate method CheckIdentity.check. If, however, the methods used String, a subclass of Object, and the predicate method still used Object, the Thread Checker would find no match. I don’t think this will be too hard to solve, though.

I also haven’t fixed up @Combine-style annotations. There are a few difficulties here: First of all, even if a @Combine-style annotation specifies arguments = true, it is up to the member annotation whether the arguments should actually be passed. So I have to decide this on a case-by-case basis. It will also make loading the arguments onto the stack a bit more difficult, since the method arguments are at the beginning of the array of local variables, so I can’t just linearly iterate over the array anymore, but that’s not too hard to solve either.

Second, if a @Combine-style annotation does not specify arguments = true, then none of its member annotations can do that either. Where would that information come from? An additional check is needed here.

Third, I don’t expose this ability in external XML files yet.

I haven’t even touched the @SuppressSubtypingWarning annotation, but I think that really does have low priority for me. This was more important, because I plan to stick with the same small set of examples for the entire thesis, and if I can’t satisfactorily fix one of them, then it will seem like there’s a gap in my work.

[2] [3]Share [4]