Path: news.daimi.aau.dk!rws From: rws@daimi.aau.dk (Rene Wenzel Schmidt) Newsgroups: comp.lang.beta Subject: Re: Overriding procedural patterns Date: 11 May 1995 17:43:48 GMT Organization: DAIMI, Computer Science Dept. at Aarhus University Lines: 168 Message-ID: <3otick$s3l@belfort.daimi.aau.dk> References: <3o315c$9he@pulm1.accessone.com> <3odefd$hbp@belfort.daimi.aau.dk> NNTP-Posting-Host: quercus.daimi.aau.dk Thus spake eernst@quercus.daimi.aau.dk (Erik Ernst): > Baiss E. Magnusson writes: >>> I am troubled by the Beta definition that a virtual pattern can only be >>> extended and cannot be completely redefined. The complete over-riding of >>> the enclosing procedure pattern seems to me to be a fundamental need. > ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ > > [stuff deleted] > >I once wrote a proposal for an alternative inheritance mechanism >("weak inheritance") which would allow override semantics whereever >wanted, and which would introduce more flexible method-combination >schemes. Weak inheritance works exactly like normal inheritance wrt >scope rules, enter-lists, and exit-lists. Only the combination of the >do-parts up through the chain of super-patterns is affected. >Nobody (else :-) liked it. Anyway, here is a sketch of it: I think it sounds interesting. However, it does not fit well with the current conceptual framework for developing BETA programs, i.e., that subclassing is specialzing. But the framework can, of course, be changed. I agree that overwritting semantics is really what you want sometimes. In fact, in some places INNER is actually used to implement overridding. Consider the IntegerValue pattern in BetaEnv: IntegerValue: (# value: @integer do INNER exit value #); Example: foo: (# default:< IntegerValue(# do 341->value; INNER #); #); bar: foo (# default<:(# do 143->value; INNER #); (* Overwritting(!) a value *) #) The redundant statement 341->value gets executed each time 'default' pattern is evaluated. Resulting in a performance degradation. An optimizing compiler and inlining of code might prevent this overhead in some situation (but we don't have such a compiler right now). However, separate compilation makes it impossible to do inlining across different source files. > [stuff deleted] > > e: (# 'e'->put; INNER #); > f:! e(# do 'The hen or the '->puttext; OUTER; INNER #); > g: f(# do 'g'->put #); (* Yes, it prints "The hen or the egg"! *) > At first I found it very strange that the g is printed out twice. After thinking about it for a while I actually think that it makes sense ;-) By using the INNER construct you semantically inserts code into another pattern. The OUTER semantically wraps code around another pattern. A macro-expansions of the above code gives: Step 1: (first expand OUTERs from the bottom) f:! e(# do 'The hen or the '-> puttext; 'e'->put; INNER; INNER; #); g: f(# do 'g'->put #); Step 2: (then expand INNERs from the top) g: (# do 'The hen or the '-> puttext; 'e'->put; 'g'->put; 'g'->put; #) (Erik, please correct me if I am wrong) >Think of it this way: >Normal inheritance: Executing the dopart of a pattern means executing >the dopart of its super-pattern with its own dopart as a _callback_ to >execute for each occurrence of "INNER". The most specialized pattern >binds its "INNER" to DO-NOTHING. > >Weak inheritance: Executing the dopart of a pattern means executing >this dopart with "OUTER" bound to the dopart of its super-pattern >which in turn binds its "INNER" to the same as the "INNER" of this >pattern. The most specialized pattern binds its "INNER" to >DO-NOTHING. > >So, intuitively, the meaning of "INNER" is propagated up through all >levels of weak inheritance. > >The basic idea is to provide a general mechanism which is orthogonal >to the other aspects of BETA, reasonably simple to understand and use, >and that makes it possible to do more flexible kinds of method >combination than what is (directly) supported today. > >I also think it should allow for an efficient implementation, even >though it demands some changes compared to the methods used today in >Mjølner BETA. Then again it might help in implementing virtual prefix >and other as-yet-unsupported kinds of inheritance. It is actually straight forward to implement and can also be implemented very efficient. OUTER corresponds to C++'s A::B syntax, so a similar implementation is possible. It is statically know at compile-time what code the OUTER is calling, so a direct jump-subrutine call can be generated. This is in contrast to INNER where an indirect jump is needed. The way INNER dispatch is handled through the INNER dispatch-table does not need to be changed. To illustrate how it works I will use the above Hen/Egg program: Code for e: (no change form current implementation) Me: putCharE jump-subrutine [IDT+0] ; IDP is a register pointing to the return ; INNER dispatch table Code for f: Mf: putString jump-subrutine Me ; OUTER: Jumps directly to code for e jump-subrutine [IDT+1] ; INNER: standard code. The offset is ; 1 because it is the second INNER return Code for g: Mg: putCharG return The virtual-dispatch table for a call of G will have two entries because there is two INNERs. Both of the entries will point to Mg. IDTg: .word Mg .word Mg A call of g will be translated into to: load IDT,IDTg jump-subrutine Mf > .. comments are looked forward to! >-- >Erik Ernst eernst@daimi.aau.dk >Computer Science Department of Aarhus University, Denmark Here are some and they are even positive /Rene --- Rene Wenzel Schmidt Fax: +45 8942 3255 Department of Computer Science Phone: +45 8942 3257 University of Aarhus Email: rws@daimi.aau.dk 8000 Aarhus C, Denmark WWW: http://www.daimi.aau.dk/~rws