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



Reply via email to