More On Multiple Inheritance

Hans-Dieter Dreier Ursula.Dreier@ruhr-uni-bochum.de
Sat, 27 Mar 1999 22:08:55 +0100


--------------8AE1311CE4C3CD298414CCD5
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit



Matthew Tuck schrieb:

> Hans-Dieter Dreier wrote:
>
> >>> If the editor and the source are both objects, with one of them
> >>> acting on the other, anytime is runtime for some part of the system.
> >>> For some objects a compiled version exists (and thus they are
> >>> executable).  Others consist only of source code and a notice that
> >>> says "I need to be compiled before use". Still other objects cannot
> >>> be compiled (a stack, for example).
> >> What would you say the ramifications of this point of view are?
> > Generally speaking, a more interactive environment. See the GUI
> > builder thread for an example involving the editor.
>
> Regarding the editor calling an object for stuff like knowing how to
> display it, how would you handle long-running and nonterminating
> methods?

It should be no problem to edit the source code of a method that is currently
executing. During editing, the reference to the generated code (which is included in
the source object along with the actual source) is detached as soon as a change has
been made. Normally, the code could then be collected. If it is executed however,
there still should be a reference to it (from VM's state or the stack) which
prevents collecting as long as it is executing. If the old version of the source is
kept as well, even debugging would remain possible.

> In a sense incremental compilation can help a lot.  That's why it's nice
> to have a lot of fragility options.  The inter-module optimiser is
> probably going to be the slowest part.  If we do incrementally linking
> however it could help dramatically.  That's going to complicate it of
> course, but it's probably useful.  Although a lot of inter-module
> optimisations won't be possible until the system is closed (we know
> there are not anymore implementations in the system).

How many different implementations will be present (ie loaded) for a type at any
given time?
I'm not so sure whether (typically) this will be more than one.

> > If I do a similar
> > thing on my PC at work (VC++ on 350 MHz PII with 64 MB core) it takes 2
> > minutes to produce a 200 KB DLL. If you do that dozens of times a day,
> > it adds up.
>
> Ahh, but it's an excuse to use Netscape.  =)

What do you mean?

> >> An implementation is the code that obeys a type's interface.  They are
> >> semantically and syntactically different entities.
> > Where do you see a syntactical difference? Why *can't* both be mixed?
> > Maybe they *shouldn't* be mixed, but that is a matter of style. And if
> > they can't be mixed, how do we avoid the overhead of having two
> > entities describing the same thing. Some programmers wouldn't like to
> > first define the interface, then a separate impl. Remember, there are
> > lots of cases where this simply is overkill: Everything that it is
> > intended to be derived from does not need an interface.
>
> Think "shorthand".

How could this look like?

> > I also think we should introduce a notion for the information a
> > compiler needs to actually produce code - namely, is it a reference
> > type, is it a binary type, and if so, how big is it; is it a function,
> > and if, what are its parameters and return  value. The code generator
> > simply needs that. I wouldn't delegate code generation to the linker
> > (especially if we can do without a linker which I believe), and then
> > the linker would need that information too.
>
> You can't do without a "linker" if you have modules.  Even if a linker
> just merges ASTs together, rather than does fixups etc.

OK. Maybe my approach would need a linker too - or actually two of them:A *very*
small one at compile time that does no more than flip some references,
a bigger one that is capable of loading a workspace and merging the name spaces, to
be called when you "include" a workspace. This one would then call the compiler to
generate code for the parts that have been loaded and were depending on parts that
were not included in the loaded package.

> So if code generation is done after linking the code generator may well
> know that information, all that is needed is do some optimisation.  I
> think it's more important to get that extra flexibility and tradeoff a
> bit of compile-time efficiency (which might be reduced with incremental
> compilation) or run-time efficiency.
>
> I've needed the flexibility or get/sets before and most programmers
> probably have too - I think we don't necessarily realise it however
> because we're used to it not being there.  Programmers don't miss a
> feature they've never had.

True, but I'd at least like to be able to avoid the cost if I choose to.

> Many other important language advances are going to need this too, eg
> multiple implementations leading to dynamic dispatch, making arrays an
> implementation of a type rather than a hardcoded feature.  They're all
> going to need optimisation.  It is just the continuation of what was
> begun by information hiding.

Information hiding does not have such a performance hit.

> > > Deriving things like no side effects would require looking at a piece of
> > > code in an impl.  For a start there might be more than one impl to look
> > > at.  Not an insurmountable problem.
> >
> > No problem, actually, since each impl must be compiled before use. It
> > is checked then. Because it inherits from the type, it gets flagged as
> > "need to be compiled" if the type changes significantly (i.e. visibly
> > to the outside world).
>
> Well certain situations make this impossible - impls could be run-time
> loaded/generated/made via prototyping - or delayed - in another module
> that hasn't been linked in yet, etc.

