cocoon-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Daniel Fagerstrom <dani...@nada.kth.se>
Subject Re: [RT] composition vs. inheritance in blocks
Date Wed, 30 Mar 2005 22:46:02 GMT
Stefano Mazzocchi wrote:
> Daniel Fagerstrom wrote:
> 
> [snip]
> 
>> Can you describe how you would prefer to adress the "building a webapp 
>> from several blocks" scenario that I described above.
> 
> 
> Daniel, you are asking for two things:
> 
>  1) the existence of a super() equivalence in the block protocol
>  2) the introduction of multiple inheritance of block implementations
> 
> the first is harmless and while I have never thought about needing it, I 
> don't see how it could harm us, so I would not be against introducing it 
> it. So, if Block A extends Block B, calling
> 
>  block:super://blah.xml
> 
> from Block A would yield the call to 'blah.xml' in Block B. Does this 
> satisfy your needs?

No, you still don't get it. Super can certainly be useful in some cases 
but that's not what I'm talking about. Lets just forget about the 
multiplicity of the inheritance or even the term inheritance until we at 
least are discussing the same subject.

Ok, I'll give you a new example trying to explain the concept. Let's 
start with the portal block and say that I want to use that for my app, 
MyPortal, but I want a different skin. The skin consists of the 
stylesheet "styles/portal-page.xsl" among other things. We assume that 
the designer of the portal block wanted to make the skin overridable so 
there is a sitemap rule that exposes the stylesheet in the Portal block.

<match pattern="styles/portal-page.xsl">
   <read src="default-portal-page.xsl"/>
</match>

Now I let MyPortal extends Portal and reimplements the stylesheet in 
MyPortal

<match pattern="styles/portal-page.xsl">
   <read src="my-portal-page.xsl"/>
</match>

and thanks to polymorphism the user of MyPortal will get 
"my-portal-page.xsl" when asking for "styles/portal-page.xsl" and 
everything else will be delivered from Portal.

But is that what we want? Taking a closer look at the sitemap in Portal 
there are a number of sitemap rules that uses "styles/portal-page.xsl" 
for creating other resources: "portal", "loggedin" and 
"resources/login-error.xml". What about them, should they use the the 
stylesheet from Portal or from MyPortal? In general it depends, but in 
this case our aim was to change to our on skin for the portal so we 
should use it everywhere.

This is also covered by the polymorphism concept from OO. A service that 
is defined and used in the base block but overridden in the extending 
block should use the overriding service in the base block as well. But 
IMO it could be confusing if the default behaviour would be to have 
polymorphic lookup as default in blocks and because of that I proposed a 
block:polymorph subprotocol for being explicit about what service 
accesses in a (base) block that are supposed to be overridable. So in 
the Portal block we could have a sitemap rule:

<match pattern="portal">
   ...
   <transform src="block:polymorph:/styles/portal-page.xsl"/>
   ...
</match>

if we access "portal" from the MyPortal block and have overrided 
"styles/portal-page.xsl" in MyPortal, the version from MyPortal will be 
used instead.

                       --- o0o ---

So we have two aspects of polymorphism, the first is that services from 
an extending block overides services in an extended block. But also that 
  services that are used as *part* of other services in the extended 
block will be overrided by corresponding services in the extending block.

So, my main message is that I want this second aspect of polymorphism in 
blocks as well. IMO (and experience) it makes blocks much more useful. A 
block can contain overridable default values and example data so that it 
can be used at once, then the user can override one thing at a time 
during development. I gave an example of how one can work by using this 
aspect of polymorphism in my last mail.

                       --- o0o ---

So what I'm proposing is that we should have this kind of polymorphism 
in block. Or if anyone have a better mechanism that solves the same problem.

> [and no, let's not go over the super(2) to indicate the case where there 
> is more than one layer of inheritance! that's FS!]
Don't worry, I don't like deep inheritance hierarchies.


>                                   - o -
> 
> As for MI, like I said before (and you carefully snipped),
Funny that you comment my snipping, in a mail where you snipped away 
everything but two lines from my mail.

> MI makes it 
> *easier* to glue pieces together that were not designed to be reused, 
> while composition, since it forces you to define a behavioral interface 
> for every exposed service, will very likely slow you down (yes! this is 
> true! it's a feature not a bug) but will make you think about how to 
> design those services.... A by product of this is that your services are 
> instantanously more reusable and the contracts between components are 
> more solid, and SoC/polymorphism much more effective (the size of the 
> cocoon distribution proves my point).

I read it before and didn't comment because 1) I don't agree 2) IMO we 
waste time by discussing sweeping analogues. If we want to get any 
closer to real blocks we need to discuss concrete cases.

> So, instead of multiply inherit a bunch of blocks, you have to define a 
> behavioral interface for every block (which is a URI at the end, not 
> such a big deal) and indicate that you "require" the use of a block that 
> implements that functionality.
> 
> So, instead of what you are proposing:
> 
>  A -(extends)-> B
>  A -(extends)-> C

No I don't. If you read my answer to Peter you could see that I even 
start to doubt that it is meaningful to state that a block extends 
another at some global level. I'm interested in being able to use, and 
in some cases use and override services from several other blocks.

> 
> I proposed to do:
> 
>  A -(requires)-> 1 <-(implements) B
>  A -(requires)-> 2 <-(implements) C
> 
> (where letters are implementations and numbers are interfaces), and if 
> you need to extend B and C to provide a slightly different 
> functionality, then you would have something like
> 
>  A -(requires)-> 1 <-(implements)- B2 -(extends)-> B
>  A -(requires)-> 2 <-(implements)- C2 -(extends)-> C
> 
> or fragmented in statements
> 
>  A -(requires)-> 1
>  A -(requires)-> 2
>  B -(implements)-> 1
>  C -(implements)-> 2
>  B2 -(extends)-> B
>  C2 -(extends)-> C
> 
> where you could have 'default' statements that say
> 
>  A -(prefers)-> B2
>  A -(prefers)-> C2
> 
> and the block manager would reason on the above graph and infer that 
> it's sane and that
> 
>  A -(connects to)-> B2
>  A -(connects to)-> C2
> 
> which achieves the same exact functional effect as MI, but with more 
> explicit contracts.

It's OK for me as long as A and B2 (or C2) can have the kind of 
polymorph connection that I described innthe beginning.

Also I would appriciate if you could replace the letters and the numbers 
above with something more concrete, and if you could flesh out some 
details about how they actually are going to communicate. Before that it 
is rather hard to compare our different approaches or even know if it is 
different rather than complementing approaches. And above all it is hard 
to get to the point where we can start to actually implement it.

/Daniel


Mime
View raw message