Ruminations of a Reflective Robespierre
OOPSLA '90 Workshop
on
Reflection and Metalevel Architectures
Brian Foote
18 October 1990
Mamdouh Ibrahim chair, Brian Foote, Jean-Pierre Briot, Gregor Kiczales, Satoshi Matsuoka, and Takuo Watanabe, organizers
The Ramifications of a Reflective
Revolution
Object-oriented programming systems and languages are every bit as appropriate a domain for object-oriented programming techniques as are window systems, databases and the like...
Reflective and object-oriented approaches together, for the first time, provide us with sufficient power to allow a language to serve as the vehicle for its own incremental evolution
Reflective object-oriented architecures allow metalevel functionality to be distributed across a constellation of different metaobjects
Reflection allows the venerable vision of allowing one's programming system to encroach upon and supplcant large sections of the operating system and the user interface to be realized
An aggressively animistic perspective in which obects are tangible, active, first class entities that may dynamically alter their structures and their relationships with other elements of the environment in which they reside
Reflective Approaches have implications for:
programming language design
compiler construction
code generation
language design
programming environments
debugging, tracing
...even operating systems
(as per Tesler)
computation theory
semantics
Reflection affects how we think about translation
Polymorphism raises the level of abstraction of object-oriented code
More mechanics are subsumed into the metalevel
Hence, metalevel manipulation can have a greater impact
Reflection can tear down the distinctions between statically compiled and dynamically interpreted translation
(incremental compilation always seemed like a reasonable middle ground anyway...)
static vs. dynamic
batch vs. interactive
Reflection can influence the architecture of systems that embody the results of well-researched areas such as lexical and semantic analysis...
Possible Metalevel Components
(Potential Metaobjects)
(Things one might reify)
A Metaobject Pallette
In no particular order...
Variables/Slots
Selectors/Generic Functions/Keys/Operators
Messages
Evaluators/Processors/Interpreters
Method Dictionaries/Script/Scripts Sets/Role/Containers/Behaviors
Records/Repertoire/Relation/Table/Index
A-List/Association/Pair/Tuple/Entry
Handles/Pointers/Names/Addresses/Locations/References/OOPs
Environments
Continuations
Contexts (Method, Block)
Mailboxes/Message Queues
State Memory/Stores/Storage
Blocks/Closures
Classes
Metainstances/Metaclasses
Types
Prototypes/Traits
Signatures/Protocols
Methods (Primitive and otherwise)
Code/Expressions/Parse Trees/Byte Codes/Forms
Processes/Theads/Engines
...and last but not least:
Objects
Integers/Floats/Reals/Strings
Arrays/Aggregates/Structures/Collections/Lists
(other primitive objects)
Some meta-metalevel design issues:
Distributed (implicit) representation
vs.
Localized (explict) representation
Issues in consistency mainentance:
Everyone's favorite implementation strategy (at least at PARC, perhaps)
The single principle that underlies the results reported here is
DYNAMIC CHANGE OF REPRESENTATION
Later they speak of "Multiple Rpresentation"
causal connection
dynamic structure
active structure
active representation
...even dynamic constraint maintenance/satisfaction
How might representation changes be instigated:
Uniform (Normal) representation: never
Equivalent representaion: implicitly (transparently, like PS contexts)
Convertable representation: explicitly (under user control)
Transparency vs. Convertability
Design Principles
Message Passing at the Bottom
all computation shall be conducted via message passing
Object-Oriented Uniformity
everything shall be an object
(including variables, "code", contexts, oops?)
Malleable Self-Representation
computations shall be represented by first class objects
at a semanticallly interesting level
Extensionality
behavior only shall determine an object's identity
(The Duck Test)
Inheritance is signature composition
at least from an extensional standpoint
State and Behavior
shall be externally indistinguishable
(state is, of course, architecturally significant
at certain levels)
Active Dispatching vs. Passive Lookup
shall be externally indistinguishable
Dynamic vs. Static Scope
(Operational vs. Denotational Scope)
static scope shall be dynamically implemented
(as it usually is, anyway)
Language Design:
The Hamiltionian Tradition
vs.
The Jeffersonian Ideal
The Hamiltionian tradition can be characterized by the image of the language designer as a sage locked in a castle in the Alps forever defining just what a language shall and shall not be able to do...
A favorite example: Pascal's utterly inflexible arrays
Reflection potentially puts this power in the hands of each and every user of a language
Metaprogramming: It's not for everyone
Of course, it is expected that most users will not need to resort to designing and building, as opposed to using, reflective facilities
Metaprogramming should not be undertaken frivolously
They should be there when they are needed.
A language should not be an
obstacle to its users, or to its own evolution
Metaprogrammers are a peculiar, but distinctive breed
The alternative: A sort of Software Stalinism
Monism vs. Dualism
and Metamorphosis
The question: do we effect dynamic structural alterations by manipulating
heavyweight objects
or
lightweight classes?
The perspective of an object is a discrete entity that is itself the captain of its own ship is useful at times
The perspective of an objects as being a member of a perhaps dynamic coalition that defines its behavior us useful as well...
Table I
1. Monitors
2. Encapsulators
3. Message Forwarding
4. Property List Manipulations
5. Accessible Objects (Dicts=Records=Props)
6. Multiple Views (Database style)
7. Capabilities (Access Control)/OS Style Protection
8. Multiple Inheritance
9. Tracing
10. Debugging (Many Mentions)
11. Futures
12. Remote (Distributed) Objects
13. Multitasking (transparent, perhaps)
14. Constraints
15. Reflection
16. Part/Whole Relationships
17. Active Values
Active Variables
Active Messages
Active References
18. "Smart" Variables
19. Lightweight (Anonymous) Classes
20. Melds (Garlan & Kaiser)
21. Actors/Daemons
22. Lazy Evaluation
23. Caching Schemes
24. Memo Memory Functions (as in POP2 and friends)
25. Read-Only Variables
26. Logging
27. Metering/Statistics/Performance Data Collection
28. Component Delegation
29. Atomic Objects/Actions
30. Protocol Translators/Adaptors
31. Open Systems (Protocol Negotiators?)
32. Multiple Inheritance Schemes
33. Delegated Inheritance (and other forms of sharing)
34. Multimethods (and other generic dispatch schemes)
35. Method Combination/Composition
36. Prototypes (ala Borning)
37. Modules (ala Wirfs-Brock)
38. Continuations? Catch/Throw?
39. Exception Handling of various sorts...
40. Dynamic Behavior Changes
41. Dynamic Class Changes
42. Dynamic Class Construction
43. "Smart" Paths (see Part/Whole)
44. Flavors (now CLOS)-Style Method Combination
45. Two Way Implicit Group Membership (like Part/Whole?)
(Perhaps encompassing the idea of "Enrollment"
(Randall Smith))
46. Implicit Coercion Schemes
47. X-Style Substructure Redirection
48. Event Dispatching (see Multimethods)
49. Alternate Memory Allocation Schemes
50. Multilevel (Virtual, in the OS sense) Object Allocation
51. Sundry Dynamic and Other Optimizations (Cointe)
52. Escape Operators (see Continuations) (B. C. Smith)
53. "Deviant" Variable Passing Protocols (B. C. Smith)
54. Planning/Supervisory Code (Genesereth, others)
55. Behavior Based Programming
56. Active Types
57. Strategy Computation
58. Truth Maintenance
59. Program Supervision
60. Multiprocessor Load Balancing
61. Active Values/Access Oriented Programming
62. Self Analysis (Code Walking)
63. Self description of a program's operational semantics
64. Smart Comments
65. Logic Variables/Unification
66. Agents
67. Virtual Time (Time Warp)
68. Version Management
69. Garbage Collection
70. Persistent Objects
71. Active Protocols
72. Algorithm animation
73. Language Level Viruses
74. Program Transformation
Implementation
Reflective extensions to an objec t-oriented language should be as much built into the existing language as on top of it
In order to be practical, reflective facilities must be efficient
Some Strategies
Integrate these approaches into the Typed Smalltalk runtime environment or a custom runtime environment
Inlining
Typed Smalltalk Types
Deutcsh and Schiffman Caches and Dynamic Changes of Representation (The PARC Strategy)
MMU stunts
Ungar's Customization/splitting
For instance, Method Lookup can be addressed as per
Foote and Johnson 1989
An appropriate self representation can permit implementation specific information to be attached to the linguisti structures that implement user defined reflective entities
Thus, user defined entities can affect their implementations
The Issues
Is this even possible?
Or are practical obstacles overwhelming?
Is it practical?
Can it be done efficiently?
Is it useful enough to worth doing?
What are the tradeoffs?
What do we include? exclude?
Do we have any other choice?