Introduction to Eiffel

Dan introduces us to the Eiffel language, a fairly new Object-Oriented language designed to streamline the software engineeering process.
Classes

Object-oriented programming draws on just a few main ideas. I will talk about three of the important ones and illustrate their realization in the Eiffel language.

The first important idea is encapsulation: the packaging of data with means to manipulate it. Such a package, written in a programming language is a class, but an instance of a class in execution (or in storage) is an object.

In Eiffel, everything exists within a class. There are no external variables or routines. A class has features. Features in turn are either attributes or routines.

Attributes store values, including references to objects. They may be constant or variable.

Routines do things. Routines are either procedures or functions. Functions return results and are not supposed to change system state. Procedures change system state but return nothing.

All features, even constant or variable attributes, are said to be “called”. This is perhaps less strange than it might seem, for in Eiffel, a call to a function with no arguments is written the same as a call to an attribute. If in some class you write:


that := the.other

the.other may be either a function or an attribute, in this context it makes no difference.

So, you encapsulate data and the routines that manipulate it in a class. Assertions, mentioned previously, are also parts of a class and serve to express class preconditions, constraints and invariants.

Inheritance

The second important idea is inheritance.

Once you have a class, which describes what you know about the how and why of some sort of object, it may further benefit you to derive a new class from it, with additions and variations, without touching the program code in the original class. Inheritance is a mechanism that allows this.

For example, you might derive BEE from INSECT. Many features of BEE would inherit directly from INSECT, some features would be modified, and BEE would provide a few new features of its own.

A rule of thumb, called the “is-a” rule, furnishes one way to determine whether A might usefully inherit from B. Examine the sentence “A is a B”. Does it make sense? It should if A is a reasonable candidate to inherit from B. For example, “BEE is an INSECT” passes this test, so BEE might inherit from INSECT. Then, INSECT will be ancestor of BEE, and BEE will be a descendent INSECT.

The “has-a” rule furnishes a contrast. If “A has a B” makes more sense than “A is a B”, it may be prudent to let A reference or have a feature of type B, rather than inheriting from B. “BEE has a STINGER” makes more sense than “BEE is a STINGER” or for that matter “STINGER is a BEE”. Therefore, class BEE should have a feature of type STINGER. That makes BEE a client of STINGER, and STINGER a supplier to BEE.

The client-supplier relationship offers a client less detailed control than a descendent. A client may use or not use a feature of a supplier, but it cannot redefine such a feature. Many of a supplier's features may be hidden from a client, while they will be visible to a descendent. The positive side of this is that the client will be relatively unaffected by details of a supplier's implementation and less likely to be impacted by changes in a supplier.

Both client and inheritance relationships can facilitate software reuse. The traditional function call is more akin to the client relationship, and many attempts at reuse in the past, prior to object-oriented approaches, have made use of the function call. However, we still find ourselves writing and rewriting familiar pieces of functional code too complex to make good candidates for library routines.

The implementation details of inheritance may seriously affect its suitability as a mechanism for reuse. In the ideal implementation, problems arising in descendent classes could always be resolved there. Unfortunately, with many languages, problems arising in descendent classes require changes to ancestors.

This becomes more true with multiple inheritance, a technique by which a class may enjoy, or perhaps not enjoy, multiple ancestors. This technique is a powerful one, but it is unavailable in many object-oriented languages and discouraged in most of the rest. Among languages that have reached commercial viability, Eiffel offers a superior implementation of multiple inheritance.

Polymorphism

In its broad sense, this indicates a situation where a simple request may elicit different but not entirely inconsistent responses, depending on the target of the request. These responses may be arrived at by entirely different means.

For example, you might have classes that look in part like this:


class INSECT
-- Description of a standard            -- insect.
     ...
feature flee is
     do
     -- How a standard
     -- insect flees.
     ...
     end; -- flee
end

class BEE
inherit INSECT
     redefine flee
     end;
     ...
feature flee is
     do
     -- How a bee flees.
            ...
     end; --flee
end
class COCKROACH
inherit INSECT
     redefine flee
     end;
     ...
feature flee is
     do
     -- How a cockroach flees.
     ...
     end; -- flee
end

class WATERBUG
inherit INSECT
     redefine flee
     end;
     ...
feature flee is
     -- How a water bug flees.
     ...
     end; -- flee
end

Then, you might have examples of BEE, COCKROACH, and WATERBUG bound to references of INSECT:


-- Define references to an
-- INSECT and to a BEE.

     insect:INSECT;
     bob:BEE;

-- Bind some particular
-- insect to the reference

     insect := bugs.get

-- Now you have a BEE, a
-- COCKROACH or a WATERBUG.
-- Make it flee after its own
-- fashion, be it that of BEE,
-- COCKROACH, or WATERBUG.
-- This is a polymorphic call,
-- as the code executed will
-- depend on the type of the
-- object bound to insect.

     insect.flee;

-- You can't make a WATERBUG
-- collect pollen.
-- For this you need a BEE, and
-- a trial assignment is
-- available to assign objects
-- that might conform to the
-- type of a reference.

     bob ?= insect;

-- Then maybe you can make bob
-- the bee collect pollen.
-- If he isn't a BEE or a
-- conforming type, bob is Void.

     if bob /= Void then
        bob.collect_pollen
     end;

Another sort of polymorphism, sometimes called parametric polymorphism, is supported in Eiffel as genericity.

The final sort of polymorphism I'll mention is found as function overloading in other languages. Here, a function may be defined multiple times, with different types and numbers of arguments. When the function is called, the actual function invoked depends on the argument list.

Function overloading is not implemented in Eiffel. Workarounds are present, and arithmetic operations are handled as special cases, but the general case of function overloading is felt by the designers of Eiffel to be too full of potential ambiguities, type-checking failures, complications, and interactions to be worthwhile just now. A lively thread on this topic is seen from time to time on the newsgroup comp.lang.eiffel.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix