Corky has made the thread checker a core part of the project now. In our group meeting on Monday, we briefly and with little time discussed how to make them more general and easier to use. The result was something I had already considered of when I thought about how to link model and view for ONLY\_AFTER\_REALIZED
: Predicates written in Java, i.e. allowing calls to Java methods that return boolean
. Somehow it seems like I didn’t write this idea down, which is a shame; that’s exactly why I keep this blog.
At that time, I saw four different options:
- Defining the semantics of
ONLY_AFTER_REALIZED
for non-component classes as “any thread can call this method until the event thread calls it the first time; after that, only the event thread may call the method”. - Linking model and view classes with a
HashMap<String,Boolean>
by letting the view set the value indexed by some unique name totrue
and definingONLY_AFTER_REALIZED
as “allow any thread as long the value indexed by the unique name isfalse
; once it istrue
, only the event thread is allowed”. That’s what I described in the earlier posting, and I considered generalizing it to allow Boolean expressions. - Specifying a Java method by name in the annotation and calling it. This is essentially what we decided to do now.
- Allowing arbitrary Java code as a string in the annotation, extracting, compiling and then inserting it in the right place. This seemed like overkill, though, since pretty much everything can be done by calling a method. If I could find a way to easily access the variables in the surrounding context, then this might have some benefits over just calling a method.
I have listed these in order of increasing difficulty. I would have tried the first option first, but I’m not sure it would have worked well and it isn’t very flexible, so I planned to implement the second option anyway. I decided against the last two options because of their complexity, and especially because allowing the execution of arbitrary code might have a large impact on the threading behavior. I still think that the predicates should be as simple as possible, and I don’t know if the use of reflection, for example, is a good idea, even though it would open many doors.
In our meeting, the differences between what Corky had in mind and what I proposed (after the Boolean expression option had been shot down as not powerful enough) were mostly syntactic and superficial. He wanted something that’s as easy and short as possible for the “user programmer”, while it could be a little more complicated for the “library programmer”.
I guess he has a point here: All my current annotations can be a bit lengthy, because they require a primary annotation (@OnlyRunBy
or @NotRunBy
) and then another annotation, @ThreadDesc
, as data for the primary annotation. The big advantage of doing it this way is that annotations can specify an arbitrary number of thread descriptions because the primary annotations contain an array of @ThreadDesc
. Since any annotation may only appear once in the list of annotations in front of whatever is being annotated, without this array it will be difficult to specify compound predicates that use “and” and “or” to combine simpler predicates, e.g. “allow thread with name ‘foo’ and thread with name ‘bar'”.
Unfortunately, annotation interfaces cannot extend another interface, so there’s absolutely no subtyping for annotations, and arrays of annotations must specify the type of the annotation precisely. It’s impossible to say “make this an array of any annotation” or introduce a common super-annotation that all Thread Checker annotations must extend. I’ll have to think about that and discuss it with Corky and the group.