1 | |
---|
2 | Below is a DRAFT e-mail that I intend to send to the mailing list, |
---|
3 | however, having it in the repository (probably rephrased) is better |
---|
4 | long-term documentation. |
---|
5 | |
---|
6 | |
---|
7 | |
---|
8 | Over the past days, I've been working on porting SBCL's D-M-C tests to ABCL's |
---|
9 | test suite and testing+fixing our implementation. A number of use-cases have |
---|
10 | been fixed, however, I'm now down to the more complex cases, in particular |
---|
11 | the case for the (:arguments . lambda-list). |
---|
12 | |
---|
13 | |
---|
14 | Context |
---|
15 | ----------- |
---|
16 | |
---|
17 | When handling EMF computation, there are two sets of arguments (lambda lists): |
---|
18 | |
---|
19 | 1. the arguments passed to the METHOD-COMBINATION through the |
---|
20 | (:method-combination ...) form in the generic function definition |
---|
21 | 2. the arguments passed to the generic function when it is being called |
---|
22 | |
---|
23 | This distinction is very important, yet not particularly clear from our |
---|
24 | sources. The former set of arguments is available from the instantiation of |
---|
25 | the generic function (DEFGENERIC evaluation) and constant throughout the life |
---|
26 | of the GF. The latter is set of arguments is not available until the function |
---|
27 | is being called and will presumably be different for each invocation of the GF. |
---|
28 | |
---|
29 | The former set is passed to the D-M-C form in the second position: |
---|
30 | (D-M-C <name> <arguments> ....). The latter set is made accessible by |
---|
31 | providing the (:arguments ...) form to the D-M-C form -- binding of the |
---|
32 | variables happens at "EMF-calculation-time". |
---|
33 | |
---|
34 | Current implementation |
---|
35 | --------------------------------- |
---|
36 | |
---|
37 | Our existing implementation does not work at all with the (:arguments ...) |
---|
38 | option in the D-M-C definition. [SBCL didn't either, btw, |
---|
39 | until 0.7.<something>] |
---|
40 | What happens in our implementation is that the function |
---|
41 | STD-COMPUTE-EFFECTIVE-METHOD-FUNCTION calls a function created by the D-M-C. |
---|
42 | That function returns forms to be used as the EMF. S-C-E-M-F wraps the returned |
---|
43 | forms in a function and returns it as the EMF. |
---|
44 | |
---|
45 | This works as long as the EMF does not depend on the arguments supplied |
---|
46 | to the GF (generic function) call. |
---|
47 | |
---|
48 | |
---|
49 | The problem |
---|
50 | ------------------ |
---|
51 | |
---|
52 | Our implementation tries to access the function call parameters (resulting |
---|
53 | in "unbound variable errors") from the EMF-generating function. However, |
---|
54 | that function won't (ever) be passed the call arguments. |
---|
55 | |
---|
56 | |
---|
57 | The solution |
---|
58 | ----------------- |
---|
59 | |
---|
60 | Writing down the above and taking into account that we want to cache as much |
---|
61 | of our EMF as possible for performance reasons as well as considering that |
---|
62 | the EMF depending on the function call arguments can't be cached, I think |
---|
63 | this is the solution: |
---|
64 | |
---|
65 | The forms being returned (and later wrapped in a lambda) should include code |
---|
66 | which does another code-generation step --with access to the call parameters-- |
---|
67 | and include a call to the forms having been generated. |
---|
68 | |
---|
69 | Examples |
---|
70 | -------------- |
---|
71 | |
---|
72 | A call to the EMF-generating function which does not depend on the call |
---|
73 | arguments would return something like: |
---|
74 | |
---|
75 | '(CALL-METHOD (MAKE-METHOD (error "ABC 123"))) |
---|
76 | |
---|
77 | This form will be wrapped in a lambda roughly like this: |
---|
78 | (lambda (args) (macrolet ((call-method ...)) <forms>)) |
---|
79 | |
---|
80 | |
---|
81 | A call to the EMF-generating function which *does* depend on the arguments |
---|
82 | would return something like: |
---|
83 | |
---|