summaryrefslogtreecommitdiffstats
path: root/doc/next.n
blob: a312764149a2cb5743ff7a0a5f47c6931c7621fa (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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
'\"
'\" Copyright (c) 2007 Donal K. Fellows
'\"
'\" See the file "license.terms" for information on usage and redistribution
'\" of this file, and for a DISCLAIMER OF ALL WARRANTIES.
'\"
'\" RCS: @(#) $Id: next.n,v 1.1 2008/05/31 11:42:13 dkf Exp $
'\"
.so man.macros
.TH next n 0.1 TclOO "TclOO Commands"
.BS
'\" Note:  do not modify the .SH NAME line immediately below!
.SH NAME
next \- invoke superclass method implementations
.SH SYNOPSIS
.nf
package require TclOO

\fBnext\fR ?\fIarg ...\fR?
.fi
.BE

.SH DESCRIPTION
.PP
The \fBnext\fR command is used to call implementations of a method by a class,
superclass or mixin that are overridden by the current method. It can only be
used from within a method. It is also used within filters to indicate the
point where a filter calls the actual implementation (the filter may decide to
not go along the chain, and may process the results of going along the chain
of methods as it chooses). The result of the \fBnext\fR command is the result
of the next method in the method chain; if there are no further methods in the
method chain, the result of \fBnext\fR is the empty string. The arguments,
\fIarg\fR, to \fBnext\fR are the arguments to pass to the next method in the
chain.
.SH "THE METHOD CHAIN"
.PP
When a method of an object is invoked, things happen in several stages:
.IP [1]
The structure of the object, its class, superclasses, filters, and mixins, are
examined to build a \fImethod chain\fR, which contains a list of method
implementations to invoke.
.IP [2]
The first method implementation on the chain is invoked.
.IP [3]
If that method implementation invokes the \fBnext\fR command, the next method
implementation is invoked (with its arguments being those that were passed to
\fBnext\fR).
.IP [4]
The result from the overall method call is the result from the outermost
method implementation; inner method implementations return their results
through \fBnext\fR.
.IP [5]
The method chain is cached for future use.
.SS "METHOD SEARCH ORDER"
.PP
When constructing the method chain, method implementations are searched for in
the following order:
.IP [1]
In the object.
.IP [2]
In the classes mixed into the object, in class traversal order. The list of
mixins is checked in natural order.
.IP [3]
In the classes mixed into the classes of the object, with sources of mixing in
being searched in class traversal order. Within each class, the list of mixins
is processed in natural order.
.IP [4]
In the object's class.
.IP [5]
In the superclasses of the class, following each superclass in a depth-first
fashion in the natural order of the superclass list.
.PP
Any particular method implementation always comes as \fIlate\fR in the
resulting list of implementations as possible.
.SS FILTERS
.PP
When an object has a list of filter names set upon it, or is an instance of a
class (or has mixed in a class) that has a list of filter names set upon it,
before every invokation of any method the filters are processed. Filter
implementations are found in class traversal order, as are the lists of filter
names (each of which is traversed in natural list order). Explicitly invoking
a method used as a filter will cause that method to be invoked twice, once as
a filter and once as a normal method.
.PP
Each filter should decide for itself whether to permit the execution to go
forward to the proper implementation of the method (which it does by invoking
the \fBnext\fR command as filters are inserted into the front of the method
call chain) and is responsible for returning the result of \fBnext\fR.
.PP
Filters are not invoked when processing an invokation of the \fBunknown\fR
method because of a failure to locate a method implementation, or when
invoking either constructors or destructors.
.SH EXAMPLES
.PP
This example demonstrates how to use the \fBnext\fR command to call the
(super)class's implementation of a method. The script:
.CS
oo::class create theSuperclass {
    method example {args} {
        puts "in the superclass, args = $args"
    }
}
oo::class create theSubclass {
    superclass theSuperclass
    method example {args} {
        puts "before chaining from subclass, args = $args"
        \fBnext\fR a {*}$args b
        \fBnext\fR pureSynthesis
        puts "after chaining from subclass"
    }
}
theSubclass create obj
oo::define obj method example args {
    puts "per-object method, args = $args"
    \fBnext\fR x {*}$args y
    \fBnext\fR
}
obj example 1 2 3
.CE
prints the following:
.CS
per-object method, args = 1 2 3
before chaining from subclass, args = x 1 2 3 y
in the superclass, args = a x 1 2 3 y b
in the superclass, args = pureSynthesis
after chaining from subclass
before chaining from subclass, args = 
in the superclass, args = a b
in the superclassm args = pureSynthesis
after chaining from subclass
.CE
.PP
This example demonstrates how to build a simple cache class that applies
memoization to all the method calls of the objects it is mixed into, and shows
how it can make a difference to computation times:
.PP
.CS
oo::class create cache {
    filter Memoize
    method Memoize args {
        \fI# Do not filter the core method implementations\fR
        if {[lindex [self target] 0] eq "::oo::object"} {
            return [\fBnext\fR {*}$args]
        }

        \fI# Check if the value is already in the cache\fR
        my variable ValueCache
        set key [self target],$args
        if {[info exist ValueCache($key)]} {
            return $ValueCache($key)
        }

        \fI# Compute value, insert into cache, and return it\fR
        return [set ValueCache($key) [\fBnext\fR {*}$args]]
    }
    method flushCache {} {
        my variable ValueCache
        unset ValueCache
        \fI# Skip the cacheing\fR
        return -level 2 ""
    }
}

oo::object create demo
oo::define demo {
    mixin cache
    method compute {a b c} {
        after 3000 \fI;# Simulate deep thought\fR
        return [expr {$a + $b * $c}]
    }
    method compute2 {a b c} {
        after 3000 \fI;# Simulate deep thought\fR
        return [expr {$a * $b + $c}]
    }
}

puts [demo compute  1 2 3]      \fI\(-> prints "7" after delay\fR
puts [demo compute2 4 5 6]      \fI\(-> prints "26" after delay\fR
puts [demo compute  1 2 3]      \fI\(-> prints "7" instantly\fR
puts [demo compute2 4 5 6]      \fI\(-> prints "26" instantly\fR
puts [demo compute  4 5 6]      \fI\(-> prints "34" after delay\fR
puts [demo compute  4 5 6]      \fI\(-> prints "34" instantly\fR
puts [demo compute  1 2 3]      \fI\(-> prints "7" instantly\fR
demo flushCache
puts [demo compute  1 2 3]      \fI\(-> prints "7" after delay\fR
.CE
.SH "SEE ALSO"
oo::class(n), oo::define(n), oo::object(n), self(n)
.SH KEYWORDS
call, method, method chain

.\" Local variables:
.\" mode: nroff
.\" fill-column: 78
.\" End: