Aspect oriented programming: Difference between revisions

Content added Content deleted
m (→‎{{header|J}}: make example slightly easier for a casual reader to follow)
m (syntax highlighting fixup automation)
Line 23: Line 23:
=={{header|6502 Assembly}}==
=={{header|6502 Assembly}}==
The easiest way to do this is by putting every related function into the same file. One important thing to remember is that in 6502 (and most other assembly languages for that matter, unless linkers are involved), the order in which your code is placed implies its memory location. This is not the case in other languages, not even in [[C]].
The easiest way to do this is by putting every related function into the same file. One important thing to remember is that in 6502 (and most other assembly languages for that matter, unless linkers are involved), the order in which your code is placed implies its memory location. This is not the case in other languages, not even in [[C]].
<lang 6502asm>;Basic_Functions.asm
<syntaxhighlight lang=6502asm>;Basic_Functions.asm
SwapXY:
SwapXY:
pha
pha
Line 39: Line 39:
NewLine: ;the above function will be stored in memory above this one.
NewLine: ;the above function will be stored in memory above this one.
lda #13
lda #13
jmp $FFD2 ;PrintChar on Commodore 64</lang>
jmp $FFD2 ;PrintChar on Commodore 64</syntaxhighlight>


This is somewhat relevant because it lets you abuse fallthrough. If you have a special case of a particular function that you use often, you can easily make that special case its own function by having it load those specific parameters and then "falling through" into the function you're actually running. This helps to reduce call/return penalties while keeping your relevant pieces of code together. Unfortunately, you can only do this once per function, for obvious reasons.
This is somewhat relevant because it lets you abuse fallthrough. If you have a special case of a particular function that you use often, you can easily make that special case its own function by having it load those specific parameters and then "falling through" into the function you're actually running. This helps to reduce call/return penalties while keeping your relevant pieces of code together. Unfortunately, you can only do this once per function, for obvious reasons.


<lang 6502asm>NewLine:
<syntaxhighlight lang=6502asm>NewLine:
LDA #10 ;linefeed
LDA #10 ;linefeed
;the PrintChar function is literally below this line, both in a source code sense and a memory layout sense.
;the PrintChar function is literally below this line, both in a source code sense and a memory layout sense.
Line 50: Line 50:
;input: A = the ascii code you wish to print to the screen.
;input: A = the ascii code you wish to print to the screen.
;
;
; unimplemented because it's dependent on the video hardware but you get the idea</lang>
; unimplemented because it's dependent on the video hardware but you get the idea</syntaxhighlight>


=={{header|Ada}}==
=={{header|Ada}}==
Line 56: Line 56:


Example parent package specification:
Example parent package specification:
<lang Ada>package parent is
<syntaxhighlight lang=Ada>package parent is
function Add2 (X : in Integer) return Integer;
function Add2 (X : in Integer) return Integer;
end parent;</lang>
end parent;</syntaxhighlight>
Example parent package body:
Example parent package body:
<lang Ada>package body parent is
<syntaxhighlight lang=Ada>package body parent is


function Add2 (X : in Integer) return Integer is
function Add2 (X : in Integer) return Integer is
Line 67: Line 67:
end Add2;
end Add2;


end parent;</lang>
end parent;</syntaxhighlight>
Example child package specification:
Example child package specification:
<lang Ada>package parent.child is
<syntaxhighlight lang=Ada>package parent.child is
function Add2 (X : in Integer) return Integer;
function Add2 (X : in Integer) return Integer;
end parent.child;</lang>
end parent.child;</syntaxhighlight>
Example child package specification:
Example child package specification:
<lang Ada>with Ada.Text_IO; use Ada.Text_IO;
<syntaxhighlight lang=Ada>with Ada.Text_IO; use Ada.Text_IO;


package body parent.child is
package body parent.child is
Line 83: Line 83:
end Add2;
end Add2;


end parent.child;</lang>
end parent.child;</syntaxhighlight>
The following program demonstrates calling both the Add2 function from the parent package and calling the Add2 function from the child package. The child package has visibility to the public portion of the parent package and can therefore call the parent's Add2 function directly.
The following program demonstrates calling both the Add2 function from the parent package and calling the Add2 function from the child package. The child package has visibility to the public portion of the parent package and can therefore call the parent's Add2 function directly.
<lang Ada>with parent.child;
<syntaxhighlight lang=Ada>with parent.child;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Text_IO; use Ada.Text_IO;


