For instance, the class COMPARABLE is from the Eiffel library (the result shown is the result of extracting the flat-short version of the class).
deferred class interface COMPARABLE
feature specification
    infix "<" (other: like Current): BOOLEAN is
        deferred;
    infix "<=" (other: like Current): BOOLEAN is
        deferred;
    infix ">" (other: like Current): BOOLEAN is
        deferred;
    infix ">=" (other: like Current): BOOLEAN is
        deferred;
end interface -- class COMPARABLE
Now define
class INTORD
feature
    value:INTEGER;
    infix "<"(other:like Current) is
        do 
            Result := value < other.value
        end;
    ...
end -- class INTORD
Can use in
class Sorting[T -> COMPARABLE] 
feature
    sort(thearray:ARRAY[T]):ARRAY[T] is
        local  ....
        do
            ......
            .... if thearray.item(i) < thearray.item(j) ....
        end;
Subclasses can see all features, whether exported or not.
Eiffel has tools to
Allowable changes which can be made in subclasses:
More flexible than Object Pascal or C++ (but leads to problems, below!)
Big problem with Eiffel - identification of class with type.
Say C' is a subclass (or heir) of C if C' inherits from C.
Thus C' inherits attributes and methods from superclass.
When redefine methods in subclass may replace class of arguments and answer by subclasses.
E.g.
If m(a:A):B in C then can redefine m(a:A'):B' in subclass C' if A' inherits from A and B' inherits from B.
Unfortunately, this can lead to holes in typing system.
Recall A' is a subtype of A if an element of type A' can be used in any context expecting an element of type A.
Eiffel allows programmer to use an element of subclass anywhere it expects an element of its superclass.
Therefore distinction between static and dynamic class!
Unfortunately subtype != subclass.
The following are slightly simplified examples from the Eiffel structure library. They represent singly and doubly-linked nodes.
class LINKABLE [G]
feature
        item: G;
        right: like Current;  -- Right neighbor
        put_right (other: like Current) is
        -- Put `other' to the right of current cell.
                do
                        right := other
                ensure
                        chained: right = other
                end;
end -- class LINKABLE
Now
define subclass:
class BI_LINKABLE [G] inherit
        LINKABLE [G]
                redefine
                        put_right
                end
feature -- Access
        left: like Current;
                        -- Left neighbor
        put_right (other: like Current) is
                        -- Put `other' to the right of current cell.
                do
                        right := other;
                        if (other /= Void) then
                                other.simple_put_left (Current)
                        end
                end;
        put_left (other: like Current) is
                        -- Put `other' to the left of current cell.
                do
                        left := other;
                        if (other /= Void) then
                                other.simple_put_right (Current)
                        end
                ensure
                        chained: left = other
                end;
        simple_put_right (other: like Current) is
                        -- set `right' to `other'
                do
                        if right /= Void then
                                right.simple_forget_left;
                        end;
                        right := other
                end;
        simple_put_left (other: like Current) is
                        -- set `left' to `other' is
                do
                        if left /= Void then
                                left.simple_forget_right
                        end;
                        left := other
                end;
invariant
        right_symmetry:
                (right /= Void) implies (right.left = Current);
        left_symmetry:
                (left /= Void) implies (left.right = Current)
end -- class BI_LINKABLE
So far so good.
But now suppose have following routine
trouble(p, q : LINKABLE [RATIONAL] ) is
    do
        p.put_right(q);
        ....
    end
and suppose have s_node : LINKABLE [RATIONAL] and bi_node: BI_LINKABLE [RATIONAL].
What happens if write:
    trouble(bi_node,s_node)
If
BI_LINKABLE [RATIONAL] is subtype of LINKABLE [RATIONAL],
then this should work, instead, BANG!!!!! - system crash.
Problem is that
s_node.put_right takes a parameter of type (class) LINKABLE [RATIONAL]
while bi_node.put_right takes a parameter of type (class):
        BI_LINKABLE [RATIONAL] 
and
these are not subtypes:A' -> B' subtype of A -> B iff B' subtype of B and A subtype of A'
note reversal!
With procedure can think of the return type as VOID.
Thus subclass in Eiffel does not always give legal subtype.
Hence get holes in type system.
Can also export method from superclass, but not from subclass. This will also break system if send message to object of subclass which is not visible.
E.g., define
hide_n_break(a:A) is
    do
        a.meth ....
    end
and then write hide_n_break(a') where a' : A', and A' is subclass of A which does not export meth.
Earlier versions of Eiffel allowed user to break the type system in these ways.
Eiffel 3.0 attempts to compensate by mandating a global check of all classes used in a system to make sure that above situation could not occur (class-level check and system-level check). One consequence is that a system could work fine,but addition of new (separately compiled) class could break a previously defined class.
Unfortunately no Eiffel compilers implement this system validity check.
In Fall, '95, Bertrand Meyer announced solutions to "covariant typing problem" at OOPSLA '95. Two days later I found a hole in the solution. It's been fixed, but other problems may remain.
Virtually all object-oriented language either provide holes like this or are so rigid they force the programmers to bypass the type system. For example, C++ doesn't allow user to change type of parameters of methods (new versions allow change in type of results of function methods), but has many, many, more holes, e.g., unchecked casts. Java inserts dynamic checks of casts to avoid type holes (but blew suptyping of array types - though add dynamic check).
Most statically typed object-oriented languages are either
Trellis/Owl (by DEC) avoids the problem by only allowing subclasses which are also subtypes, but this is pretty restrictive - rules out above COLORPOINT class.
Claim proper solution is to separate subtype and inheritance hierarchies (originally proposed by researchers in ABEL group at HP Labs and independently by P. America at Philips Research Labs)
Inheritance hierarchy has only to do with implementation.
Subtype hierarchy has only to do with interface.
Therefore class != type.
Bonus:  Can have multiple classes generating objects of same
type
E.g., cartesian and polar points with same external interface.
Even though don't necessarily care if subclasses turn out to be subtypes, still need restrictions on redefinitions to avoid breaking other inherited methods.
Ex.:
    method1(...) = ... p.method2(..)....
    method2(...) = .....
If now redefine method2 with different type, how do we know it will continue to be type-safe when used in method1 (presuming method1 is inherited and not changed).
One can set up type-checking rules for determining legal subclasses and subtypes and be guaranteed that can't break the typing system.
This is extremely important, since one of goals of object-oriented programming languages is to provide reusable libraries of components, much like that found with FORTRAN for numerical routines or Modula-2 for data structures.
Major advantage would be ability to make minor modifications to allow user to customize classes.
Sale of libraries is expected to become a major software industry. However, if selling library will typically only sell compiled version, not source code (though provide something like definition module).
If user doesn't see source code of superclass, how can s/he be confident that will get no type errors. Need the kind of guarantees claimed above.
Work here on TOOPLE, TOIL, PolyTOIL, and LOOM (involving honors theses by R. van Gent '93, A. Schuett '94, and L. Petersen '96, and supporting work by J. Rosenberg & S. Calvo '96) resulted in object-oriented language which is type-safe and only requires classes and methods to be type-checked once (don't have to repeat when inherit methods).
Other Eiffel examples:
PARENTHESES - simple example using STACK class from structures library.
Evaluation of OOL's.
Pro's (at least of Eiffel)
Con's
Eiffel also provides support for number of features of modern software engineering - e.g., assertions.
Could be a very important language if fixed type problems - Sather is one attempt.
What will be impact of OOL's on programmers and computer science?
Large number of powerful players jumped on the bandwagon without careful assessment of consequences. Now growing reaction against C++.
Many OO programmers don't really understand paradigm, esp. if use OO add-on to older language.
Suspect that most of the advantages claimed by proponents could be realized in Clu, Modula-2, or Ada (all available decade or more ago).
Some languages (Modula-3, Haskell, Quest, etc.) provide subtyping without inheritance. Seem to be few problems associated with this.
My advice: specify carefully meaning of methods, avoid long inheritance chains, and be careful of interactions of methods. If implement generics, Java could be a very successful compromise between flexibility and usefulness.
May have originated with idea that definition of language be an actual implementation. E.g. FORTRAN on IBM 704.
Can be too dependent on features of actual hardware. Hard to tell if other implementations define same language.
Now define abstract machine, and give translation of language onto abstract machine. Need only interpret that abstract machine on actual machine to get implementation.
Ex: Interpreters for PCF. Transformed a program into a "normal form" program (can't be further reduced). More complex with language with states.
Expressions reduce to pair (v,s), Commands reduce to new state, s.
E.g.
    (e1, rho, s) => (m, s')    (e2, rho, s') => (n, s'')
    ----------------------------------------------------
               (e1 + e2, rho, s) => (m+n, s'')
            (M, rho, s') => (v, s'')
    ----------------------------------------
    (X := M, rho, s) => (rho, s''[v/rho(X)])
    (fun(X).M, rho, s) => (< fun(X).M, rho >, s)
    (f,rho,s) => (<fun(X).M, rho'>, s')   (N,rho,s') => (v,s''),    
                (M, rho' [v/X], s'') => (v', s''' )
    ------------------------------------------------------------                  
                    (f(N), rho, s) => (v', s''' )
Meaning of program is sequence of states that machine goes through in executing it - trace of execution. Essentially an interpreter for language.
Very useful for compiler writers since very low-level description.
Idea is abstract machine is simple enough that it is impossible to misunderstand its operation.
No model of execution.
Definition tells what may be proved about programs. Associate axiom with each construct of language. Rules for composing pieces into more complex programs.
Meaning of construct is given in terms of assertions about computation state before and after execution.
General form:
			{P} statement {Q}
where
P and Q are assertions.  
Meaning is that if P is true before execution of statement and statement terminates, then Q must be true after termination.
Assignment axiom:
	{P [expression / id]} id := expression  {P}
e.g.
		{a+17 > 0} x := a+17 {x > 0}
or
		{x > 1} x := x - 1 {x > 0} 
While rule:
	If {P & B} stats {P}, then {P} while B do stats {P & not B}
E.g. if P is an invariant of stats, then after execution of the loop, P will still be true but B will have failed.
Composition:
	If {P} S1 {Q}, {R} S2 {T}, and Q => R, 
		then {P} S1; S2 {T}
Conditional:
	If {P & B} S1 {Q}, {P & not B} S2 {Q}, 
			then {P} if B then S1 else S2 {Q}
Consequence:
	If P => Q, R => T, and {Q} S {R},
			then {P} S {T}
Prove program correct if show
	{Precondition} Prog {PostCondition}
Often easiest to work backwards from Postcondition to Precondition.
Ex:
	{Precondition: exponent0 >= 0}
	base <- base0
	exponent <- exponent0
	ans <- 1
	while exponent > 0 do
		{assert:  ans * (base ** exponent) = base0 ** exponent0}
		{           & exponent >= 0}
		if odd(exponent) then
				ans<- ans*base
				exponent <- exponent - 1
			else
				base <- base * base
				exponent <- exponent div 2
		end if
	end while
	{Postcondition: exponent = 0}
	{               & ans = base0 ** exponent0}
Let us show that:
P = ans * (base ** exponent) = (base0 ** exponent0) & exponent >= 0is an invariant assertion of the while loop.
The proof rule for a while loop is:
	If {P & B} S {P}  then  {P} While B do S {P & not-B}
We
need to show P above is invariant (i.e., verify that {P & B} S
{P}).
Thus we must show:
{P & exponent > 0}
if odd(exponent) then
                ans<- ans*base
                exponent <- exponent - 1
            else
                base <- base * base
                exponent <- exponent div 2
        end if
{P}
However,
the if..then..else.. rule is:
    if {P & B} S1 {Q} and {P & not-B} S2 {Q} then 
                                    {P} if B then S1 else S2 {Q}.
Thus
it will be sufficient if we can show
(1) {P & exponent > 0 & odd(exponent)}
            ans<- ans*base; exponent <- exponent - 1 {P} 
and
(2) {P & exponent > 0 & not-odd(exponent)}
            base <- base * base; exponent <- exponent div 2 {P}
But
these are now relatively straight-forward to show.  We do (1) in detail and
leave (2) as an exercise.Recall the assignment axiom is {P[exp/X]} X := exp {P}.
If we push P "back" through the two assignment statements in (1), we get:
{P[ans*base/ans][exponent - 1/exponent]} 
                ans<- ans*base; exponent <- exponent - 1 {P}
But
if we make these substitutions in P we get the precondition is:
    ans*base* (base ** (exponent - 1)) = base0 ** exponent0 
            & exponent - 1 >= 0
which
can be rewritten using rules of exponents as:
    ans*(base ** exponent) = base0 ** exponent0 & exponent >= 1
Thus,
by the assignment axiom (applied twice) we get
(3) {ans*(base**exponent) = base0**exponent0 & exponent >= 1}
            base <- base * base; exponent <- exponent div 2 {P}
Because we have the rule:
    If {R} S {Q} and R' => R  then {R'} S {Q}
To
prove (1), all we have to do is show that
(3)     P & exponent > 0 & odd(exponent) => 
                    ans*(base ** exponent) = base0 ** exponent0 
                    & exponent >= 1
where
P is 
    ans*(base**exponent) = (base0**exponent0) & exponent >= 0.
Since
ans * (base ** exponent) = (base0 ** exponent0) appears in both the
hypothesis and the conclusion, there is no problem with that.  The only
difficult is to prove that exponent >= 1.However exponent > 0 & odd(exponent) => exponent >= 1.
Thus (3) is true and hence (1) is true.
A similar proof shows that (2) is true, and hence that P truly is an invariant of the while loop!
Axiomatic semantics due to Floyd & Hoare, Dijkstra also major contributor. Used to define semantics of Pascal [Hoare & Wirth, 1973]
Too high level to be of much use to compiler writers.
Perfect for proving programs correct.