Return-Path: Delivered-To: apmail-cocoon-dev-archive@www.apache.org Received: (qmail 26800 invoked from network); 30 Mar 2005 10:51:46 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 30 Mar 2005 10:51:46 -0000 Received: (qmail 57336 invoked by uid 500); 30 Mar 2005 10:51:44 -0000 Delivered-To: apmail-cocoon-dev-archive@cocoon.apache.org Received: (qmail 56821 invoked by uid 500); 30 Mar 2005 10:51:42 -0000 Mailing-List: contact dev-help@cocoon.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: dev@cocoon.apache.org Delivered-To: mailing list dev@cocoon.apache.org Received: (qmail 56804 invoked by uid 99); 30 Mar 2005 10:51:42 -0000 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: pass (hermes.apache.org: local policy) Received: from essemtepe.nada.kth.se (HELO smtp.nada.kth.se) (130.237.222.115) by apache.org (qpsmtpd/0.28) with ESMTP; Wed, 30 Mar 2005 02:51:40 -0800 X-Authentication-Info: The sender was authenticated as danielf using PLAIN at smtp.nada.kth.se Received: from [130.237.218.93] (cvap80.nada.kth.se [130.237.218.93]) (authenticated bits=0) by smtp.nada.kth.se (8.12.11/8.12.11) with ESMTP id j2UApZIx003985 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Wed, 30 Mar 2005 12:51:36 +0200 (MEST) Message-ID: <424A84B7.1000008@nada.kth.se> Date: Wed, 30 Mar 2005 12:51:35 +0200 From: Daniel Fagerstrom User-Agent: Mozilla Thunderbird 1.0 (X11/20041206) X-Accept-Language: en-us, en MIME-Version: 1.0 To: dev@cocoon.apache.org Subject: Re: [RT] composition vs. inheritance in blocks References: <42444CFF.4020807@yahoo.de> <42446062.8000404@nada.kth.se> <424529B7.2020409@yahoo.de> <4245512C.3000107@nada.kth.se> <4248F241.2050503@apache.org> <4249437A.80600@nada.kth.se> <424980CB.4030708@apache.org> <42499D1D.6000104@nada.kth.se> <4249ED2C.8060408@apache.org> In-Reply-To: <4249ED2C.8060408@apache.org> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Stefano Mazzocchi wrote: > Daniel Fagerstrom wrote: > >> Stefano Mazzocchi wrote: >> >>> Daniel Fagerstrom wrote: >> >> >> >>> I don't like multiple inheritance and this is not just because I >>> learned OOP thru java, but because every single time I wish I had >>> multiple implementation inheritance in java I found a way to go >>> around the problem with single implementation inheritance that was >>> more elegant. >> >> I learned OOP thru C++, so I even have had the possibility of using >> multiple implementation inheritance, not just the work arounds ;) And >> in most cases composition is better than multiple implementation >> inheritance, but in the cases where you merge two different concern >> areas it is useful and natural according to my experience. While I >> don't find the "extend the largest abstract base class and repeat the >> interface and delgate to the other" ideom used in Java particulary >> elegant. >> >> But, although I believe that we should use well known concepts from >> OO as much as possible in the design of blocks, as we know some of >> the consequnces of them and as they are familiar to the users, we >> must be aware about that blocks and typical objects have quite >> different levels of granularity and are not completely analogous. >> >> --- o0o --- >> >> So what I propose is that "extend and override" is a convenient and >> productive way to build webapps. You start from a working default >> application and add your own data and modify the behaviours that you >> need to modify. If you have used Forrest, you know what I'm talking >> about. But the difference between Forrest and what I propose is that >> you don't need any complicated sitemap tricks and global >> configurations with search paths, if we makes the block polymorphic. >> >> --- o0o --- >> >> This is not just armchair speculations from me. We have built a >> number of webapps during the last year based on sitemap polymorphism. >> The mechanism is rather simple, in the sitemap of the base >> application we use a variant of the cocoon protocol: >> >> cocoon:polymorph:/foo.xml >> >> that basically calls >> >> cocoon:///foo.xml >> >> by mounting the base application in the end of the "extending" >> sitemap, the polymorph sitemap rules can be overrided just by >> defining the uri in the before the mount. >> >> Its easy and works well. Of course one have to do some thinking to >> build a reusable base application, but that goes generally for >> reusability. >> >> We started to use this pattern because we had a webapp, that a number >> of customers wanted slight variations of. In the beging we just made >> the new webapps extend a slight abstraction of the original webapp. >> Not because I thought it was a good idea, but more because of time >> constraints. Our experience is, hardly supprising, that it is more >> flexible to base your webapp on a number of orthogonal vertical >> frameworks. So we have factored out some such from the original webapp. >> >> --- o0o --- >> >> So our experience is: >> * extend and override is productive >> * vertical frameworks are easier to reuse > > > If you are talking about > > block A extends block B > > then the functionality that you describe above is already included in > the original real block design and you don't even need the (ugly!) > polymorphic protocol flavor, since the block protocol should takes > care of all this transparently (thru the block dependency map of the > block manager). Citing from http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111209768003970&w=2 >In your example block A extends block B, then in block B we can have a >sitemap rule like: > > > > > > > >The block:polymorphism makes that stylesheets/document2html.xslt is >taken from A rather than B. Say that you use that stylesheet in several >rules, then you change multiple behaviours by overriding it. > > I described why I think its safer to be explicit about when an (extended) block should find a service by polymorphic rather than local lookup in http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=111183895029727&w=2: >Ok, allready discussed that above. I think we need to be more explicit >about what behaviour we want. If we just write: > > > >that means normally the same as: > > > >and I don't think it is a good idea for isolation between block to be >able to overide what is in the current context, only things that are >exposed through the sitemap should IMO be overidable: > >. > > So I talk about polymorphic access *whithin* a possibly extended block. I'm fully aware that you described how A can override B by exposing an uri that is exposed in B, and I agree with the proposed mechanism. Question is how to handle the use of a service within the extended block (B) if this service is overriden i the extending block (A). > But (as usual), you jumped directly from that to > > block A extends block b *and* c I wrote: > Our experience is, hardly supprising, that it is more flexible to base > your webapp on a number of orthogonal vertical frameworks. So we have > factored out some such from the original webapp. on the line before my conclusion, and also described why I wanted it earlier in the thread, but (as usual) you jumped in and started screaming without bothering to read the whole thread. > which, to me, is not the painless jump that you (and Peter) seem to > suggest. As already said, I have practical experience of using multiple inheritance in C++ and poymorphic extensions of sitemaps in Cocoon. And, like any other powerful construct, you have to learn how to use it and it can be missused, but in my experience, it simplifies life if you use it in the right way. A coleauge of mine was involved in building some rather large systems in Common Lisp long time ago, and used multiple (implementation) inheritance as one of the major ways to compose the systems. Hi find the single inheriatnce idea in Java ridiculous, and claims that he was about a magnitude more productive when he programmed in Common Lisp rather than in Java. Now comparing langauges is rather unproductive, I just wanted to point out that multiple inheritance not is bad per se, it all depends on what you use it for and how it is implemented in the particular language. >> This implies AFAICS multiple inheritance > > not at all. you can have block 'cascading'/'wrapping' (you name it) > without multiple inheritance. Sure, but if you want to base your webapp on several blocks that takes care of different concerns you have to chose which of them you want to be able to extend if you have single inheritance. --- o0o --- But let's take a look at an example instead. We have built a number of webapps for administring sells campaigns for a number of companies within the same concern that are based on the polymorphic sitemap inheritance scheme that I described above. The webapps have functionality for administring the campaigns (of course), functionality for selecting and optimizing what customers to communicate with, documentation of how it works and about data models, visualization of the results of the campaigns, it communicates with some other systems, database administration functionality that we use internally etc. Ok, when building a new system like this I start with a sitemap like: ... ... By typing "index.html" in my browser I get the default start page from "/block/skin", its a little bit like the default start page from Forrest: menu, menubar, bread crumb, short description about how to continue the development in the main page, etc. First step is puting the other functionality in the menu, so I write an own "site.xml" that overides the polymorphically used in skin: ... whithin skin "site.xml" is used through "block:polymorph:/site.xml" and the overriding version will be used instead. Now my application have menu links to the default implementation of the other blocks (that may contain own manu definitions). I continue by overiding the uris to some of the icons, the start page, some css rules and maybe a "setting.xml" that describe some of the texts etc in the skin. Now I have customized how the application looks, start page an the top menu structure. Next, probably after having created sub sitemaps for campaign, doc etc, I start to customize the parts of my webapp, by overriding some default behaviour in campaign, doc etc. I override the default (example) db meta description for my particular campaign database, change some of the adm forms etc. I use the same db meta description to my doc "block" as well for geting various data views: table overview and a connection diagram. For more general use we should of course factor out the db documentation to a separate dbdoc block, but all our webapps are db based so we haven't found it worthwhile yet. --- o0o --- The important thing here is that my "blocks" are useable as is with example or default data, so that you just can mount them and test them. Then the things that are designed to be overidden is used through the "block:polymorph" protocol and can be overiding by puting a rule before the mount in the mounting sitemap. To make this way of building webapps as simple and convenient as possible it is of course important to have common formats and design conventions between the block. And to focus the blocks so that they do one thing good instead of doing a little bit of everything. Also most of the blocks: systemadm, campaign and doc above should be "content" blocks and let the skin take care of view aspects. If the blocks doesn't use the same formats things get more complicated, but it is still possible to handle. Say that "campaign" and "doc" uses different db description formats. Then you could write something like: --- o0o --- So what I want to have in blocks, is this possiblity to extend and override functionality in several blocks. But I don't see any need for leting my "application level" blocks export all the services from the blocks it extend the functionality from. For sitemap services I prefer to explicitly export things with "mount" and for components we could have some similar mechanism as I described in my comment to Peter's mail. >> as you have to implement polymorphism by hand if you use composition. > > > No. Absolutely not. Go back and read all my emails about the block > protocol: the functionality you describe is already there and doesn't > require MI at all. I have read the ones that have links from http://wiki.apache.org/cocoon/Blocks and serched the archives for block discussions numerous times, and haven't found anything that adresses the usage scenario that I described above. If there are other relevant mails that adresses this, please do us all a service and add the links to the Wiki. Can you describe how you would prefer to adress the "building a webapp from several blocks" scenario that I described above. /Daniel