Line 99: Line 99:
Result := parent.child.Add2 (Num);
Result := parent.child.Add2 (Num);
Put_Line ("Result : " & Result'Image);
Put_Line ("Result : " & Result'Image);
end Main;</lang>
end Main;</syntaxhighlight>
{{output}}
{{output}}
<pre>
<pre>
Line 118: Line 118:
When a new feature introduces code scattered throughout the program, we can relate all the code together using a define and ifdefs.
When a new feature introduces code scattered throughout the program, we can relate all the code together using a define and ifdefs.


<syntaxhighlight lang=c>
<lang c>
#define MY_NEW_FEATURE_ENABLED
#define MY_NEW_FEATURE_ENABLED


Line 132: Line 132:
close_my_new_feature();
close_my_new_feature();
#endif
#endif
</syntaxhighlight>
</lang>


As well as allowing us to enable or disable the feature at compile time, this also provides a way to find all the relevant code easily, by searching for the variable name.
As well as allowing us to enable or disable the feature at compile time, this also provides a way to find all the relevant code easily, by searching for the variable name.
Line 142: Line 142:
An alternative macro method can be used in C, which is shorter for one-liners.
An alternative macro method can be used in C, which is shorter for one-liners.


<syntaxhighlight lang=c>
<lang c>
/* Enable logging: */
/* Enable logging: */
/* #define LOG(x) printf("%s\n",x); */
/* #define LOG(x) printf("%s\n",x); */
Line 153: Line 153:


...
...
</syntaxhighlight>
</lang>


===Using function pointers===
===Using function pointers===
Line 161: Line 161:
Here is a typical layout:
Here is a typical layout:


<lang c>struct object {
<syntaxhighlight lang=c>struct object {
struct object_operations *ops;
struct object_operations *ops;
int member;
int member;
Line 168: Line 168:
struct object_operations {
struct object_operations {
void (*frob_member)(struct object *obj, int how);
void (*frob_member)(struct object *obj, int how);
};</lang>
};</syntaxhighlight>


In this example, an object is constructed as an instance of <code>struct object</code> and the <code>ops</code> field is filled in with a pointer to an operations table of type <code>struct object_operations</code>. The object is usually dynamically allocated, but the operations table is often statically allocated, and the function pointers are statically initialized.
In this example, an object is constructed as an instance of <code>struct object</code> and the <code>ops</code> field is filled in with a pointer to an operations table of type <code>struct object_operations</code>. The object is usually dynamically allocated, but the operations table is often statically allocated, and the function pointers are statically initialized.
Line 174: Line 174:
A call to the <code>frob_member</code> method, if coded by hand without the help of any macros or wrapper functions, would look like this:
A call to the <code>frob_member</code> method, if coded by hand without the help of any macros or wrapper functions, would look like this:


<lang c>pobj->frob_member(pobj, 42);</lang>
<syntaxhighlight lang=c>pobj->frob_member(pobj, 42);</syntaxhighlight>


This representation opens the door to various possibilities. To gain control over all of the calls to an object, all we have to do is replace its <code>ops</code> pointer with a pointer to another operations structure of the same type, but with different function pointers.
This representation opens the door to various possibilities. To gain control over all of the calls to an object, all we have to do is replace its <code>ops</code> pointer with a pointer to another operations structure of the same type, but with different function pointers.
Line 250: Line 250:
┌─┐
┌─┐
│8│
│8│
└─┘</lang>
└─┘</syntaxhighlight>


Or, generally speaking, J provides us with the ability to wrap arbitrary statements with information gathering statements while allowing the original expression to proceed. (And, if we enable debugging, this information gathering can examine the surrounding context, gathering and reporting information on the calling environment, inspecting the local symbol table, the names of routines, the defining script(s), etc.)
Or, generally speaking, J provides us with the ability to wrap arbitrary statements with information gathering statements while allowing the original expression to proceed. (And, if we enable debugging, this information gathering can examine the surrounding context, gathering and reporting information on the calling environment, inspecting the local symbol table, the names of routines, the defining script(s), etc.)
Line 264: Line 264:
=={{header|Julia}}==
=={{header|Julia}}==
Several of Julia's graphics frameworks use the idea of a backend for graphics, where the graphics module wraps and extends a lower level graphics framework. The use of one module to wrap another captures most of the ways in which aspect programming seems to be used. As an example, here we add logging to a module. Users of the Adder module can simply import the LogAspectAdder module instead of the Adder module to add logging to the functions of the Adder class.
Several of Julia's graphics frameworks use the idea of a backend for graphics, where the graphics module wraps and extends a lower level graphics framework. The use of one module to wrap another captures most of the ways in which aspect programming seems to be used. As an example, here we add logging to a module. Users of the Adder module can simply import the LogAspectAdder module instead of the Adder module to add logging to the functions of the Adder class.
<lang julia>module Adder
<syntaxhighlight lang=julia>module Adder
exports add2
exports add2


Line 286: Line 286:
end
end
end
end
</syntaxhighlight>
</lang>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
Line 322: Line 322:


Actually, there is one way to instrument (specific) calls without modifying the existing code. Suppose you have somelib.e, containing:
Actually, there is one way to instrument (specific) calls without modifying the existing code. Suppose you have somelib.e, containing:
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<span style="color: #008080;">global</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">saysomething</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">procedure</span> <span style="color: #000000;">saysomething</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"something\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"something\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
Then write wraplib.e as follows:
Then write wraplib.e as follows:
<!--<lang Phix>-->
<!--<syntaxhighlight lang=Phix>-->
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">somelib</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #008080;">as</span> <span style="color: #000000;">somelib</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">somelib</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span> <span style="color: #008080;">as</span> <span style="color: #000000;">somelib</span>
Line 336: Line 336:
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"thingwrap\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"thingwrap\n"</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">procedure</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
And replace all (existing) "include somelib.e" with "include wraplib.e". Hopefully there will be (and usually there is) only one.
And replace all (existing) "include somelib.e" with "include wraplib.e". Hopefully there will be (and usually there is) only one.


Line 344: Line 344:


Personally, while I might begrudgingly accept that sort of thing for the occasional quick 'n dirty, or a temporary debug aid, I am strongly opposed to it being permanent, and instead strongly believe '''code should do what it says it does''', no more and no less. For easy toggling, my own code tends to be littered with things like:
Personally, while I might begrudgingly accept that sort of thing for the occasional quick 'n dirty, or a temporary debug aid, I am strongly opposed to it being permanent, and instead strongly believe '''code should do what it says it does''', no more and no less. For easy toggling, my own code tends to be littered with things like:
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<span style="color: #008080;">global</span> <span style="color: #008080;">constant</span> <span style="color: #000000;">NEWFEATURE</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #008080;">global</span> <span style="color: #008080;">constant</span> <span style="color: #000000;">NEWFEATURE</span> <span style="color: #0000FF;">=</span> <span style="color: #004600;">true</span>
<span style="color: #0000FF;">...</span>
<span style="color: #0000FF;">...</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">NEWFEATURE</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">...</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">NEWFEATURE</span> <span style="color: #008080;">then</span> <span style="color: #0000FF;">...</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
I also actually favour explicit shims, almost exactly what the task is asking for a way to avoid doing, such as
I also actually favour explicit shims, almost exactly what the task is asking for a way to avoid doing, such as
<!--<lang Phix>(phixonline)-->
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<span style="color: #008080;">function</span> <span style="color: #000000;">my_length</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">my_length</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">return</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<!--</lang>-->
<!--</syntaxhighlight>-->
and manually edit every single call, again so that any future (/temporary) changes are quick, easy & obvious.<br>
and manually edit every single call, again so that any future (/temporary) changes are quick, easy & obvious.<br>
Also note the latter is compatible with p2js, whereas namespaces are not.
Also note the latter is compatible with p2js, whereas namespaces are not.
Line 375: Line 375:


For example:
For example:
<lang tcl>oo::class create InterceptAspect {
<syntaxhighlight lang=tcl>oo::class create InterceptAspect {
filter <methodCalled>
filter <methodCalled>
method <methodCalled> args {
method <methodCalled> args {
Line 394: Line 394:
puts ">>[xmpl calculate 2 3 5]<<"
puts ">>[xmpl calculate 2 3 5]<<"
oo::objdefine xmpl mixin InterceptAspect
oo::objdefine xmpl mixin InterceptAspect
puts ">>[xmpl calculate 2 3 5]<<"</lang>
puts ">>[xmpl calculate 2 3 5]<<"</syntaxhighlight>
{{out}}
{{out}}
>>22<<
>>22<<
Line 410: Line 410:
Notice also that a client can still import the ''wrapped'' class via the ''wrapper'' module which enables it to call ''unwrapped'' methods without the need to import the ''wrapped'' module as well. To expand the Julia example a little:
Notice also that a client can still import the ''wrapped'' class via the ''wrapper'' module which enables it to call ''unwrapped'' methods without the need to import the ''wrapped'' module as well. To expand the Julia example a little:


<lang ecmascript>/* adder.wren */
<syntaxhighlight lang=ecmascript>/* adder.wren */


class Adder {
class Adder {
Line 416: Line 416:


static mul2(x) { x * 2 }
static mul2(x) { x * 2 }
}</lang>
}</syntaxhighlight>


<lang ecmascript>/* logAspectAdder.wren */
<syntaxhighlight lang=ecmascript>/* logAspectAdder.wren */


import "/adder" for Adder
import "/adder" for Adder
Line 434: Line 434:
return Adder.add2(x)
return Adder.add2(x)
}
}
}</lang>
}</syntaxhighlight>


<lang ecmascript>/* adderClient.wren */
<syntaxhighlight lang=ecmascript>/* adderClient.wren */


import "/logAspectAdder" for LogAspectAdder, Adder
import "/logAspectAdder" for LogAspectAdder, Adder
Line 443: Line 443:
var m = Adder.mul2(4)
var m = Adder.mul2(4)
System.print("3 + 2 = %(a)") // logged
System.print("3 + 2 = %(a)") // logged
System.print("4 * 2 = %(m)") // not logged</lang>
System.print("4 * 2 = %(m)") // not logged</syntaxhighlight>


{{out}}
{{out}}