This is the mail archive of the guile@cygnus.com mailing list for the guile project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
>>>>> "Per" == Per Bothner <bothner@cygnus.com> writes: ``This letter is longer than usual because I lack the time to make it short.'' -- Pascal Per> I have no CLOS experience. But I won't let that stop me from Per> expressing my opinion ... Oh, dear. :) Per> * The method precedence order is arbitrary, and (supposedly) Per> "wrong". You appear to have come by this through hearsay, and that makes it somewhat difficult for me to address it, but I'll try. There's only one thing where the precedence order could really be ``wrong'', and that works most of the time. The topological sort that CLOS does degrades nicely into the traditional precedence order in the case of single inheritance or single dispatch. The topological sort even works fairly well for most method calls. It occasionally falls down in borderline cases involving semi-large multimethod grids; I can furnish an example if necessary with three classes but it's somewhat contrived. Rather than force you to choose which method to use, CLOS defines a tie breaking algorithm. Urs Hölzle once pointed out the problem with this to me, mentioning that the Self system he used to work on had a similar problem and that the default tie breaking criteria was so arbitrary that the system implementors themselves were regularly surprised by its behavior. They couldn't change to something else because *any* tie breaking criteria would be similarly arbitrary. Eventually the tie breaking stuff was removed completely, replaced with a signalled error; and there was much rejoicing. I believe a similar `fix' would be appropriate for this proposed object system. Per> * I'm not convinced that multi-methods are worth it. They Per> are more difficult to implement efficiently, they make it Per> more difficult to figure out what is going on, they remove Per> the modularity advantage that conventional object-oriented Per> languages have (that methods are associated with their Per> classes). Technically, it is not too difficult to ensure that the multimethod implementation incurs no penalties for single dispatching and is reasonably fast in the presence of multiple dispatch; PCL manages this, and I think TICLOS does, too. There's a small body of papers on how to reduce multiple dispatch to something like single dispatch that are usually targeted for CLOS and Cecil implementors: if there's enough interest, I can probably dig up the papers I have. Multimethods are not as conceptually difficult as you say you are *if* you treat them as language elements in their own right and not as bags on the side of some class. They are magnificent for navigating hierarchies and CL's generic functions have many useful properties that `methods' do not, but if you insist on treating them like they're methods in Smalltalk (for example, by assuming they have to be associated with anything) and then try to get away with things that you can't do in Smalltalk (for example, define multiple dispatch) you can get burned. As for your modularity argument, you're still thinking of generic functions as belonging to some class. It is no trouble at all for me to restrict access to generic functions through a package/module system; given that most module systems are more thorough than CL's package system and it's a breeze even there, I don't see the problem. If you change the focus from `do this to this object' to `do this operation on these things' then it becomes much easier conceptually. There's nothing really for this. You can program in a `traditional' object oriented style in CLOS, and it's not hard, although you lose a lot; there's no sense in restricting the system for those of us who want the extra flexibility if there's little or no cost for it. Per> * I'm nervous about a "mostly-functional" language whose Per> semantics depend so much on global state and side-effects. What, the MOP? Or inserting the MOP into Scheme? I'll grant that parts of the current MOP aren't terribly functional, but a great deal of that reflects that it was designed for Common Lisp, which has a strange position in the whole functional/procedural debates. I would argue that parts of the dispatching and whatnot would be somewhat procedural, but this is an artifact of the techniques used to make it fast and doesn't mean it can't be conceptually pure. Essentially, the magic that underlies ensure-class is there because of what CL is, and turning it into a more Schemey protocol isn't conceptually difficult. You might have to rethink how slot accessors work, but it's not *hard*, and because CLOS is so tied to CL a certain amount of transformation before it'll play nice with Scheme is inevitable. Heck, most of the work is done for you; make-instance *will* create instances of anonymous classes if you gag it with enough data! Per> * I'm concerned that efficient compilation and static Per> analysis seem to be difficult. This I see as a very legitimate criticism. CLOS was never designed to be statically analyzed and indeed except in simple circumstances it is extremely difficult to statically analyze it. The MOP was careful to flag some changes as particularly expensive, but it is still somewhat expensive; a classic features/performance tradeoff. Now, a few things (largely derived from the Self system, also an extremely dynamic and generally compiler unfriendly environment) off the top of my head could help a whole lot: customization[0], done judiciously, could allow us to inline a lot of MOP calls; a simple type flow analysis program (again, like in Self) could pick up a lot of the rest; and heavy inlining could make it quite reasonable when all is said and done. However, this is all pretty hairy stuff, and I would question whether it is under guile's purview. Certainly we could make it fast enough. I.e. with a fair amount of effort and some time I could probably make *a* Scheme with this proposed object model run real fast (like, 2x C code speeds, maybe better); I'm not sure if I can make *this* Scheme run that fast, and I'm not sure if it really matters all that much. One caveat with all this: that you *can* implement CLOS well doesn't mean that you have to. CMUCL, for example, still relies on PCL last I checked, and PCL is somewhat portable but dog slow even in the case of single dispatching. Per> --Per Bothner Cygnus Solutions bothner@cygnus.com Per> http://www.cygnus.com/~bothner [0] Customization in Self involves recompiling methods from a superclass for each subclass so that the method benefits from exact knowledge about the type of `self' (analogous to `this' in C++ code). This allows us to do much inlining of methods to self, and various other optimization steps allow methods to be inlined almost into oblivion; <int> max: <int> can, I believe, be reduced to two branches and one return while still allowing <int> max: <float> to work. To make this less space explosive we only customize methods (and indeed, only compile methods) when they are called for the first time. In a sense, Self had a better JIT than most implementations for Java do now *before* Java came on the scene. I believe the new HotSpot stuff *finally* is getting around to incorporating this. Two steps forward, one step back. -- Graham Hughes <ghughes@cs.ucsb.edu> PGP Fingerprint: 36 15 AD 83 6D 2F D8 DE EC 87 86 8A A2 79 E7 E6