Reflection Rules


The framework uses reflection to access fields and methods of framework classes and domain objects. The reflection takes place in contexts that involve reading, writing or both. For example, a row fixtures wants to read values by reflection while the enter action of an action fixture wants to write. Thirdly, a column fixture does both.

Currently the framework uses a sufix of () to denote where methods should be called as opposed to fields accessed. Here is how this works for the examples cited above.

  • Read Context -- A RowFixture reads values from a domain object and checks them against expected values in the table. It can read fields or methods depending on the () sufix.

  • Write Context -- An ActionFixture writes values to an actor (another fixture it has started) whenever it encounters the enter action. Enter always writes by calling a method.

  • Read/Write Context -- A ColumnFixture writes values to fields and reads values from methods. It distinguishes a read (a given) from a write (an unknown) by the () sufix.

We are considering dropping the sufix convention and using only data available by reflection to resolve the intent of any given name.


A Proposal

This is a proposal to drop the sufix () convention in favor of further searching by reflection. The current scheme knows what it wants by reflection and errors when it doesn't find it. If we didn't have the sufix () then we might need to make several probes by reflection to find an appropriate binding. Here we propose that we do one, two or possibly three probes of the reflection data to find the field or method refered to in a table.

for Java reading writing both
check type method() first   first
check field second   
set void method(type)   first second
set field   second third

A feature of this proposal is that accessing methods could substitute for field accesses and thereby allow the availability of data to trigger computations. As such, we recommend the reset() and exectute() and their invoking logic be removed from ColumnFixture. For example, the key column could be defined as a setter method that also invokes the hp35 calculator. This makes more sense than interpreting the keystroke on the (most likely) first read column.


Other Languages

Other languages may have other mechanisms for communicating with an object beyond fields and methods.

  • C# has properties: get and set methods on fields.
  • Ruby always accesses fields through methods.
  • Lisp calls functions which may be specialized. (CLOS requires all specializations to have the same number of arguments)

Can the table above be adapted to these languages? Is this an improvement on the status quo?


Observations

The RowFixture is the only one (so far) that reflects directly on domain objects. This is important because we assume we don't have total control over field/method names for domain objects. If we drop the () sufix then it won't be possible to read the contents of a field and the results of a method if they have the same name.

ActionFixture converts multi-word names to likely field/method names before reflecting. (It uses Fixture.camel(String)) This would seem to be a nice feature to offer everywhere we do reflection.

The sufix, empty parenthesis, is a C/Java convention used distinguish variable references from function calls. An early version of the framework used a question mark to denote names that should be checked. This is a lisp convention for denoting predicates (functions that perform tests) which is how I thought of them. I abandoned this convention because the named function isn't actually the predicate. It is the function that delivers the value to the predicate.

 

Last edited October 20, 2002
Return to WelcomeVisitors