[Grace-core] Multiple inheritance & module inheritance

Kim Bruce kim at cs.pomona.edu
Mon Mar 9 11:36:30 PDT 2015


A few thoughts off the top of my head.

Java needs the superclass constructor to execute immediately because there are private fields that the user might not even know about, let alone access.  Thus it is wise to make the initialization come immediately (even when inconvenient).  Because we only have confidential fields, we can see those and make sure they are initialized, even if we run the initialization code from the superclass later.  (Am I missing anything)

I'm always skeptical of multiple inheritance as I've seen so many proposals lead to great complexity.  Ordering things certainly helps (as with traits).  However, the stuff about fields makes me very nervous.  Right now we do not allow a subclass to redeclare an instance variable from the superclass (though we can provide it with a new value).  Why would we allow multiple declarations with multiple inheritance?  Why not just say it is a mistake if two superclasses contain separate declarations of an instance variable.  (Presumably if we have the diamond property with a single declaration at the top of the diamond then we would be OK.)

Speaking of the diamond property, what would the initialization sequence be if B and C both inherit from A and then D inherits from B and C (in that order)?  Running the initialization code for A twice sounds like a bad idea, and yet B and C (separately) might initialize fields to different values.  (Michael's catfish example illustrates some of the difficulties.)

A big concern with making a change of this sort is that we need to think through ALL the consequences very, very carefully, as they typically have lots of subtle impacts.  Thus we definitely need lots of time to consider them.

An important question is which of these do we really NEED?  Our goal is a simple language for novices.  We have some real needs that are not met by the current design, but we should be conservative about extensions.  For example, it seems reasonable to me to do something more like traits (whatever we decide that means -- to me something without instance variables) rather than full blown multiple inheritance.

Kim

P.S.  Some aspects of this proposal remind me of C++ multiple inheritance, increasing my anxiety ...

> On Mar 9, 2015, at 12:25 AM, Michael Homer <mwh at ecs.vuw.ac.nz> wrote:
> 
> This is a proposal to support multiple inheritance.
> 
> Background: in the "fresh objects" design, an inherits
> statement includes a method request, the resulting method of
> which must tail-return an object constructor. A method
> tail-returns an object constructor iff the last element of
> the method body is a (return of) an object constructor.
> That object constructor is executed in the context of the
> existing object identity (the one with the inherits clause
> in it) and the methods defined in all inheriting objects.
> The inherits clause must be the first thing inside the
> object body. (End background)
> 
> This proposal builds on the fresh objects design. In
> particular, any program that is valid in the current design
> continues to function with the same behaviour under this
> proposal.
> 
> This proposal focuses on the dynamic semantics. Additional
> restrictions on behaviour (what can be inherited from and
> how, etc) may be enforced by a dialect.
> 
> Inherits statements
> ===================
> 
> An inherits statement has the form "inherits <REQUEST>",
> where <REQUEST> is any valid method request in the current
> scope.
> 
> The request must be answered by a method whose last element
> is a return of an object constructor, and that constructor
> will be executed in the context of the object identity
> already under construction. Class declarations are syntactic
> sugar for an object having such a method, so "inherits
> dog.aged(3)" is a valid statement.
> 
> A method tail-returning an object constructor continues to
> behave as now.
> 
> Multiple inheritance
> ====================
> 
> Multiple "inherits" statements can appear in a single
> object, executing in order of appearance. A single statement
> at the top has the behaviour of the current system.
> 
> Positional inheritance
> ======================
> 
> Inherits statements can appear at any point in the object
> body, and the inheritance occurs visibly at that point. All
> side effects of the inherited request occur when execution
> flow reaches that line, and by the start of the following
> line all initialisation in that inheritance chain has
> completed and all its methods are defined.
> 
> Methods and fields defined in the current object constructor
> are available at the start of the execution of its body,
> although it may not be possible to execute them successfully
> until other initialisation has completed. Methods and fields
> defined in a superobject are available after the "inherits"
> statement introducing them, and their initialisation will be
> complete.
> 
> The effect is that, with "inherits" at the top of
> the object body, upcalls are safe; with it at the bottom,
> downcalls to you are safe; and with care, you can order
> things so both work. Common programming styles are likely to
> favour either upcalls or downcalls, so a dialect may enforce
> that inherits statements only appear at either the top or
> bottom for its code.
> 
> This resolves issues with what Kim wants to do in the
> current system, but may require some motivation to be clear
> on what the point is. I have put the sequence of motivating
> examples in a sidebar so they don't stretch this out. I will
> post them as a follow-up, but they are available now from
> <http://ecs.vuw.ac.nz/~mwh/positional-motivation.txt>.
> 
> Ambiguity
> =========
> 
> An inherits statement can include an "as" clause, just like
> a module import. The given name can only be used as the
> receiver for directed super-sends up a particular
> inheritance tree.  "self" remains bound to the same object.
> 
> When a single anonymous inherits statement exists, it is
> implicitly named "super". This allows all existing code to
> function exactly as now.
> 
> If an object inherits multiple methods by the same name, the
> one provided by the last inherits statement wins. In all
> cases, the eventual method defined in the object (whether
> inherited or local) SHOULD be fully compatible with the
> signatures of all inherited methods by the same name, with a
> local override being provided to satisfy this criterion if
> applicable.
> 
> Verifying this compatibility statically is up to the
> dialect, with only the ordinary gradual checks occurring at
> runtime. This is required in order to allow the "when the
> programmer does it, that means that it is not illegal"
> style.
> 
> In the case of trait-style inheritance of disjoint sets of
> methods, no ambiguity arises. Multiple independent parents
> may be composed without issue.
> 
> In the case of single-inheritance chains, no ambiguity
> arises. A local definition in the initiating object
> constructor will always override an inherited version.
> 
> Modules
> =======
> 
> Inheriting from modules is by (shallow) cloning.  Modules
> (but not other objects) implicitly get a public "clone"
> method added to them with the appropriate effect.
> 
> The method may be overridden explicitly, and must either
> return an object constructor or raise an exception.
> 
> Option:
> - The method is called something nonspecific and can be
>  provided with various semantics: cloning, delegation,
>  forwarding, &c. These may be obtained by inheriting from a
>  particular library class. In this way they do not need
>  additional privileged access to self reflectively from
>  outside.
> 
> Unresolved issues
> =================
> 
> - Evaluation order of types that depend on types defined in
>  a superclass.
> 
> - "Definitively static" rules out all inheritance chains not
>  rooted in an object defined in the local scope of the
>  method or an imported module.
> 
> - Static binding of names with type parameters.
> 
> All of the above may be related to, but are not the same as,
> Tim's proposed "let".
> 
> - Introduction of method names in a subclass/use of
>  unqualified names in the superclass.
> 
> - Do repeated field declarations give rise to new storage
>  spaces? Some relevant examples are in another sidebar at
>  <http://ecs.vuw.ac.nz/~mwh/catfish.txt>.
> 
> - Non-local returns and exceptions during object
>  construction can lead to leaked partially-initialised
>  objects.
> _______________________________________________
> Grace-core mailing list
> Grace-core at cecs.pdx.edu
> https://mailhost.cecs.pdx.edu/mailman/listinfo/grace-core




More information about the Grace-core mailing list