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.
|Dynamic DNS—an Object Lesson in Problem Solving||May 21, 2013|
|Using Salt Stack and Vagrant for Drupal Development||May 20, 2013|
|Making Linux and Android Get Along (It's Not as Hard as It Sounds)||May 16, 2013|
|Drupal Is a Framework: Why Everyone Needs to Understand This||May 15, 2013|
|Home, My Backup Data Center||May 13, 2013|
|Non-Linux FOSS: Seashore||May 10, 2013|
- Dynamic DNS—an Object Lesson in Problem Solving
- Making Linux and Android Get Along (It's Not as Hard as It Sounds)
- Using Salt Stack and Vagrant for Drupal Development
- New Products
- A Topic for Discussion - Open Source Feature-Richness?
- RSS Feeds
- Drupal Is a Framework: Why Everyone Needs to Understand This
- Validate an E-Mail Address with PHP, the Right Way
- Readers' Choice Awards
- The Secret Password Is...
- All the articles you talked
2 hours 20 min ago
- All the articles you talked
2 hours 23 min ago
- All the articles you talked
2 hours 25 min ago
6 hours 49 min ago
- Keeping track of IP address
8 hours 40 min ago
- Roll your own dynamic dns
13 hours 54 min ago
- Please correct the URL for Salt Stack's web site
17 hours 5 min ago
- Android is Linux -- why no better inter-operation
19 hours 21 min ago
- Connecting Android device to desktop Linux via USB
19 hours 49 min ago
- Find new cell phone and tablet pc
20 hours 47 min ago
Enter to Win an Adafruit Pi Cobbler Breakout Kit for Raspberry Pi
It's Raspberry Pi month at Linux Journal. Each week in May, Adafruit will be giving away a Pi-related prize to a lucky, randomly drawn LJ reader. Winners will be announced weekly.
Fill out the fields below to enter to win this week's prize-- a Pi Cobbler Breakout Kit for Raspberry Pi.
Congratulations to our winners so far:
- 5-8-13, Pi Starter Pack: Jack Davis
- 5-15-13, Pi Model B 512MB RAM: Patrick Dunn
- 5-21-13, Prototyping Pi Plate Kit: Philip Kirby
- Next winner announced on 5-27-13!
Free Webinar: Hadoop
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers
Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.
Some of key questions to be discussed are:
- What is the “typical” Hadoop cluster and what should be installed on the different machine types?
- Why should you consider the typical workload patterns when making your hardware decisions?
- Are all microservers created equal for Hadoop deployments?
- How do I plan for expansion if I require more compute, memory, storage or networking?