aboutsummaryrefslogtreecommitdiffstats
path: root/docs/sandbox/common/language/DoubleDispatch.java
blob: 2d5a23f0acfb4da4f8fca312e407c2b0019e9b3d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package language;

import org.aspectj.testing.Tester;

/** @author Wes Isberg */
public class DoubleDispatch {

    public static void main(String[] a) {
        Worker worker = new Worker();
        worker.run((SuperType) new SubTypeOne());
        worker.run((SuperType) new SubTypeTwo());
        worker.run(new SuperType());
        Tester.checkAllEvents();
    }
    static aspect A {
        static int counter;
        static {
            Tester.expectEvent("language.SubTypeOne-1");
            Tester.expectEvent("language.SubTypeTwo-2");
            Tester.expectEvent("language.SuperType-3");
        }
        before(Object o) : execution(void Worker.run(..)) && args(o) {
            Tester.event(o.getClass().getName() + "-" + ++counter);
        }
    }
}

// START-SAMPLE language-doubleDispatch Implementing double-dispatch 

/**
 * By hypothesis, there is a working class with
 * methods taking a supertype and subtypes. 
 * The goal of double-dispatch is to execute the
 * subtype method rather than the supertype 
 * method selected when the compile-time
 * reference is of the super's type.
 */
class Worker {
    void run(SuperType t) {}
    void run(SubTypeOne t) {}
    void run(SubTypeTwo t) {}
}

class SuperType {}
class SubTypeOne extends SuperType {}
class SubTypeTwo extends SuperType {}

/** Implement double-dispatch for Worker.run(..) */
aspect DoubleDispatchWorker {

    /** 
     * Replace a call to the Worker.run(SuperType)
     * by delegating to a target method.  
     * Each target subtype in this method dispatches back 
     * to the subtype-specific Worker.run(SubType..) method,
     * to implement double-dispatch.
     */
    void around (Worker worker, SuperType targ):
           !withincode(void SuperType.doWorkerRun(Worker)) &&
            target (worker) && call (void run(SuperType)) &&
            args (targ) {
        targ.doWorkerRun(worker);
    }

    void SuperType.doWorkerRun(Worker worker) {
        worker.run(this);
    }

    // these could be in separate aspects
    void SubTypeOne.doWorkerRun(Worker worker) {
        worker.run(this);
    }
    void SubTypeTwo.doWorkerRun(Worker worker) {
        worker.run(this);
    }
}

// END-SAMPLE language-doubleDispatch