The Semantics of Multiple Disjoint Inheritance and Operating Overloading in Mynx
Semantic Context Quandary of Multiple Disjoint Inheritance
For a given set of super-classes that are multiply inherited, the methods can be associated with an operator that is overloadable, operator overloading. In implementing context semantics (semantics of the overall unit--a class or program) one semantic consideration is for operator overloading in multiple-disjoint inheritance. The methods of the multiply inherited classes are disjoint from one another, but it is very possible for the sub-class to have non-disjoint, multiply inherited operators. The semantic question is one of for multiply inherited operators, which method is invoked for an expression using the operator.
Example Operator Overload on Different Methods
Consider the following Mynx classes:
class X is
public X cat(in X x) is
//method definition for concatenation
end cat;
overload default + as cat;
end class;
class Y is
public Y add(in Y y) is
//method definition for addition
end add;
overload default + as add;
end class;
class Z is
public Z join(in Z z) is
//method definition for join
end join;
overload default + as join;
end class;
Each class is disjoint (X=cat, Y=add, Z=join) so can be multiply inherited.
Consider the Mynx class that derives from the Mynx classes of X,Y,Z (great names, remember the X,Y,Z affair in history?) that is:
class A as X,Y,Z is
public construct is to null;
public void doNothing is
null;
end doNothing;
end class;
To illustrate the semantic ambiguity, the following code fragment illustrates:
A myVar1 to default;
A myVar2 to default;
A result to null;
result is myVar1 + myVar2; //uh-oh! which method to use in overload??
//three possibilities is:
result is myVar1.add(myVar2);
result is myVar1.cat(myVar2);
result is myVar1.join(myVar2);
The Problem of Semantic Ambiguity
The semantic consideration is to avoid ambiguity, to consistently and the expected substitute a method invocation for an overload. The Mynx language in the semantics has to avoid the unexpected or inconsistent--something both Wirth and Hoare strongly admonish for a language designer to consider in designing a language.
Thus there is definitely semantic ambiguity--a major problem, ambiguity is the anathema of a programming language, and a major frustration for the software developer using the language.
A solution is possible--the semantic context rule for operator overloading with multiple inheritance. But, while many solutions are possible, consistency is important. Otherwise you wind up with many exceptions to a general rule, making the rule a footnote in the programming language semantics. Spoken, natural languages have lots of little rules, I remember learning German and the article to use for a word, the gender (male, female, neuter), the form (nominative, accusative, genitive, dative). English of course is no different, but a programming language has intention so lots of little rules is illogical. And a software developer has to carry the cognitive overhead of knowing all the rules in order to use the language effectively.
One solution is the ostrich-buried-head-in-the-sand approach--pretend the semantic ambiguity exists, or like most managers stressing teamwork and consensus, do not make any decision. Managers delegate the decision to team members and build consensus. Unfortunately that is problem avoidance.
Unresolved Semantic Considerations Create Semantic Ambiguity
What happens in a programming language for a semantic consideration that is solved (an oxymoron) by problem avoidance? The answer is better given with an anecdote and illustrative example.
Take a programming language that was immensely popular, Pascal. The creation of Niklaus Wirth, it was popular for many years from its original introduction in the early 1970's, when structured/procedural programming was emerging as the dominant paradigm.
Pascal (and if you read some of the papers that were critiques of Pascal about Pascal's limitations) was limited in some of its core features, but some of the features had no clear solution for semantic considerations.
For example, the for loop in Pascal had an interesting semantic ambiguity for (no pun intended) the loop variable. Consider the Pascal code fragment:
var
K, I: Integer;
begin
K := 0;
for I := 1 to 10 do
begin
K := K + I;
end;
The semantic consideration, and resulting ambiguity is the for loop variable: I. What is the value of I after the for loop terminates, is it 10, or 11, or 9?
Once I was implementing a program in Pascal as an undergrad (that was the learning language until the computer science department went over to C++), and I had a for loop that always did something on the last pass through a for loop (I forget what it was, I think it was write a total to a file and close it). I originally implemented the program using (and you guessed it...) Turbo Pascal on a 80386 PC. But, I found out later I needed much bigger arrays than the 64K limit of Turbo Pascal, so I opted to use the SunOS system, and the Sun Pascal compiler "pc" which ran on the Sun system. I was able to define huge arrays, but then looking at the created file, I saw that the for loop went one further, instead of 1 to 10, it was 1 to 11.
I wrote a simple dummy program with a bunch of writeln statements, and low-and-behold, the for loop generated code that went from 1 to 11. It got worse when I thought (you learn as an undergrad not to think...) of e-mailing my short Pascal program to a friend at another university, and in the guise of duplication of a scientific experiment. My friend had access to a esoteric minicomputer system that the university had bought into, but it had a Pascal compiler that loyally followed Wirth's definition of Pascal (something most Pascal implementations did not in order to be useable--like Turbo and Sun).
A few days later my friend e-mailed me one of the text files created, and the for-loop went from 1 to 9, apparently it was like the C programming language which normally went for(x=1;x<10;x++). The next semester, I was in a course on programming languages, and I recall the lecture about semantics, and that one quirk of Pascal mentioned. The point was any semantic consideration that was not decided by the language designer, it was up to the compiler implementer, so is idiosyncratic or specific to the platform. So if the language designer does not say, the compiler writer may do. The difficulty is that semantics can be very subtle, a reaction between two features of the language. In this case, the semantic context of operator overloading and multiple-disjoint inheritance in Mynx.
Hence the solution of leaving the semantic consideration unresolved leads to semantic ambiguity, leaving the solution up to a compiler writer. A potential inconsistency that leads to non-portable, idiosyncratic software for classes. So a formal semantic specification is needed for the solution, not semantic ambiguity. Now it becomes a question of how to handle the semantic ambiguity?
Solution to Operator Overloading with Multiple Inheritance
The solution is simple, and uses by extension an existing rule for operator overloading.
For a constant operator overload, one that is immutable, in a sub-class the operator overload must be explicitly declared and reference the super-class.
Using this rule, for a sub-class that has super-classes with multiple operator overloads, the solution is to require the sub-class to specify which operator overload to use, one of the super-class overloads, or one in the class itself. For super-classes with multiple constant overloads, the rule of explicit declaration is used, and the specific super-class referenced.
Thus for the Mynx class X, the overload is specified:
class A as X,Y,Z is
public construct is to null;
public void doNothing is
null;
end doNothing;
overload default + as super.cat;
end class;
The class references the super-class with the cat method. Then the Mynx code fragment is not semantically ambiguous:
A myVar1 to default;
A myVar2 to default;
A result to null;
result is myVar1 + myVar2; //uh-oh! which method to use in overload?? cat
result is myVar1.cat(myVar2);
The existing operator overload rule for a default operator overload is that it is implicitly included, although I wonder if it should be explicit so that intention is always manifest in a Mynx class.
Also imagine if a super-class has a deep sub-class that has implicitly included an operator overload, it would be very tedious and time consuming to find the original operator overload in the super-class.
The explicit but verbose approach is preferable, appealing to total typing torpidity is not an objective metric for assessing a programming language. Intention by verbosity over succinctness via implicitness.
Oh, and have a safe, fun, and Happy Hallowe'en!!!
Labels: multiple inheritance, mynx semantic, operator overload

