CS 334 Lecture 17

CS 334 Lecture 17

    1. More Eiffel
      1. Miscellaneous Eiffel language tips:
      2. The inherit clause
      3. Summary of assertions:
      4. Constrained genericity.
      5. Visibility:
    2. Type Problems in Eiffel

More Eiffel

Last time: Discussed classes, objects, methods, subclass, subtypes, dynamic method invocation.

Miscellaneous Eiffel language tips:

"And", "or" are non-short-circuit. Use "and then", "or else" for short circuit.

Note that all variables should be thought of as references to objects.

Can't do anything to a variable until you create it or assign a value to it.
(Illegal to send a message to an uninitialized variable.)

Thus a := b means that a now refers to the same object as b (sharing).

Important:: Note that only local variables or own attributes may be assigned to or created:

If "a" has been created, a.copy(b) will change "a" to be field-by-field identical to "b" (using sharing for reference fields). It will crash if a = Void.

To give "a" a new copy of object referred to by "b", write a := clone(b)
Note that you need not have created a before you can do this!

deep_clone and deep_copy are similar, but copy recursively.

frozen equal(some: ANY; other: like some): BOOLEAN is
    Result = (some = Void and other = Void) or 
                    (some /= Void and other /= Void 
                        and then some.is_equal(other) )
The standard is_equal determines if fields which are references are identical (or flat fields are equal). If a "deep" version is desired, it may be programmed by hand or you may simply use deep_equal (some, other).

Note that clone and equal are routines available in any class.
They are defined in class ANY which has features which are available to all other classes. ANY also includes io which was used earlier.

The inherit clause

Eiffel supports multiple inheritance (just list multiple names after INHERIT).

Leads to necessity of resolving name clashes.

As a result the INHERIT clause has a number of options (which must occur in the following order:

rename -- allows the programmer to change the name of inherited features, can be especially helpful if get name clashes in multiple inheritance

export -- allows the user to change the export status of inherited features

undefine -- can be used to resolve name clashes in multiple inheritance

redefine -- warns that inherited feature will be redefined

select -- used to determine which method is to be used if there are two methods with same name (usually a result of multiple inheritance)

See chapters 6 and 7 in Switzer for details on how to use these.

Few tips: Suppose feature m is defined in class A and have

class B 
    inherit A
            m as k
feature ...

Now suppose that x : A, but at run time x actually holds a value of type B.

I.e., static type of x is A, but dynamic type is B.

By static type-checking, x.m should be defined. What is actually executed?

Answer: method k of B (only reasonable answer)

More complicated: Suppose you wish to redefine m in B, but use old definition in A as part of code:

class B 
    inherit A
            m as old_m
        redefine m
    m (...) is
        do ... old_m ... end;

Unfortunately, this won't quite work. The problem arises again when we have a variable of static type A, holding a value of type B. What happens when x.m is executed?

As in the earlier example, the renamed version of m (in this case old_m) will be executed. This is not what we wanted. Instead must write:

class B 
    inherit A
            m as old_m
    inherit A
    m (...) is
        do ... old_m ... end;

Here we have actually inherited m twice. Since there are two definitions which can be used when this object is held in a variable of type A, we must tell the system which to use. The select clause tells it to resolve the ambiguity by taking the m from the second version (which is redefined in the class!).

Ugly, but it resolves all of the ambiguities!

I personally think multiple inheritance is usually a bad idea and should generally be avoided. (See comments later on multiple subtyping - which is helpful!)

Summary of assertions:

Different classes of assertion-checking can be turned on and off in the Ace file.

Assertions can be labelled - provides information in error messages and helpful in exception handling.

If method is redefined in subclass preconditions must be weaker (i.e., accept at least as many inputs as before) and postconditions must be stronger.

Therefore if use subclass in place of superclass, redefined method will accept any inputs that original would have and return results meeting expected criteria.

Go over parsing example on-line.