2 Dynamically-Typed Core
For example, predicate objects could be used to implement a bounded buffer abstraction:
The following diagram illustrates the inheritance hierarchy created by this example (the explicit inheritance link from the buffer object toobjectbufferisacollection;fieldelements(b@buffer); -- a queue of elementsfieldmax_size(b@buffer); -- an integermethodlength(b@buffer) { b.elements.length }methodis_empty(b@buffer) { b.length = 0 }methodis_full(b@buffer) { b.length = b.max_size }predicateempty_bufferisabufferwhenbuffer.is_empty;methodget(b@empty_buffer) { ... } -- raise error or block callerpredicatenon_empty_bufferisabufferwhennot(buffer.is_empty);methodget(b@non_empty_buffer) { remove_from_front(b.elements) }predicatefull_bufferisabufferwhenbuffer.is_full;methodput(b@full_buffer, x) { ... } -- raise error or block callerpredicatenon_full_bufferisabufferwhennot(buffer.is_full);methodput(b@non_full_buffer, x) { add_to_back(b.elements, x); }predicatepartially_full_bufferisanon_empty_buffer, non_full_buffer;
buffer is omitted):
Predicate objects increase expressiveness for this example in two ways. First, important states of bounded buffers, e.g., empty and full states, are explicitly identified in the program and named. Besides documenting the important conditions of a bounded buffer, the predicate objects remind the programmer of the special situations that code must handle. This can be particularly useful during maintenance phases as code is later extended with new functionality. Second, attaching methods directly to states supports better factoring of code and eliminates if and case statements, much as does distributing methods among classes in a traditional object-oriented language. In the absence of predicate objects, a method whose behavior depended on the state of an argument object would include an if or case statement to identify and branch to the appropriate case; predicate objects eliminate the clutter of these tests and clearly separate the code for each case. In a more complete example, several methods might be associated with each special state of the buffer. By factoring the code, separating out all the code associated with a particular state or behavior mode, we hope to improve the readability and maintainability of the code.
The syntax for a predicate object declaration is as follows:
predicate_decl ::= "predicate" name {relation} [field_inits] ["when" expr] ";"
Generated with Harlequin WebMaker