473,320 Members | 1,810 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Pure Aspect-Oriented Program: an example

Hi,

I have been looking into AOP (Aspect-Oriented Programming) for
sometime, now. I frankly don't like the syntax of any of the
approaches I have seen so far. I am kind playing around with some
ideas, and maybe write up an article later.

AOP is not just buzzword. It's not just callback, it's not just Ruby's
MixIn, it's not just Python's metaclass, it's not just C++'s template.
AOP can be implemented/considered as a subset of metaprogramming... an
important subset that stands on its own. AOP deserves its name,
because one really can think and program in "aspects" instead of
"objects". That being said, I have never seen an example of purely
aspect-based program. So, I thought I'd write up one.

Here it is, and let's get some feedback.

thanks,

Hung Jung

--------------------

Suppose you have to implement a checking account that allows
withdrawal of money. Your first simple implementation may look like:

class Account {
real balance
method withdraw(amount) {
this.balance = this.balance – amount
}
}

A program that withdraws money may look like:

account = new Account()
...
amount = 100
account.withdraw(amount)

In order to simplify the discussion, in the following I will omit all
initialization code details, and assume that variable values have been
properly assigned elsewhere. Also notice that everything is in
pseudocode, I am not using any particular language as base.

After you have implemented the program, your bank manager comes and
tells you there are constraints to the withdrawal of money. For
instance, an account maybe disabled. In OOP, you would modify your
Account class to:

class Account {
real balance
bool enabled
method withdraw(amount) {
if not this.enabled
raise AccountDisabledException
this.balance = this.balance – amount
}
}

Now, stop thinking in OOP. Let us try to think in AOP.

//---------------------------------------------------
class Account {
real balance
method withdraw(amount):
this.balance = this.balance – amount
}

//---------------------------------------------------
aspect AccountStatus {
bool enabled
codeblock check_status {
if not this.enabled:
raise AccountDisabledException
}
method withdraw(...) {
this.check_status
this.withdraw.code
}
}

//---------------------------------------------------
endow Account with AccountStatus
The general idea is to have the concerns implemented outside the
object. We have added a new feature to the account (namely, the
account status,) without having to tweak the original code of the
account. Notice that we have three parts to the above code: a class
definition, an aspect definition, and a final part to endow the aspect
to the class. The last part is also known as the "aspect weaver".

Let us proceed to the next step. Say, there is a maximum daily
withdrawal limit.

//---------------------------------------------------
class Account {
real balance
method withdraw(amount) {
this.balance = this.balance – amount
}
}

//---------------------------------------------------
aspect AccountStatus {
bool enabled
codeblock check_status {
if not this.enabled:
raise AccountDisabledException
}
method withdraw(...) {
this.check_status
this.withdraw.code
}
}

//---------------------------------------------------
aspect WithdrawalLimit {
real daily_limit
real withdrawn_today
codeblock check_and_update_withdraw {
new_withdrawn_today = this.withdrawn_today + amount
if new_withdrawn_today > this.daily_limit:
raise WithdrawalLimitExceededException
&inner_code
this.withdrawn_today = new_withdrawn_today
}
method withdraw(...) {
this.check_and_update_withdraw {
...
&inner_code = this.withdraw.code
...
}
}
}

//---------------------------------------------------
endow Account with AccountStatus
endow Account with WithdrawalLimit

Notice the usage of a hook (also known as pointcut): &inner_code. In
general, a code block or a method can contain one or many hooks. Hooks
allow future enhancement of code. There are two implicit hooks: the
before and the after hooks. But for readability of AOP code, in our
approach we treat named hooks very differently from implicit hooks.
Ruby users should notice that a code block here can contain multiple
hooks, and that the direction of hooking process is kind of opposite
to Ruby's MixIn.

The above way of programming of course takes longer to write. But, the
advantage is in the degree of decoupling (or "separation of concerns")
that is achieved. Say, one day, we want to eliminate the feature on
withdraw limit, it is as simple as commenting out one single line of
code:

endow Account with AccountStatus
//endow Account with WithdrawalLimit

The same is true if one day we want to eliminate the account status
feature:

//endow Account with AccountStatus
endow Account with WithdrawalLimit

Also, once the concerns are separated, it is easier to modify the
aspects individually.

