From: Dmitry A. Kazakov on
On Mon, 12 Nov 2007 00:03:16 +0100, Joachim Durchholz wrote:

> Marshall schrieb:

>> Very interesting. Can you expand on the difficulties that multiple
>> dispatch brings to the question of composable modules?
>
> Assume you have a multi-dispatching function
>
> f (A, B)
>
> Now the author of class A creates a subclass A', and the associated function
>
> f (A', B)
>
> Likewise for the author of B:
>
> f (A, B')
>
> Problems arise if the two authors don't know about each other (or can't
> or don't want to collaborate). Then, combining classes A' and B' in one
> system will lack a definition for
>
> f (A', B')
>
> There are several ways to deal with the situation:
>
> 1) Give priority to one of the parameters (usually the first one). This
> means f (A', B') defaults to f (A', B). This can cause problems if the
> implementations of A' and B' are so different from their respective base
> classes that f (A', B') really would have to be written.
> 2) Force the integrator to write f (A', B'). Extra bonus if he doesn't
> have the sources of A' and B'.
>
> The "nonmodular" bit comes from the observation that A' and B' aren't
> modules anymore: they cannot be added independently, there's an
> interaction between them.

Just to put it in different words...

The problem arises from uncertainty about the freezing points of the type
definitions. A freezing point is the point where the new type becomes first
usable. For instance, after the freezing point one can derive a new type
from the frozen one, declare objects of etc. In C++ the freezing point is
the closing }; of the class definition.

Now, the problem is that the freezing point of A' cannot be determined. It
does not lie in the module where A gets declared, if there exists B'.
Because in that case it shall lie after the declaration of f(A',B'). But B'
is in another module.

Even funnier it becomes with A''. It cannot be declared at all, because
that shall happen before the freezing point of A', which lies nowhere.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Marshall on
On Nov 12, 7:12 am, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
wrote:
>
> The problem arises from uncertainty about the freezing points of the type
> definitions. A freezing point is the point where the new type becomes first
> usable.

Hmmm. This "freezing point" is an interesting concept.
You make explicit what I am used to being implicit. But
now that you've made it explicit, I have to ask: what
good is this concept? Why should we have it? So far
the only thing we've said about it explicitly is that it
causes this problem. So why not ditch the concept?


Marshall

From: Joachim Durchholz on
Marshall schrieb:
> On Nov 12, 7:12 am, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
> wrote:
>> The problem arises from uncertainty about the freezing points of the type
>> definitions. A freezing point is the point where the new type becomes first
>> usable.
>
> Hmmm. This "freezing point" is an interesting concept.
> You make explicit what I am used to being implicit. But
> now that you've made it explicit, I have to ask: what
> good is this concept? Why should we have it? So far
> the only thing we've said about it explicitly is that it
> causes this problem. So why not ditch the concept?

Not having a freezing point means the code remains extensible.
Viz. it remains possible to add subclasses with redefinitions.

Regards,
Jo
From: Joachim Durchholz on
Marshall schrieb:
> On Nov 11, 3:03 pm, Joachim Durchholz <j...(a)durchholz.org> wrote:
>> Marshall schrieb:
>>
>>> Very interesting. Can you expand on the difficulties that multiple
>>> dispatch brings to the question of composable modules?
>> Assume you have a multi-dispatching function
>>
>> f (A, B)
>>
>> Now the author of class A creates a subclass A', and the associated function
>>
>> f (A', B)
>>
>> Likewise for the author of B:
>>
>> f (A, B')
>>
>> Problems arise if the two authors don't know about each other (or can't
>> or don't want to collaborate). Then, combining classes A' and B' in one
>> system will lack a definition for
>>
>> f (A', B')
>
> Okay. This is the same thing as the "expression problem", yes?

I don't know the expression problem, so I can't answer that.

> But it seems to me the situation is actually better with multiple
> dispatch than it is with OOP. Or am I imagining that?

Not sure what you're after. The situation certainly does not involve
mutability, it just assumes that the implementation of f (A', B') could
be different from that of f (A', B) and f (A, B').

Now if
* all types involved are immutable, and
* A' is a true subtype of A and
* B' is a true subtype of B,
then f (A, B) will do just fine for all four combinations of A, A', B,
and B', so the problem does indeed vanish.

I'm not sure that this is what you meant though.

> It seems that again the problem is mutability, not multiple dispatch.
>
> If we are really asserting:
>
> A' <: A
> B' <: B
> the extension of f(A', B) is a subset of the extension of f(A, B)
> the extension of f(A, B') is a subset of the extension of f(A, B)
>
> Then if we have a:A' and b:B', it doesn't matter which one
> of the three f's we call; they all produce the same answer.
>
> However in practical terms, we don't have expressive enough
> languages to capture enough semantics, as you've said I think.

I happen to believe that this is largely true if mutability comes into
play, but I didn't consciously say that :-)

>> There are several ways to deal with the situation:
>>
>> 1) Give priority to one of the parameters (usually the first one). This
>> means f (A', B') defaults to f (A', B). This can cause problems if the
>> implementations of A' and B' are so different from their respective base
>> classes that f (A', B') really would have to be written.
>
> Why must it be written? Efficiency?

No, it can be semantics.

Imagine A' is some variant of A that keeps a file open for some purpose,
and the same for B'.
Also imagine that f (A', B) opens the A file, as does f (A, B') does for
the B file.
Now f (A', B') should open that file, too.

Note that this example is a bit contrived; it's a bit too late for me to
make up something better. I think any behind-the-scene bookkeeping in A'
and B' will suffice to exhibit the problem.

>> The "nonmodular" bit comes from the observation that A' and B' aren't
>> modules anymore: they cannot be added independently, there's an
>> interaction between them.
>
> It appears to me there is only an interaction if the authors of the
> specialized f's have broken the semantics of subtyping, yes?

Not really. Adding some behind-the-scene bookkeeping is perfectly
acceptable for any subclass.

Regards,
Jo
From: Dmitry A. Kazakov on
On Mon, 12 Nov 2007 23:28:10 +0100, Joachim Durchholz wrote:

> Marshall schrieb:
>> On Nov 12, 7:12 am, "Dmitry A. Kazakov" <mail...(a)dmitry-kazakov.de>
>> wrote:
>>> The problem arises from uncertainty about the freezing points of the type
>>> definitions. A freezing point is the point where the new type becomes first
>>> usable.
>>
>> Hmmm. This "freezing point" is an interesting concept.
>> You make explicit what I am used to being implicit. But
>> now that you've made it explicit, I have to ask: what
>> good is this concept? Why should we have it? So far
>> the only thing we've said about it explicitly is that it
>> causes this problem. So why not ditch the concept?
>
> Not having a freezing point means the code remains extensible.
> Viz. it remains possible to add subclasses with redefinitions.

But freezing points shall exist in manifested systems, because there we
cannot use a type before its definition:

-- I cannot use the type T here, it is not declared yet. The
-- freezing point should be somewhere below.

type T is ... -- The type definition starts

-- I don't know if I can use T. Only partial views on T exist here.

<freezing point>

-- Now I can use T

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de