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?


Brian Foote foote@cs.uiuc.edu
Last Modified: 12 November 2005