TIP #381: CALL CHAIN INTROSPECTION AND CONTROL ================================================ Version: $Revision: 1.9 $ Author: Donal K. Fellows State: Final Type: Project Tcl-Version: 8.6 Vote: Done Created: Wednesday, 20 October 2010 URL: https://tip.tcl-lang.org381.html Post-History: ------------------------------------------------------------------------- ABSTRACT ========== This TIP proposes mechanisms for inspecting the TclOO call chain for a particular method, both externally via *info* and from within a call to that method. It also proposes a mechanism that will allow the traversal of the call chain in a more controlled way than at present with the *next* command. RATIONALE =========== Experience with TclOO in deployment has shown that the call chain mechanism used for identifying method implementations to bind to a particular method call is not just a powerful system, but also fairly difficult to understand. In particular, there is currently no way to discover what implementations of a method will be actually called, which makes debugging more difficult than it ought to be. In addition, it has been found that it is quite difficult to manage multiple inheritance with TclOO. In particular, when a "diamond" inheritance graph is constructed where the different arms of the graph require different arguments, it is exceptionally difficult to ensure that the correct arguments get delivered to the right constructors, this being a requirement for some of the ways in which people use [incr Tcl] and build megawidgets. Arguably, in these cases it would be perhaps better for code to use delegation as a class composition mechanism, but it is not the place of TclOO to impose such a policy. As such, there needs to be a mechanism to allow more precise runtime control over the traversal of call chain (control over the construction of the chain would not be so useful; there simply is no right order that can ensure that immiscible constructor arguments get passed correctly). PROPOSED CHANGES ================== There will be the the following subcommands of *info* added: *info object call* /objectName methodName/ This will return a list describing the methods used to implement a call to the given /methodName/ on the given /objectName/. It will be an error to call it on anything that is not an object, but in the case that /methodName/ does not describe a (visible) method, the returned list will describe how things are handled by *unknown* processing. Each element of the list will be a tuple. The first element of the tuple will be one of *filter*, *method* and *unknown* to indicate whether it is a filter, a normal method call, or a special method call used to handle unknown methods (i.e., with the method name as an additional argument); the remainder of the tuple's interpretation will depend on which it is. The second element will be the name of the method implementation (always *unknown* in the case of unknown handling, except where that is intercepted by a filter). The third element will be the literal *object* or the fully-qualified name of the class of that provided the implementation of the method or filter (NB: not necessarily the class that enabled the filtering through that name). The fourth element will be the type of the method implementation (i.e., as described by *info object methodtype* or *info class methodtype*, depending on where the method is declared). *info class call* /className methodName/ This will be similar to *info object call*, but will instead describe what would happen with a stereotypical instance of /className/. In addition, there will be an extra subcommand of *self*: *self call* This will return a list of two items, the first being the list that would have been returned by *info object call* for this method call, and the second being an index into the list of the current method (i.e., *0* for the first implementation on the list). Finally, there will be another command made available inside method bodies to provide the advanced chain calling described above: *nextto* /className/ ?/arg .../? This command will behave just like *next* except that it will scan /forward/ in the current method chain until the implementation of the method provided by /className/ is located, and chain to that (while passing in the /arg/uments given, of course). It will be an error to attempt to call a class's implementation of a method that is not on the chain, or that is preceding the currently executing method implementation, and it will not be possible to jump to filters applied to the method. REFERENCE IMPLEMENTATION ========================== See for the proposed implementation (notably commit-f5a2cfd0d4). COPYRIGHT =========== This document has been placed in the public domain. ------------------------------------------------------------------------- TIP AutoGenerator - written by Donal K. Fellows