Enabling White-Box Reuse in a Pure Composition Language
1. Enabling White-Box Reuse in a
Pure Composition Language
Andreas Schlapbach
schlpbch@iam.unibe.ch
January, 2003.
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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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
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. 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
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. 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. 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
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