works with single-inheritance:
. how does the support for multi-inheritance
differ from that for single-inheritance?
review of single inheritance:
. within a subprogram's symbol table,
every symbol has a type indicated,
but if the type was undefined,
then the type indicator says to check the obj's type.tag,
and the symbol table's subtype says the same .
. if it's typed as being an oop supertype,
then the symbol table's type says which supertype,
and the subtype is given as [check the obj's type.tag],
finally, if it's typed as being a particular subtype,
then the symbol table says both type and subtype .
. the main point is that every symbol is typed,
either by the symbol table or the obj's type tags;
thus, when an assignment is made,
the source's type can always be found,
and the destination's type can always be completed .
. a supertype mgt doesn't expect to see a supertype.tag:
it's there for the system to do type checking;
if the object contains a supertype.tag,
then the supertype mgt is sent an adjusted pointer,
one that starts at the subtype.tag .
. a generic container, on the other hand,
does expect to see the supertype.tag,
so it includes space for such boxing itself .]
. when a single-inheriting var is passed a value,
it checks for whether it's already type-tagged:
if not, then the system needs to do the boxing
(ie, adding a type-tag that identifies the value's type
like a box would).
. if it's for a supertype like the numbers
(with a fixed number of owned subtypes,
and some binary operations that can accept
any combination of it's subtypes as arguments )
then it needs to be typed or boxed twice:
once for the supertype,
and again for the subtype;
eg, (type:number, subtype:integer, value:obj),
or (type:string, subtype:null-terminated, value:obj).
. if any type has a non-oop interface,
the system must also provide an oop interface for it;
ie, the type is assigned a type mgt id
that points to a function that will then
accept this oop-system call: the-type( obj, message, args)
that will do the same thing as: obj.the-type`message(args) .
. but, if it's for a supertype like the numbers,
where it owns a fixed set of subtypes,
then the supertype is providing the oop interface,
and its subtypes can be dealt with directly;
eg, it can have a subtype.tag specifically for int32,
and get direct access to this type
instead of working through an interface .]
. when the input is a multi-inheriting type (MIT),
it needs to be boxed just like untagged types;
because, it is functioning as any one of several types,
so it needs to know which role it is currently serving;
ie, when the MIT's type mgt is called with
the-type( obj, message, args),
and it gets the pointer to one of its member objects,
it expects the first word to be the needed type .
. we might avoid the boxing requirement by ensuring that
every types interface had unique message names,
or that the MIT could inherit only
those types that had unique message names;
we could ensure this uniqueness by
implicitly adding the full type name
to every message name .
. a "(full name) includes a pathname,
ie, main.program may declare a local subprogram f
that may declare a local type t,
so the full name of t is main::f::t.type .
. it may seem like it would be efficient to ask the MIT
to provide us with access to the part of itself
that is implementing the type we need
and then we could call the needed type's mgt directly
instead of going through the MIT;
but the MIT may have over-ridden some methods,
so every message has to be directed to the MIT's type mgt,
and then the MIT determines how to route it to a base type .
. overriding may be needed to integrate the
work of the various base types; for example,
the MIT's mgt may want to log or filter all activity,
so it needs to know about any use of its components .
. one problem with assuming MIT's should be boxed
is that we want to support generic polymorphism;
ie, instead of defining a parameter's type,
we are saying only that the input must support
all the messages that are sent to it;
therefore our MIT needs to handle the message
without reference to a specific inheritance .
... on the other hand,
the MIT may prefer to know what's expected,
so then the system should be capable of
providing the expected type;
ie, instead of the basic oop call being:
type-mgt(obj#1..2, msg, args),
it would be:
uniop( msg, type#1..2, obj#1..2, other args ...)
biop( msg, type#1..3, obj#1..3, other args ...)
-- the 1st obj is the destination,
and the other obj or 2 is the operation's source .
. suppose the MIT declares it can act as a number,
then it will be passed to binary operations,
and Number's mgt will then need to know
how to get at the MIT's numeric services
including access to its numeric subtype tag .
. there needs to a flag that says
this is an MIT directory not a type.tag .
. the system may need to repackage things,
so the expected subtype.tag is at the head .
. if the subtype is abstract, eg, integer;
instead of concrete, eg, int32;
then supertype mgt knows to use MIT's interface;
whereas, if the type is concrete,
then the MIT is saying supertype mgt can have direct access,
so then supertype mgt expects the next field
to be a pointer into the MIT's concrete component .