I said "before use". More specifically, I meant "before execution". Of course no
statement can be made at a time when not all neccessary information is present.

> > > But then you might want to subtype the type.  If it was typed as
> > > side-effectless, a subtype would be forced to obey this, which might not
> > > be desired.
> >
> > You'd have to change inheritance relationships then. Subtypes cannot have
> > weaker postconditions. But I see your point. How about having the compiler
> > flag such a condition for information purposes (as a comment), and letting the
> > user choose whether he wants to export the condition (ie activate it for
> > inheritance purposes).
>
> OK, I'm going to go off into object right now, which is my pet topic,
> bear with me.  We consider "side" as the right to perform side effects.
> Other examples of permissions are "read" and "write" for parameters.
> Anyway, the type allows "side" which in turn it grants to its
> implementations.  The implementation may now either be marked "side" or
> not.  If they're specified as side, yet they're side-effect less, we
> might warn at compile-time.

Why this? How can being side-effect less do any harm?

> --
>      Matthew Tuck - Software Developer & All-Round Nice Guy
>

Regards,

Hans-Dieter Dreier


--------------8AE1311CE4C3CD298414CCD5
Content-Type: text/html; charset=us-ascii
Content-Transfer-Encoding: 7bit

<HTML>
&nbsp;

<P>Matthew Tuck schrieb:
<BLOCKQUOTE TYPE=CITE>Hans-Dieter Dreier wrote:

<P>>>> If the editor and the source are both objects, with one of them
<BR>>>> acting on the other, anytime is runtime for some part of the system.
<BR>>>> For some objects a compiled version exists (and thus they are
<BR>>>> executable).&nbsp; Others consist only of source code and a notice
that
<BR>>>> says "I need to be compiled before use". Still other objects cannot
<BR>>>> be compiled (a stack, for example).
<BR>>> What would you say the ramifications of this point of view are?
<BR>> Generally speaking, a more interactive environment. See the GUI
<BR>> builder thread for an example involving the editor.

<P>Regarding the editor calling an object for stuff like knowing how to
<BR>display it, how would you handle long-running and nonterminating
<BR>methods?</BLOCKQUOTE>
It should be no problem to edit the source code of a method that is currently
executing. During editing, the reference to the generated code (which is
included in the source object along with the actual source) is detached
as soon as a change has been made. Normally, the code could then be collected.
If it is executed however, there still should be a reference to it (from
VM's state or the stack) which prevents collecting as long as it is executing.
If the old version of the source is kept as well, even debugging would
remain possible.
<BLOCKQUOTE TYPE=CITE>In a sense incremental compilation can help a lot.&nbsp;
That's why it's nice
<BR>to have a lot of fragility options.&nbsp; The inter-module optimiser
is
<BR>probably going to be the slowest part.&nbsp; If we do incrementally
linking
<BR>however it could help dramatically.&nbsp; That's going to complicate
it of
<BR>course, but it's probably useful.&nbsp; Although a lot of inter-module
<BR>optimisations won't be possible until the system is closed (we know
<BR>there are not anymore implementations in the system).</BLOCKQUOTE>
How many different implementations will be present (ie loaded) for a type
at any given time?
<BR>I'm not so sure whether (typically) this will be more than one.
<BLOCKQUOTE TYPE=CITE>> If I do a similar
<BR>> thing on my PC at work (VC++ on 350 MHz PII with 64 MB core) it takes
2
<BR>> minutes to produce a 200 KB DLL. If you do that dozens of times a
day,
<BR>> it adds up.

<P>Ahh, but it's an excuse to use Netscape.&nbsp; =)</BLOCKQUOTE>
What do you mean?
<BLOCKQUOTE TYPE=CITE>>> An implementation is the code that obeys a type's
interface.&nbsp; They are
<BR>>> semantically and syntactically different entities.
<BR>> Where do you see a syntactical difference? Why *can't* both be mixed?
<BR>> Maybe they *shouldn't* be mixed, but that is a matter of style. And
if
<BR>> they can't be mixed, how do we avoid the overhead of having two
<BR>> entities describing the same thing. Some programmers wouldn't like
to
<BR>> first define the interface, then a separate impl. Remember, there
are
<BR>> lots of cases where this simply is overkill: Everything that it is
<BR>> intended to be derived from does not need an interface.

