Enabling White-Box Reuse in a Pure Composition Language

1,084 views

Published on

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,084
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Enabling White-Box Reuse in a Pure Composition Language

  1. 1. Enabling White-Box Reuse in a Pure Composition Language Andreas Schlapbach schlpbch@iam.unibe.ch January, 2003.
  2. 2. Overview • Introduction – Component-based software development. – Roles of inheritance. – Subclassing as a form of white-box reuse. – Subclassing considered harmful. • Goal – To combine the power of inheritance with the ease of scripting. • Solution – Piccola, our composition language. – Introduce a language extension to JPiccola that enables inheritance. – Implementation and examples. – Applications. • Lessons Learned • Questions & Comments 2
  3. 3. Component-based Software Development • Modern applications must be flexible and extendible to adapt to changing require- ments. • These requirements can be addressed best by a component-oriented software devel- opment approach. • Component-oriented software development shifts away from programming towards soft- ware composition. 3
  4. 4. Scripting Real-World Components • Applications = Components + Script + a Drop of Glue. • We build applications by scripting compo- nents. • These components must adhere to a com- positional style. • In reality, such components often do not exist. £ We have to adapt existing components, us- ing a drop of glue. 4
  5. 5. Adaptation: Black-box versus White-box White-box Reuse. Adapts a mismatched com- ponent by either changing or overriding its internal specification. E.g.: Copy & Paste, Inheritance Black-box Reuse. Adapts the interface of a component only. E.g.: Wrapping techniques, Reflective ap- proach, Standardization 5
  6. 6. Roles of Inheritance Inheritance is a key concept of object-oriented languages and plays different roles: Subclassing. At the implementation level, it is a means for code reuse. Subtyping. At the design level, it defines a substitutability relationship. Is-a Relationship. At the conceptual level, it represents a conceptual specialization rela- tionship. These roles of inheritance can conflict. 6
  7. 7. Subclassing Considered Harmful • Subclassing can break encapsulation by ac- cessing internal implementation details of an object. • Subclassing introduces subtle dependencies between base and extending classes. • Subclassing is a white-box form of reuse. £ Let’s minimize the use of inheritance. 7
  8. 8. Goal: Migrate from Class Inheritance to Object Composition • There are many powerful object-oriented frameworks we would like to reuse as black- box components. • We need inheritance to access their func- tionality. • Our approach is to gain access to the com- ponents of a framework using inheritance, wrap them and script those wrapped com- ponents. £ We would like to have the power of inheri- tance combined with the ease of scripting. 8
  9. 9. Piccola • Piccola is a small, pure and general pur- pose scripting language. • Piccola is based on forms, agents and chan- nels: Agents communicate by sending forms along channels. • Forms are extensible records unified with services. Everything is a form. • JPiccola is the Java-based implementation of Piccola. 9
  10. 10. A Language Extension for JPiccola We want to use Java frameworks in Piccola using inheritance. Key idea: Create Java objects implementing a given type that delegate all calls to its meth- ods to Piccola services. func(args): ... Java result up(args) down(result) Piccola func(arg1, arg2,...,argn) £ We have to generate classes of a given type at runtime. 10
  11. 11. Implementation I The class generation process consists of three steps: 1. Gather information on the structure of the class. 2. Generate the class, using the BCEL byte code engineering library. 3. Load the class into the Java Virtual Ma- chine, using a custom class loader. 11
  12. 12. Structure of a Generated Class I Let’s suppose we have class A with a method plus(int i, int j). We define a service plus in Piccola to handle calls to this method. plus(args): ’i = args.at(1) ’j = args.at(2) i + j We generate a subclass of A and redirect the Java call to a Piccola service: public int plus(int j, int j) { Arguments args = new Arguments(); args.add(this); args.add(new Integer(i)); args.add(new Integer(j)); return ((Integer) getService(quot;plusquot;) .callback(args)).intValue(); } 12
  13. 13. Structure of a Generated Class II Actually, we generate byte code. Method int plus(int, int) 0 new #22 <Class ch.unibe.piccola.bridge.Arguments> 3 dup 4 invokespecial #23 <Method ch.unibe.piccola.bridge.Arguments()> 7 astore 4 9 aload 4 11 aload_0 12 invokevirtual #27 <Method void add(java.lang.Object)> 15 aload 4 17 new #56 <Class java.lang.Integer> 20 dup 21 iload_1 22 invokespecial #65 <Method java.lang.Integer(int)> 25 invokevirtual #27 <Method void add(java.lang.Object)> 28 aload 4 30 new #56 <Class java.lang.Integer> 33 dup 34 iload_2 35 invokespecial #65 <Method java.lang.Integer(int)> 38 invokevirtual #27 <Method void add(java.lang.Object)> 41 aload_0 42 ldc #75 <String quot;plusquot;> 44 invokevirtual #33 <Method ch.unibe.piccola.IForm getService(java.lang.String)> 47 aload 4 49 invokeinterface (args 2) #39 <InterfaceMethod java.lang.Object callback(ch.unibe.piccola.bridge.Arguments)> 54 checkcast #56 <Class java.lang.Integer> 57 invokevirtual #60 <Method int intValue()> 60 ireturn 13
  14. 14. Example I generateSubclassOfA(): newClass name = quot;Bquot; superClassName = quot;Aquot; interfaceNames = [ ] methods = plus = argumentTypeList = [ Type.int, Type.int ] returnType = Type.int body(args): args.at(1) + args.at(2) 14
  15. 15. Implementation II Often, we do not need to generate an arbitrary class but implement an interface or generate a direct subclass of an abstract class. £ We can use reflection to gather the infor- mation needed to generate a class. 15
  16. 16. Example II generateKeyListener(): newInterface className = quot;java.awt.event.KeyListenerquot; methods = keyPressed(args): println quot;Key Pressedquot; keyReleased(args): println quot;Key Releasedquot; keyTyped(args): println quot;Key Typedquot; 16
  17. 17. Applications • Print Service • Scripting an Event Based Parser • Scripting Web Browser Frameworks • GUI Event Composition Style • ... £ We use the language extension whenever we need inheritance. 17
  18. 18. Role of Java Interfaces in Frameworks • We seldom generate arbitrary classes, most often we just implement Java interfaces. Why is this? • A framework consists of ready-to-use and half finished building blocks. • While most parts are stable, it permits its user to adapt parts of it according to their needs. These are the hot spots of a frame- work. • Superior to (abstract) classes, interfaces do not impose a specific inheritance hier- archy. £ Java interfaces provide a good way to con- trol the type of adaptations compatible with a framework. 18
  19. 19. Closing Remarks • The language extension integrates nicely into JPiccola. • Good components are hard to find. • A framework is more than a bundle of classes. 19
  20. 20. Questions & Comments 20
  21. 21. ClassFile ClassFile { u4 magic; u2 minor_version; u2 major_version; u2 constant_pool_count; cp_info constant_pool[constant_pool_count-1]; u2 access_flags; u2 this_class; u2 super_class; u2 interfaces_count; u2 interfaces[interfaces_count]; u2 fields_count; field_info fields[fields_count]; u2 methods_count; method_info methods[methods_count]; u2 attributes_count; attribute_info attributes[attributes_count]; } 21

×