@@ -6,21 +6,17 @@ This document will explain how functions, method definitions, and method tables
6
6
## Method Tables
7
7
8
8
Every function in Julia is a generic function. A generic function is conceptually a single function,
9
- but consists of many definitions, or methods. The methods of a generic function are stored in
10
- a method table. Method tables (type ` MethodTable ` ) are associated with ` TypeName ` s. A ` TypeName `
11
- describes a family of parameterized types. For example ` Complex{Float32} ` and ` Complex{Float64} `
12
- share the same ` Complex ` type name object.
13
-
14
- All objects in Julia are potentially callable, because every object has a type, which in turn
15
- has a ` TypeName ` .
9
+ but consists of many definitions, or methods. The methods of a generic function are stored in a
10
+ method table. There is one global method table (type ` MethodTable ` ) named ` Core.GlobalMethods ` . Any
11
+ default operation on methods (such as calls) uses that table.
16
12
17
13
## [ Function calls] (@id Function-calls)
18
14
19
- Given the call ` f(x, y) ` , the following steps are performed: first, the method cache to use is
20
- accessed as ` typeof(f).name.mt ` . Second, an argument tuple type is formed, ` Tuple{typeof(f), typeof(x), typeof(y)} ` .
21
- Note that the type of the function itself is the first element. This is because the type might
22
- have parameters, and so needs to take part in dispatch . This tuple type is looked up in the method
23
- table .
15
+ Given the call ` f(x, y) ` , the following steps are performed: First, a tuple type is formed,
16
+ ` Tuple{typeof(f), typeof(x), typeof(y)} ` . Note that the type of the function itself is the first
17
+ element. This is because the function itself participates symmetrically in method lookup with the
18
+ other arguments . This tuple type is looked up in the global method table. However, the system can
19
+ then cache the results, so these steps can be skipped later for similar lookups .
24
20
25
21
This dispatch process is performed by ` jl_apply_generic ` , which takes two arguments: a pointer
26
22
to an array of the values ` f ` , ` x ` , and ` y ` , and the number of values (in this case 3).
@@ -49,15 +45,6 @@ jl_value_t *jl_call(jl_function_t *f, jl_value_t **args, int32_t nargs);
49
45
50
46
Given the above dispatch process, conceptually all that is needed to add a new method is (1) a
51
47
tuple type, and (2) code for the body of the method. ` jl_method_def ` implements this operation.
52
- ` jl_method_table_for ` is called to extract the relevant method table from what would be
53
- the type of the first argument. This is much more complicated than the corresponding procedure
54
- during dispatch, since the argument tuple type might be abstract. For example, we can define:
55
-
56
- ``` julia
57
- (:: Union{Foo{Int},Foo{Int8}} )(x) = 0
58
- ```
59
-
60
- which works since all possible matching methods would belong to the same method table.
61
48
62
49
## Creating generic functions
63
50
94
81
95
82
## Constructors
96
83
97
- A constructor call is just a call to a type. The method table for `Type` contains all
98
- constructor definitions. All subtypes of `Type` (`Type`, `UnionAll`, `Union`, and `DataType`)
99
- currently share a method table via special arrangement.
84
+ A constructor call is just a call to a type, to a method defined on `Type{T}`.
100
85
101
86
## Builtins
102
87
@@ -128,18 +113,14 @@ import Markdown
128
113
Markdown. parse
129
114
```
130
115
131
- These are all singleton objects whose types are subtypes of `Builtin`, which is a subtype of
132
- `Function`. Their purpose is to expose entry points in the run time that use the "jlcall" calling
133
- convention:
116
+ These are mostly singleton objects all of whose types are subtypes of `Builtin`, which is a
117
+ subtype of `Function`. Their purpose is to expose entry points in the run time that use the
118
+ "jlcall" calling convention:
134
119
135
120
``` c
136
121
jl_value_t * (jl_value_t* , jl_value_t** , uint32_t)
137
122
```
138
123
139
- The method tables of builtins are empty. Instead, they have a single catch-all method cache entry
140
- (`Tuple{Vararg{Any}}`) whose jlcall fptr points to the correct function. This is kind of a hack
141
- but works reasonably well.
142
-
143
124
## Keyword arguments
144
125
145
126
Keyword arguments work by adding methods to the kwcall function. This function
@@ -228,18 +209,13 @@ sees an argument in the `Function` type hierarchy passed to a slot declared as `
228
209
it behaves as if the `@nospecialize` annotation were applied. This heuristic seems to be extremely
229
210
effective in practice.
230
211
231
- The next issue concerns the structure of method cache hash tables. Empirical studies show that
232
- the vast majority of dynamically-dispatched calls involve one or two arguments. In turn, many
233
- of these cases can be resolved by considering only the first argument. (Aside: proponents of single
234
- dispatch would not be surprised by this at all. However, this argument means "multiple dispatch
235
- is easy to optimize in practice", and that we should therefore use it, *not* "we should use single
236
- dispatch"!) So the method cache uses the type of the first argument as its primary key. Note,
237
- however, that this corresponds to the *second* element of the tuple type for a function call (the
238
- first element being the type of the function itself). Typically, type variation in head position
239
- is extremely low -- indeed, the majority of functions belong to singleton types with no parameters.
240
- However, this is not the case for constructors, where a single method table holds constructors
241
- for every type. Therefore the `Type` method table is special-cased to use the *first* tuple type
242
- element instead of the second.
212
+ The next issue concerns the structure of method tables. Empirical studies show that the vast
213
+ majority of dynamically-dispatched calls involve one or two arguments. In turn, many of these cases
214
+ can be resolved by considering only the first argument. (Aside: proponents of single dispatch would
215
+ not be surprised by this at all. However, this argument means "multiple dispatch is easy to optimize
216
+ in practice", and that we should therefore use it, *not* "we should use single dispatch"!). So the
217
+ method table and cache splits up on the structure based on a left-to-right decision tree so allow
218
+ efficient nearest-neighbor searches.
243
219
244
220
The front end generates type declarations for all closures. Initially, this was implemented by
245
221
generating normal type declarations. However, this produced an extremely large number of constructors,
0 commit comments