<P>Think "shorthand".</BLOCKQUOTE>
How could this look like?
<BLOCKQUOTE TYPE=CITE>> I also think we should introduce a notion for the
information a
<BR>> compiler needs to actually produce code - namely, is it a reference
<BR>> type, is it a binary type, and if so, how big is it; is it a function,
<BR>> and if, what are its parameters and return&nbsp; value. The code
generator
<BR>> simply needs that. I wouldn't delegate code generation to the linker
<BR>> (especially if we can do without a linker which I believe), and then
<BR>> the linker would need that information too.

<P>You can't do without a "linker" if you have modules.&nbsp; Even if a
linker
<BR>just merges ASTs together, rather than does fixups etc.</BLOCKQUOTE>
OK. Maybe my approach would need a linker too - or actually two of them:A
*very* small one at compile time that does no more than flip some references,
<BR>a bigger one that is capable of loading a workspace and merging the
name spaces, to be called when you "include" a workspace. This one would
then call the compiler to generate code for the parts that have been loaded
and were depending on parts that were not included in the loaded package.
<BLOCKQUOTE TYPE=CITE>So if code generation is done after linking the code
generator may well
<BR>know that information, all that is needed is do some optimisation.&nbsp;
I
<BR>think it's more important to get that extra flexibility and tradeoff
a
<BR>bit of compile-time efficiency (which might be reduced with incremental
<BR>compilation) or run-time efficiency.

<P>I've needed the flexibility or get/sets before and most programmers
<BR>probably have too - I think we don't necessarily realise it however
<BR>because we're used to it not being there.&nbsp; Programmers don't miss
a
<BR>feature they've never had.</BLOCKQUOTE>
True, but I'd at least like to be able to avoid the cost if I choose to.
<BLOCKQUOTE TYPE=CITE>Many other important language advances are going
to need this too, eg
<BR>multiple implementations leading to dynamic dispatch, making arrays
an
<BR>implementation of a type rather than a hardcoded feature.&nbsp; They're
all
<BR>going to need optimisation.&nbsp; It is just the continuation of what
was
<BR>begun by information hiding.</BLOCKQUOTE>
Information hiding does not have such a performance hit.
<BLOCKQUOTE TYPE=CITE>> > Deriving things like no side effects would require
looking at a piece of
<BR>> > code in an impl.&nbsp; For a start there might be more than one
impl to look
<BR>> > at.&nbsp; Not an insurmountable problem.
<BR>>
<BR>> No problem, actually, since each impl must be compiled before use.
It
<BR>> is checked then. Because it inherits from the type, it gets flagged
as
<BR>> "need to be compiled" if the type changes significantly (i.e. visibly
<BR>> to the outside world).

<P>Well certain situations make this impossible - impls could be run-time
<BR>loaded/generated/made via prototyping - or delayed - in another module
<BR>that hasn't been linked in yet, etc.</BLOCKQUOTE>
I said "before use". More specifically, I meant "before execution". Of
course no statement can be made at a time when not all neccessary information
is present.
<BLOCKQUOTE TYPE=CITE>> > But then you might want to subtype the type.&nbsp;
If it was typed as
<BR>> > side-effectless, a subtype would be forced to obey this, which
might not
<BR>> > be desired.
<BR>>
<BR>> You'd have to change inheritance relationships then. Subtypes cannot
have
<BR>> weaker postconditions. But I see your point. How about having the
compiler
<BR>> flag such a condition for information purposes (as a comment), and
letting the
<BR>> user choose whether he wants to export the condition (ie activate
it for
<BR>> inheritance purposes).

<P>OK, I'm going to go off into object right now, which is my pet topic,
<BR>bear with me.&nbsp; We consider "side" as the right to perform side
effects.
<BR>Other examples of permissions are "read" and "write" for parameters.
<BR>Anyway, the type allows "side" which in turn it grants to its
<BR>implementations.&nbsp; The implementation may now either be marked
"side" or
<BR>not.&nbsp; If they're specified as side, yet they're side-effect less,
we
<BR>might warn at compile-time.</BLOCKQUOTE>
Why this? How can being side-effect less do any harm?
<BLOCKQUOTE TYPE=CITE>--
<BR>&nbsp;&nbsp;&nbsp;&nbsp; Matthew Tuck - Software Developer &amp; All-Round
Nice Guy
<BR><A HREF="http://www.box.net.au/~matty/ultra/"></A>&nbsp;</BLOCKQUOTE>
Regards,

<P>Hans-Dieter Dreier
<BR>&nbsp;</HTML>

--------------8AE1311CE4C3CD298414CCD5--