Embed
Email

Asp

Document Sample

Shared by: gegeshandong
Categories
Tags
Stats
views:
0
posted:
10/27/2011
language:
English
pages:
40
Aspectual Collaborations



Flexible Modules for

Generic Object Oriented

Programming

Host Class Graph

• Consists of Classes written by programmer

connected by interrelationships

• Has-A parts

• Is-A edges

• Just plain ol’ java.

Collaboration

• Like a class graph, but

– Roles instead of Classes

– Roles may have missing behavior (methods or

fields)

– Closed

• No new roles can be added to the collaboration

Roles

• Differ from classes in that they may have

missing methods or fields

• Different from abstract

– Abstract behavior must be method

– Abstract classes can never be instantiated

– Roles will be completed in-situ at a later date.

Adapter

• Connects host class graph and collaboration

– Classes and Roles equated pointwise

– Subject to semantic constraints

• Collaboration is stretched to fit

• Provides expected parts by exports from

host

• Exports some parts of collaboration to

outside world, encapsulates rest

Example: Sort Host

package host;

class HasUsers {

User[] users;

void initUsers() { ... }

void addUser(User u) { ... }

void sortusers() { System.err.println("No sorting. Yet."); }

User firstuser() {

sortusers();

return users[0];

}

}

class User {

String name;

int uid;

boolean alphabeticallybefore(User that) {

return this.name.lexicographicallybefore(that.name);

}

boolean uidbefore(User u) { return this.uid < that.uid; }

}

Example: Sort Collaboration

collaboration sort;