A careful reader would point out that we may want to check the account
status before checking withdrawal limit. Notice also that we have
applied two aspects in sequence. But we can pre-compose two aspects
into one, and apply the composed aspect just once.

//---------------------------------------------------
aspect AccountAspects inherits AccountStatus, WithdrawalLimit {
method withdraw(...) {
this.check_status
this.check_and_update_withdraw {
...
&inner_code = this.withdraw.code
...
}
}
}
//---------------------------------------------------
endow Account with AccountAspects

At this point you may say: "Hey! We started with a non-trivial class…
but we could have started with an empty class, and endow the
balance-calculating feature as an aspect, too." Bingo! Now you are
thinking in AOP.

//---------------------------------------------------
class Account {
}
//---------------------------------------------------
aspect BalanceKeeping {
real balance
method withdraw(amount) {
this.balance = this.balance – amount
}
}

//---------------------------------------------------
aspect AccountStatus {
bool enabled
codeblock check_status {
if not this.enabled:
raise AccountDisabledException
}
method withdraw(...) { // this meta-method is overriden later
this.check_status
this.withdraw.code
}
}

//---------------------------------------------------
aspect WithdrawalLimit {
real daily_limit
real withdrawn_today
codeblock check_and_update_withdraw {
new_withdrawn_today = this.withdrawn_today + amount
if new_withdrawn_today > this.daily_limit:
raise WithdrawalLimitExceededException
&inner_code
this.withdrawn_today = new_withdrawn_today
}
method withdraw(...) { // this meta-method is overriden later
check_and_update_withdraw {
...
&inner_code = this.withdraw.code
...
}
}
}

//---------------------------------------------------
aspect AccountAspects: inherits BalanceKeeping,
AccountStatus,
WithdrawalLimit {
method withdraw(...) {
check_status
check_and_update_withdraw { // this meta-method overrides
...
&inner_code = this.withdraw.code
...
}
}
}
//---------------------------------------------------
endow Account with AccountAspects
print Account.codeString()

Notice that we have started with a bare class with no attributes. All
the features of the class Account have been implemented by aspects,
instead of interfaces or base classes. You may complain: the code is
now too hard to read and follow. But that actually is a problem of IDE
(Integrated Development Environment). For more advanced IDEs, editing
aspects actually should not be bad at all. It's almost like editing
the header and footer information in a Microsoft Word document. At any
rate, the last statement above would print out the code for the
"aspected class", which may look something like:

class Account {
real balance
bool enabled
real daily_limit
real withdrawn_today
method withdraw(amount) {
if not this.enabled:
raise AccountDisabledException
new_withdrawn_today = this.withdrawn_today + amount
if new_withdrawn_today > this.daily_limit:
raise WithdrawalLimitExceededException
this.balance = this.balance – amount
this.withdrawn_today = new_withdrawn_today
}
}

A good IDE/compiler/debugger can provide additional information on
where each code line or code block comes from, hence making debugging
and editing a snap. But we don't need to get into that discussion,
now.

What have we learned? We have learned that:

1. We can write a purely-AOP program.
2. Aspect inheritance can be used to compose derived aspects.
3. A new type of object: "codeblock", becomes the fundamental building
block of programs. So, in general we have to consider the (data,
codeblock, method) trio when building classes or programs. A method
consists of its "header/prototype" and a reference to its codeblock.
Also, in a real program, most codeblocks would be anonymous.
4. Despite of its innocent look, the code specifying an aspect
contains disguised meta-programming instructions.

Codeblock-based AOP actually is more suitable in programming languages
powered with meta-programming features. Also, (data, codeblock,
method) are all supposed to be virtual and overridable. Data
overriding does not do anything, if the data is already present.
Codeblock overriding does not present problem. The main problem is
with method overriding. If the new method refers to the existing
method, there is a problem as how to deal with the names and who will
hold reference to the old method once the new method is in place. For
the AOP practitioners, this means that the "before" and "after"
advices can be implemented more easily, where as the "around" advice
is trickier. A possible solution is to "decorate" the name of the old
implementation. Here I only present a possible syntax of the "around"
advice.

class C {
method f() {
return 3
}
}

aspect A {
method f_before_A = f
method f(...) {
print 'begin around-advice'
result = this.f_before_A()
print 'end around-advice'
return result
}
}

