Introduction to Eiffel
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.
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.
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.
Fast/Flexible Linux OS Recovery
On Demand Now
In this live one-hour webinar, learn how to enhance your existing backup strategies for complete disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible full-system recovery solution for UNIX and Linux systems.
Join Linux Journal's Shawn Powers and David Huffman, President/CEO, Storix, Inc.
Free to Linux Journal readers.Register Now!
- Download "Linux Management with Red Hat Satellite: Measuring Business Impact and ROI"
- Secure Desktops with Qubes: Introduction
- Fancy Tricks for Changing Numeric Base
- Seeing Red and Getting Sleep
- Working with Command Arguments
- Secure Desktops with Qubes: Installation
- The Italian Army Switches to LibreOffice
- Petros Koutoupis' RapidDisk
- CentOS 6.8 Released
- Linux Mint 18
Until recently, IBM’s Power Platform was looked upon as being the system that hosted IBM’s flavor of UNIX and proprietary operating system called IBM i. These servers often are found in medium-size businesses running ERP, CRM and financials for on-premise customers. By enabling the Power platform to run the Linux OS, IBM now has positioned Power to be the platform of choice for those already running Linux that are facing scalability issues, especially customers looking at analytics, big data or cloud computing.
￼Running Linux on IBM’s Power hardware offers some obvious benefits, including improved processing speed and memory bandwidth, inherent security, and simpler deployment and management. But if you look beyond the impressive architecture, you’ll also find an open ecosystem that has given rise to a strong, innovative community, as well as an inventory of system and network management applications that really help leverage the benefits offered by running Linux on Power.Get the Guide