role ArrayHolder {

expected Item[] arr;

void insertionsort() {

for (int i=0; i
if (arr[j].before(arr[i])) swap(i,j);

int m=0.0;

for (int i=0; i
System.out.println("geom. average number of moves: "+(m/arr.length));

}

private void swap(int i, int j) {

arr[i].moved++; arr[j].moved++;

Item o = arr[i]; arr[i]=arr[j]; arr[j]=o;

}

}

role Item {

expect boolean before(Item other);

int moved = 0;

}

Example: Sort Adapter

adapter sortedhost;

combine {sort,host} {

host.HasUsers += sort.ArrayHolder {

sort::Item[] arr provided-by host::User[] users;

host::void sortusers() provided-by sort::void insertionsort();

}

host.User += sort.Item {

sort::boolean before(Item) provided-by host::boolean uidbefore(User);

}

}

Discussion

• Expected parts are what give a collaboration

a tight yet generic coupling to the host

application.

• Allow generic behavior to have complex

interactions with host behavior.

Different class graphs

• How much may the collaboration’s role

graph and host class graph differ?

– Must maintain sub/super class links

– Expected types after mapping must match types

provided by host: Item must be User since

arr is users

Composition

• Why does the host need to be a complete

class graph? Why not a collaboration too?

• Provide behavior needed by one from the

other.

• Some behavior remains expected.

• But, What is the return type?

– come back next week for exciting conclusion!

Same bat time, same bat channel

A Tale of Two Implementations

Dynamic / Proxy

• Layering behavior like a cake

• Host remains unchanged

• Two simultaneous different types, but no object

equality between them.

• Behavior can be removed

• No permanent memory overhead

• Hard to compose

• Object mapping hard (vectors are nigh impossible)

• Unclear whether we can be type safe and pre-

compiled at the same time

‘tis a far far better thing

• Combine bytecode to make new class

– Already front-end processed

– Type checked, easily parsable

– More SOP than layering

• Determine types by adapter

• Permanent

• Can be precompiled type safely (each object

has only one type)

Format of Class Files

• The secret to working

ClassPool

with class files are

their convenient layout

• All references are Info

stored in one local

pool, the class pool. Fields

Parts are stored in area,

Methods

and class attributes in

the last. Attributes

The Constant Pool

• All identifiers and references stored there

– MethodRef, FieldRef, InterfaceMethodRef

– External Method and Type Refs

• same for fields and methods!

– Constant: Strings, Ints, Doubles, Classes, …

– Raw Strings

No need to inspect method body

• To move into a new class, we just do a

recursive copy into new class, chasing all

index pointers into constant pool.

Dealing with Expected Parts

• Preprocessor adds stub body to all expected

method.

• Postprocessor annotates expected parts as such, so

that stub may be thrown away.

• For unit testing purposes, bodies may not be stubs,

but user-written test stubs that simulate expected

behavior.

– Allows collaborations to be tested without application.

– Can be simulated by linking to simplistic app.

How to store annotations

Constant pool

Void foo()

• Expected methods

OtherClass::int bar

need to be marked as

such, so that our 1234.6

implementation knows

it’s ok to remove their Method entry in class

existing body. Info_index

• Class files allow ATTR_expected

ATTR_deprecated

additional attributes to ATTR_Code

be stored on fields and

methods. Byte code is

one

Alpha Conversion vs Export

• Of course, we don’t want to pollute name

space of resulting class file, so we

systematically rename all intra-

collaboration references.

• Names exported are renamed to resulting

name, while non-exported names are

renamed to unpronouncable names ($).

Implementation Subconclusion

• Class files are easy and flexible to work with

• Pre-parsed semantics make our life easier, while

compiled status means we can take well-

formedness for granted.

• This implementation is statically linked (we build

up new collaborations from old statically).

Dynamic linking is an option, but hard.

Composition, Cont

• Under insertive approach, the types are

completely decided by adapter: we are

creating new classes

• Must make sure no expected parts are

unexported – they become unprovidable

Aspects

• We’ve been promising aspectual

programming. Now we get some.

• Aspects are defined as systematic behaviors

that are localised to issue, but distributed

over multiple classes

• Additionally, the rest of the program can be

oblivious to aspects’ existence

(Filman&Friedman).

Precise Aspects

• Precise aspects we almost have already. All

we require is to not throw away old method

body when replacing a method stub. (memo

to self- what happens when we wrap an

expected method?)

• Allows us to play with arguments of

wrapped method

Example: No Duplicates, please

collaboration nodups;

role ElemHolder {

expected Elem[] elems;

expected void addElem(Elem e);

void insertMaybe(Elem e) {

for (int i=0; i
if (elems[i].equals(e)) return;

addElem(e);

}

}

role Elem {

expect int id;

public equals(Object o) { return ((Elem)o).id == id; }

}

Example: No Duplicates, cont

adapter sortednoduphost;

combine {nodups,sortedhost} {

sortedhost.HasUsers += nudups.ElemHolder {

nodups::Elem[] elems provided-by sortedhost::User[] users;

sortedhost::void addUser(User)

replaced-by nodups::void insertMaybe(Elem)

provides nodups::void addElem(Elem);

}

sortedhost.User += nodups.Elem {

export nodups::boolean equals(Object);

}

}

What happens

• When the addUser method is invoked, the

collaboration addElem is invoked instead,

and eventually invokes the expected old

method.

• Notice that the aspect magic is from the

adapter, the collaboration sees it as a normal

method.

Generic Aspects

• Precise aspects are nice, but very limited

– How often can do we know the interface

precisely

• Approach:

– Precompile method to known simple signature

– Wrap with generated code at adaptation time to

convert arguments and return values of

wrapped host method to the known signature

Example: Keep it Sorted

collaboration keepsorted;

role Thing {

expected void sort();

aspectual ReturnVal sortafter(ExpectedMethod e) {

ReturnVal r = e.invoke();

sort();

return r;

}

}



adapter keepsortedhost;

combine {keepsorted,sortedhost} {

sortedhost.HasUsers += keepsorted.Thing {

keepsorted::void sort() provided-by sortedhost::sortusers();

keepsorted::sortafter wraps sortedhost::void initUsers();

}

} and {

sortedhost.HasUsers += keepsorted.Thing {

keepsorted::void sort() provided-by sortedhost::sortusers();

keepsorted::sortafter wraps sortedhost::void addUser(User);

}

}

Discussion: Generated Code

From Collaboration

package keepsorted;

class Thing {

void sort() { /*expected*/ };

ReturnVal$A sortafter(ExpectedMethod$A e) {

/*aspectual*/

ReturnVal$A r = e.invoke();

sort();

return r;

}

}

abstract class ReturnVal$A { }

abstract class ExpectedMethod$A {

abstract ReturnVal$A invoke();

}

Discussion: Generated Code

package keepsortedhost;

From Adapter

class HasUsers {

...

void sortusers() { ... };

ReturnVal$A sortafter$addUser(ExpectedMethod$A e) {

/*aspectual*/

ReturnVal$A r = e.invoke(); sortusers(); return r;

}

void addUser$A(Elem e) { /* original method body, untouched */ }

void addUser(Elem e) { }

ExpectedMethod$A ex = new ExpectedMethod$A$addUser(this,e);

ReturnVal$A$addUser r = (ReturnVal$A$addUser) sortafter$addUser(ex);

return;

}

}

class ReturnVal$A$addUser extends ReturnVal$A { }

class ExpectedMethod$A$addUser extends ExpectedMethod$A {

User arg1; HasUsers self;

ExpectedMethod$A$addUser(HasUsers s, User u) { self=s; arg1=u; }

ReturnVal$A invoke() {

ReturnVal$A$addUser r = new ReturnVal$A$addUser();

self.addUser$A(arg1);

}

}

The wrapping approach

• Handles return values of any type

• Exceptions in a similar manner

• Since each signature will generate different

extracting code (exceptions must be

rethrown, for example) we have to have

subclasses of ReturnVal for each signature.

We then downcast to the known type to

extract info

The dollar signs

• The needed downcast is in the generated

body for addUser. We must make sure this

cast succeeds, as it is not in user code, and

they will not know what caused it.

Causing a casting error

collaboration fail;

role Foo {

RV old; adapter whatever;

aspectual RV meth(EM e) { combine {fail,host} {

ReturnVal r = e.invoke(); host.A += fail.Foo {

ReturnVal o = old; export fail::RV old

old = r; fail::meth wraps host::A get_a();

return (o!=null):o?r; }

} } and {

} host.B += fail.Foo {

export fail::RV old

package host; fail::meth wraps host::void print();

class A { }

A get_a() { return new A(); } } void failit() {

} A anA = new A(); B aB = new B();

class B { aB.print();

void print() { System.err.println("hi"); } // now aB.old has void ReturnVal

} aB.old = anA.old; // so does anA!

A otherA = anA.get_a();

// tries to unwrap void to A

}

Existential Types

• ReturnVal and ExpectedMethod are local to

an attachment of the collaboration; we

cannot export them.

• We assure this by adding the

unpronounceable $ to their types; thus they

cannot be mentioned in an adapter, and

cannot be exported.

• Casting is still an issue, but that’s java.

Aspectual Subconclusion

• Small addition to collaborations make them

intuitive fits for aspectual programming.

• We are able to offer type-safe separate

compilation of aspects that can be used with

a wide variety of class graphs.

Scoping Collaborations

• Objects have variables scoped per instance and per

class.

• Collaborations have another dimension:

– Per Attachment

• A counter for method invocation is per method. The default.

– Per Host

• A counter for method invocation is shared for methods of

class. Expected parts have this property.

– Per Application

• All the methods of the application share the same counter. Can

be simulated a-la object oriented globals.

A Scoping example

collaboration c_attachment; collaboration c_shared;

role Counter { role CountHolder {

int att=0; int shared=0;

static int st_att=0; static int st_shared=0;

expected int sha; }

expected int st_sha;

aspectual ReturnVal meth(ExpectedMethod exmeth) {

att++; st_att++; sh++; st_sh++;

System.err.println("this wrapped method on this object: "+att+

" and for all objects of this class: "+st_att);

System.err.println("all wrapped methods of this object: "+sha+

" and for all objects of this class: "+st_sha);

return exmeth.invoke();

}

}



adapter counting;

combine {c_shared,c_attachment} {

Counted = {c_shared.CountHolder,c_attachment.Counter} {

c_attachment::int sha provided-by c_shared::int shared;

c_attachment::static int st_sha provided-by c_shared::static int st_shared;

export c_attachment::aspectual meth;

}

}

Discussion: Scoping

• Composition is used to add the expected

parts to the host.

• It is still unclear how we specify that one

sub-collaboration is only added once, the

other possibly multiple times.

Conclusion

• Very flexible system

• Our mechanisms expressive enough to

express many kinds of aspectual behavior

• Few unclear issues

– What is added once from composed collabs,

what is duplicated.

– Wrapping expected methods with ascpectual

methods.



Related docs
Other docs by gegeshandong
Mar - Mr Hanson
Views: 0  |  Downloads: 0
WhatDoYouMeanHighest.Price
Views: 0  |  Downloads: 0
core data
Views: 0  |  Downloads: 0
jan-18-2009b
Views: 0  |  Downloads: 0
Status - California State University
Views: 0  |  Downloads: 0
PHASE ONE
Views: 0  |  Downloads: 0
By registering with docstoc.com you agree to our
privacy policy

You are almost ready to download!

You are almost ready to download!