endow C with A
c = new C()
print c.f()

//------ output
begin around-advice
end around-advice
3

One thing I have not mentioned is pattern matching for method names.
An aspect may affect many or all the methods in a class. In that case,
the name of the methods should be listed, or wildcards (possibly
regular expressions) must used to pattern-search for them. Possible
syntax variations are:

aspect A {
method <f>(...) for f in f1, f2, f3 {
}
}

aspect B {
method <f>(...) for f matching 'f*' {
}
}

Another thing that I have not mentioned is that aspects can be endowed
to different classes. For instance, if later we have checking accounts
and savings accounts, we can apply the same aspect to both classes.
That's what other people refer to as "cross-cutting".

.... That's all for now.
Jul 17 '05 #1
1 2342
I noticed that no one has responded to this posting but what the heck.

Two things:
http://www.springframework.org

and

http://www.research.ibm.com/sop

I haven't looked into aspectJ yet but I did take a look at Cool, Riddle,
and D back in 1998. Back then you could only manage a couple of aspects
like remoteness and synchronization.
On Wed, 05 Nov 2003 21:19:38 -0800, Hung Jung Lu wrote:
Hi,

I have been looking into AOP (Aspect-Oriented Programming) for
sometime, now. I frankly don't like the syntax of any of the
approaches I have seen so far. I am kind playing around with some
ideas, and maybe write up an article later.

AOP is not just buzzword. It's not just callback, it's not just Ruby's
MixIn, it's not just Python's metaclass, it's not just C++'s template.
AOP can be implemented/considered as a subset of metaprogramming... an
important subset that stands on its own. AOP deserves its name,
because one really can think and program in "aspects" instead of
"objects". That being said, I have never seen an example of purely
aspect-based program. So, I thought I'd write up one.

Here it is, and let's get some feedback.

thanks,

Hung Jung


Jul 17 '05 #2

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

51
by: Noam Raphael | last post by:
Hello, I thought about a new Python feature. Please tell me what you think about it. Say you want to write a base class with some unimplemented methods, that subclasses must implement (or...
5
by: Fuzzyman | last post by:
Python 2.4 is built with Microsoft Visiual C++ 7. This means that it uses msvcr7.dll, which *isn't* a standard part of the windows operating system. This means that if you build a windows installer...
11
by: santosh | last post by:
Hello, I was going through the Marshal Cline's C++ FAQ-Lite. I have a doubt regarding section 33.10. Here he is declaring a pure virtual destructor in the base class. And again defining...
13
by: junky_fellow | last post by:
I have read certain articles that encourage to use/write pure functions (if possible) as they are better suited for optimization. I got one example that expalins how the code can be optimised....
5
by: Ron Vecchi | last post by:
I know the math I need to perform on width and height to keep an aspect ratio but where and how would I implement keeping a set aspect ratio on a form when a user resizes it. Override OnResize?...
8
by: Ted Miller | last post by:
Hi folks, I'm looking at moving a large base of C++ code to .Net under tight time constraints. The code runs in mission-critical environments, and I am extremely concerned about the loader lock...
6
by: pakis | last post by:
I am having a problem of pure virtual function call in my project. Can anyone explaine me the causes of pure virtual function calls other than calling a virtual function in base class? Thanks
5
by: =?Utf-8?B?UmljaA==?= | last post by:
Hello, If I create a form in Java with controls like Panels, textboxes... when I stretch/shrink the form, all the controls can grow/shrink - along with the text contained in the textboxes. This...
5
by: =?Utf-8?B?U2hhcm9u?= | last post by:
I have a class that is writen in unmanaged pure native C++. This class files (h and cpp) are inserted to a managed C++ (VC++ 2005, C++/CLI) DLL compoenet. This DLL compoenet is used in a C#...
14
by: Jack | last post by:
Hi, I meet a question with it , I did not get clear the different betteen them, for example: #include <iostream>
0
by: DolphinDB | last post by:
Tired of spending countless mintues downsampling your data? Look no further! In this article, you’ll learn how to efficiently downsample 6.48 billion high-frequency records to 61 million...
0
by: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: jfyes | last post by:
As a hardware engineer, after seeing that CEIWEI recently released a new tool for Modbus RTU Over TCP/UDP filtering and monitoring, I actively went to its official website to take a look. It turned...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.