Added doc for 21.11
git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2328 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
BIN
documentation/21.11/_images/Definition_icon_2.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
3
documentation/21.11/_images/Definition_icon_2.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoDefinition
|
||||
author=halw
|
||||
path=content/logodefinition
|
||||
BIN
documentation/21.11/_images/LogoBeta.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
3
documentation/21.11/_images/LogoBeta.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoBeta
|
||||
author=halw
|
||||
path=content/logobeta
|
||||
BIN
documentation/21.11/_images/LogoUpdateNeeded.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
3
documentation/21.11/_images/LogoUpdateNeeded.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoUpdateNeeded
|
||||
author=halw
|
||||
path=content/logoupdateneeded
|
||||
BIN
documentation/21.11/_images/Review_icon_1.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
3
documentation/21.11/_images/Review_icon_1.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoReviewRequested
|
||||
author=halw
|
||||
path=content/logoreviewrequested
|
||||
BIN
documentation/21.11/_images/Rule_icon_4_2.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
3
documentation/21.11/_images/Rule_icon_4_2.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoRule
|
||||
author=halw
|
||||
path=content/logorule
|
||||
BIN
documentation/21.11/_images/tpl_Construction.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
3
documentation/21.11/_images/tpl_Construction.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoConstruction
|
||||
author=admin
|
||||
path=content/logoconstruction
|
||||
BIN
documentation/21.11/_images/tpl_Information.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
3
documentation/21.11/_images/tpl_Information.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoInformation
|
||||
author=admin
|
||||
path=content/logoinformation
|
||||
BIN
documentation/21.11/_images/tpl_Recommended.png
Normal file
|
After Width: | Height: | Size: 951 B |
3
documentation/21.11/_images/tpl_Recommended.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoRecommended
|
||||
author=admin
|
||||
path=content/logorecommended
|
||||
BIN
documentation/21.11/_images/tpl_Warning.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
3
documentation/21.11/_images/tpl_Warning.png.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=LogoWarning
|
||||
author=admin
|
||||
path=content/logowarning
|
||||
116
documentation/21.11/_others/community/index.wiki
Normal file
@@ -0,0 +1,116 @@
|
||||
[[Property:title|Community]]
|
||||
[[Property:description|Members of the Eiffel community can contribute to this documentation through this book]]
|
||||
[[Property:weight|15]]
|
||||
[[Property:uuid|75c75712-7c3e-2757-51b7-77b404471e2e]]
|
||||
=You can become a contributor!=
|
||||
|
||||
Eiffel is a community. Members of the Eiffel community can contribute to this documentation through this book.
|
||||
|
||||
EiffelStudio documentation is available in a convenient Wiki format. This makes it possible to improve the documentation continuously and make sure it is always up to date.
|
||||
|
||||
Community input is welcome.
|
||||
|
||||
==Using the Comments pages==
|
||||
|
||||
Each documentation page has an associated '''Comments''' page. Any viewer can add comments to a Comments page. These comments are periodically reviewed and appropriate content is "published," that is, made visible to the community.
|
||||
|
||||
===Guidelines for Comments pages===
|
||||
|
||||
#The '''Comments''' pages are intended to be used to record and communicate issues concerning the documentation. Use Comments pages to post comments which report problems with the documentation or which suggest improvements to the documentation.
|
||||
# '''Any material you add to this site becomes the property of Eiffel Software, and may be shared with the community.'''
|
||||
# Comments pages should ''not'' be used for product support questions, product feature requests, or bug reports. ''Comments of this sort will be deleted.'' For help with products join the [http://groups.eiffel.com Eiffel Software User Group] and use the resources at the [http://community.eiffel.com Eiffel Community site].
|
||||
|
||||
===Comment lifecycle===
|
||||
|
||||
Although the procedure for how editors deal with comments is flexible, some general guidelines can be given:
|
||||
|
||||
# For comments requesting action (e. g., fix a problem, add more information):
|
||||
## For those actions which can be accomplished immediately:
|
||||
### The comment will not be published.
|
||||
### The requested action will be fixed.
|
||||
### The original comment's subject line will be prepended with "FIXED".
|
||||
## For those actions which cannot be accomplished quickly or require special handling:
|
||||
### The comment will be published
|
||||
### A response to the comment will be made via "reply", and
|
||||
#### The original comment's subject line will be prepended with:
|
||||
##### FIXED, if and when the request can be satisfied.
|
||||
##### ANALYZED, otherwise, plus explanation of delaying or not acting on request.
|
||||
## For actions affecting docs.eiffel.com plus the Eiffel distribution:
|
||||
### Submit a problem report requesting feedback when problem is fixed so that docs.eiffel.com can be updated in kind.
|
||||
# For comments not requesting action, but adding relevant information related to the page:
|
||||
## The comment will be published.
|
||||
## If appropriate:
|
||||
### The content of the comment will be integrated into the page.
|
||||
### The original comment's subject line prepended with FIXED.
|
||||
# Periodically, an audit will remove older comments marked as FIXED and ANALYZED.
|
||||
|
||||
==Contributors and Editors==
|
||||
|
||||
If you are interested in a more active role in improving and developing EiffelStudio documentation, you can become:
|
||||
|
||||
* A contributor: authorized to edit existing pages to any book, and to add pages to the "Community" book.
|
||||
**"Community" book pages can be added to other books by an editor.
|
||||
|
||||
* An editor: authorized to modify and add pages in any book.
|
||||
|
||||
To become a contributor, you should be proficient in Eiffel technology and have good written English skills. To become an editor, you should already be a contributor and have contributed significant improvements or additions to the documentation.
|
||||
|
||||
If you are interested in becoming a contributor, you can [[path:user/register|register]] for an account, and then please [[path:contact|contact us]] with a short description of your Eiffel experience and any other relevant background.
|
||||
|
||||
===Guidelines for contributors===
|
||||
|
||||
# '''Entering log messages:''' When you change pages in the documentation, it can help sometimes if you can provide an explanation of your intent in the '''Log message''' box on the '''Edit''' page. This can eliminate confusion about why things have been changed. Of course, it is not necessary to provide a log message for every change. For fixing typographical errors or other simple changes, it generally would not be necessary, but putting a single lowercase '''"m"''' in the '''Log message''' field will convey the message that this was a minor update. If you are evolving new pages or a complex set of related changes to one or more pages, it should suffice to enter a single log message at the beginning of the series of edits. Use common sense here.
|
||||
#* In cases in which a change is directly related to an external document or policy, it may be helpful to mention the impetus in the log message. For example, documentation changes made to satisfy Eiffel Software problem reports should reference the report in the log message.
|
||||
# '''Renaming pages or moving pages to Trash:''' Before you rename a page or move it to the Trash, you should use the '''References''' tab to make certain that there are no current references to the page. If there are, make sure you resolve those references before renaming or moving the page.
|
||||
# '''Replacing pages:''' If you need to replace a page completely, do so by replacing the '''content''' of the existing page, rather than moving the page to the Trash and creating a new page in its place. Replacing the content will leave the original page (and its UUID) in place, but with the new content. UUID's are used by the [[Eiffel Information System]] (EIS) to link EiffelStudio to documentation pages, and will be broken if the original page were to be deleted.
|
||||
# '''Using templates:'''
|
||||
## There are several "templates" available for use within the text of documentation pages. For example, "Note", "SeeAlso", "Rule", "Definition", "Caution". You can click on "List templates" in the left margin to see the list of available templates.
|
||||
## While developing new pages or make significant changes to existing pages you may want to mark the tops of these pages temporarily with certain templates during the development process. The "top-of-the-page" templates most useful during page maintenance are Beta, ReviewRequested, UnderConstruction, and UpdateNeeded. The meanings of these are described below.
|
||||
|
||||
==="Top-of-the-page" Documentation template meanings===
|
||||
|
||||
====Beta====
|
||||
|
||||
Looks like this:
|
||||
|
||||
{{Beta}}
|
||||
|
||||
Means this:
|
||||
|
||||
:''Use this page with caution. This page is currently under development as a new page or a replacement for a previously existing page. It may contain information which describes capabilities not yet implemented. Avoid linking to this page. When this page comes out of beta, it is likely that the name and/or UUID of this page will change.''
|
||||
|
||||
|
||||
====ReviewRequested====
|
||||
|
||||
Looks like this:
|
||||
|
||||
{{ReviewRequested}}
|
||||
|
||||
Means this:
|
||||
|
||||
:''The material on this page needs to be reviewed for completeness and accuracy. If you have knowledge of this material, please review this page. If you are a [[Community|contributor]], feel free to make any appropriate additions and/or corrections, then remove this template. If not, you can note improvements on the [[Community#Using the Comments pages|comments]] page.''
|
||||
|
||||
|
||||
====UnderConstruction====
|
||||
|
||||
Looks like this:
|
||||
|
||||
{{UnderConstruction}}
|
||||
|
||||
Means this:
|
||||
|
||||
:''Use this page with caution. This page is currently under development. It is likely that the information on this page is still incomplete. ''
|
||||
|
||||
|
||||
====UpdateNeeded====
|
||||
|
||||
Looks like this:
|
||||
|
||||
{{UpdateNeeded}}
|
||||
|
||||
Means this:
|
||||
|
||||
:''Use this page with caution. This page has been identified as needing update. If you are a [[Community|contributor]], you can help by updating this page so that the information on it is current.''
|
||||
|
||||
|
||||
|
||||
5
documentation/21.11/_others/draft/index.wiki
Normal file
@@ -0,0 +1,5 @@
|
||||
[[Property:title|Draft]]
|
||||
[[Property:weight|99]]
|
||||
[[Property:uuid|c277e707-67a0-14a2-099e-5b861f2480ad]]
|
||||
|
||||
|
||||
49
documentation/21.11/_others/draft/multiple-inheritance.wiki
Normal file
@@ -0,0 +1,49 @@
|
||||
[[Property:title|Multiple inheritance]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|7f54afce-fd1d-fba7-7a55-f74604ea9846]]
|
||||
<h2>Multiple inheritance: definition</h2>
|
||||
|
||||
Multiple inheritance is a mechanism for combining abstractions. It lets you define a class by extending or specializing two or more classes, not just one as in <em>single</em> inheritance. For example you might define a multi_function printer as the combination of a printer and a scanner.
|
||||
|
||||
Multiple inheritance sometimes has the reputation of being complicated or even messy, but there is no such problem in Eiffel. "Name clashes", for example, are not a big deal: if classes <eiffel>A</eiffel> and <e>B</e> both have a feature with the same name <e>f</e> and class <e>C</e> inherits from both, you can either specify that they should be merged, or keep them separate through the <e>rename</e> mechanism. Details below.
|
||||
|
||||
<h2>Multiple inheritance basics</h2>
|
||||
|
||||
Multiple inheritance happens as soon as you list more than one class in the <e>inherit</e> clause at the beginning of a class. For example:
|
||||
|
||||
<eiffel>
|
||||
class PRINTER feature
|
||||
... Here the features specific to printers ...
|
||||
end
|
||||
|
||||
class SCANNER feature
|
||||
... Here the features specific to scanners ...
|
||||
end
|
||||
|
||||
class MULTI_FUNCTION_PRINTER inherit
|
||||
PRINTER
|
||||
SCANNER
|
||||
feature
|
||||
... Here the features specific to printer-scanners ...
|
||||
end
|
||||
</eiffel>
|
||||
|
||||
As with single inheritance, the new class has access to the parent features, except that here they are features of two different parents. For example if <e>PRINTER</e> has feature <print> and <e>SCANNER</e> has features <e>scan</e> and <e>scanned</e>, then the feature clause of <e>SCANNER</e> can include
|
||||
|
||||
<code>
|
||||
scan_and_print
|
||||
-- Scan a page and print it.
|
||||
do
|
||||
scan -- Leaves result of scan in `scanned'
|
||||
print (scanned)
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
5
documentation/21.11/_others/draft/test-page.wiki
Normal file
@@ -0,0 +1,5 @@
|
||||
[[Property:title|Test page]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|6dc09e0f-b713-8c5b-799f-36a60264e8f8]]
|
||||
Test page for Book "Draft"
|
||||
|
||||
|
After Width: | Height: | Size: 59 KiB |
@@ -0,0 +1,3 @@
|
||||
title=static documentation page
|
||||
author=halw
|
||||
path=content/static-documentation-page
|
||||
186
documentation/21.11/_others/guide/index.wiki
Normal file
@@ -0,0 +1,186 @@
|
||||
[[Property:title|Guide]]
|
||||
[[Property:description|Central repository of information about Eiffel and the products and technologies of Eiffel Software]]
|
||||
[[Property:link_title|Information Guide]]
|
||||
[[Property:weight|10]]
|
||||
[[Property:uuid|68b37685-64e9-f564-9258-29e709a55f44]]
|
||||
'''Guide to Eiffel Information'''
|
||||
|
||||
These pages are the central repository of information about Eiffel and the products and technologies of Eiffel Software. They cover the online documentation, but also link to many valuable resources outside the documentation set.
|
||||
|
||||
If you are interested in [[Learning Eiffel|learning Eiffel, there is a list of resources]] dedicated to that purpose.
|
||||
|
||||
The online documentation is organized into virtual books. Each book covers an important aspect of the world of Eiffel. For cases in which it is not always possible to use the online version of the documentation, all or selected parts of the documentation set can be [[Offline use of the Eiffel documentation|downloaded for offline use]].
|
||||
|
||||
* [[Guide]] -- Guide to Eiffel Information
|
||||
* [[EiffelStudio]] -- The EiffelStudio Interactive Development Environment
|
||||
* [[Solutions]] -- Eiffel Solutions, Technologies, and Class Libraries
|
||||
* [[Platform specifics]] -- Specific support for particular platforms, e.g., Microsoft Windows
|
||||
* [[Method|Method and Language]] -- The Eiffel Method and Language
|
||||
* [[Why Eiffel?]] -- Why Eiffel?
|
||||
* [[Papers]] -- Technical and position papers relating to Eiffel and the engineering of high quality software
|
||||
* [[Examples]] -- Contributor supported examples of Eiffel solutions to common programming problems
|
||||
* [[Community]] -- Community Contributions
|
||||
<!--break-->
|
||||
Sources of information on Eiffel include:
|
||||
|
||||
==Books in the Eiffel Documentation==
|
||||
----
|
||||
|
||||
===[[Guide]] -- Guide to Eiffel Information===
|
||||
|
||||
:You are reading this book now.
|
||||
|
||||
===[[EiffelStudio]] -- The EiffelStudio Interactive Development Environment===
|
||||
|
||||
:Information about installing and using EiffelStudio
|
||||
|
||||
===[[Solutions]] -- Eiffel Solutions, Technologies, and Class Libraries===
|
||||
|
||||
:Technologies available with Eiffel provide solutions to many ordinary development needs ... and some extraordinary needs too. This book addresses these requirements and the Eiffel technologies that satisfy them.
|
||||
|
||||
===[[Platform specifics]] -- Support for particular operating systems===
|
||||
|
||||
:Although most Eiffel technology is completely platform-independent, Eiffel also provides important platform-specific solutions, described in this book.
|
||||
|
||||
===[[Method|Method and Language]] -- The Eiffel Method and Language===
|
||||
|
||||
:Materials promoting the understanding of the Eiffel software development method and the Eiffel programming language.
|
||||
|
||||
===[[Why Eiffel?]] -- Why Eiffel? ===
|
||||
|
||||
:A summary of the arguments for using Eiffel.
|
||||
|
||||
===[[Papers]] -- Technical and position papers relating to Eiffel===
|
||||
|
||||
:This book is a place for white papers which provide background, foundation, or supplemental information about the the Eiffel method and language as well as the goal of engineering high quality software.
|
||||
|
||||
===[[Examples]] -- Contributor supported examples of Eiffel solutions to common programming problems===
|
||||
|
||||
:Let's build a set of examples that can be shared on popular WWW program chrestomathies.
|
||||
|
||||
===[[Community]] -- You can contribute to the documentation!===
|
||||
|
||||
:EiffelStudio documentation is available in a convenient Wiki format. This makes it possible to improve the documentation continuously and make sure it is always up to date.
|
||||
|
||||
|
||||
|
||||
'''Community input''' is welcome. If you are interested in improving and developing EiffelStudio documentation, you can become a ''contributor'' or ''editor'':
|
||||
|
||||
* Contributors can edit existing pages in any book and add pages to Community Contributions books.
|
||||
|
||||
* Editors can modify and add pages in any book (including adding Community Contribution pages to an existing book).
|
||||
|
||||
To become a contributor, you should be proficient in Eiffel technology and have good written English skills. To become an editor, you should already have made significant improvements or additions as a contributor.
|
||||
|
||||
If you are interested in becoming a contributor, please send an email to info@eiffel.com with a short description of your Eiffel experience and any other relevant background. We look forward to your contributions!
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
==Other sources of information on Eiffel==
|
||||
|
||||
----
|
||||
|
||||
|
||||
===The [http://eiffel.com Eiffel.com] website===
|
||||
|
||||
Eiffel Software's website [http://eiffel.com Eiffel.com] contains an enormous amount of information about Eiffel. There are product descriptions, special pages for developers and their managers, case studies and testimonials, the latest Eiffel news, and much more.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===[http://eiffel.com/developers/presentations/ Web Presentations] on Eiffel.com===
|
||||
|
||||
Learn quickly about Eiffel and the things that help make it special, like Design by Contract and EiffelStudio. Learn how Eiffel fits in with and compares to other popular technologies. All this and more is available on the [http://eiffel.com/developers/presentations/ presentations page] on Eiffel.com.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===[http://eiffel.com/developers/learning_maps/ Learning Maps] on Eiffel.com===
|
||||
|
||||
Get an in-depth view of topics by navigating the [http://eiffel.com/developers/learning_maps/ Eiffel Learning Maps]. Learning maps represent knowledge as a network of interrelated concepts. Attached to the concepts you may find links to additional resources. These resources can be just about anything. You'll find plain text files, web pages, screen shots, and even Eiffel Learnlets. Learnlets are small units of learning in web presentation form that are designed to take no more than 30 minutes to view ... just right for your lunch break.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===The [http://www.eiffelroom.com/ EiffelRoom] Website===
|
||||
|
||||
[http://www.eiffelroom.com/ EiffelRoom] is an Eiffel community website on which Eiffel developers from across the globe come together and share their experiences ... and their products. You'll find how-to articles, tips and tricks, example code, whole libraries of EIffel classes, and specialized products. It is easy to contribute to EiffelRoom and start giving back to the community.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===The Eiffel Software User Group===
|
||||
|
||||
The Eiffel Software Users' Group is a focus group for those who use the products of Eiffel Software. Its primary communication vehicle is a [http://groups.eiffel.com/ collaborative discussion group]. The group mailing list is monitored by Eiffel Software developers and many highly experienced Eiffel programmers. So if you have questions or comments about Eiffel Software products, this is a good place to be.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===The EiffelWorld Newsletter===
|
||||
|
||||
A few times a year, we send out an email newsletter containing announcements of new versions of products, upcoming events, newly added technologies, website changes, editorials, and contributions from the community. To subscribe send a request to [mailto:info@eiffel.com info@eiffel.com].
|
||||
|
||||
|
||||
----
|
||||
|
||||
===[[Object-Oriented Software Construction, 2nd Edition]]===
|
||||
|
||||
There is no better place to gain an in-depth understanding of the Eiffel software development method than [[Object-Oriented Software Construction, 2nd Edition]], by Bertrand Meyer, published by Prentice Hall. It is the world's most complete guide to building great object-oriented software.
|
||||
|
||||
|
||||
----
|
||||
|
||||
===Other [[Books about the Eiffel Method and Language|books about the Eiffel Method and Language]]===
|
||||
|
||||
|
||||
----
|
||||
|
||||
===The Standard: ''Eiffel: Analysis, Design, and Programming Language''===
|
||||
|
||||
Eiffel has been standardized under ISO and ECMA. The comprehensive description of the standard Eiffel programming language is presented in [http://www.ecma-international.org/publications/standards/Ecma-367.htm Standard ECMA-367].
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
===Contribute to Eiffel===
|
||||
|
||||
You can help Eiffel by contributing your time, expertise, and products. Here are some websites that you can visit to see what's up with the development of Eiffel Software products.
|
||||
|
||||
====[http://dev.eiffel.com dev.eiffel.com]====
|
||||
|
||||
:This [http://dev.eiffel.com wiki site] is the hub of development activity for the EiffelStudio interactive development environment. Even if you do not plan to contribute, dev.eiffel.com is a valuable source of information concerning where EiffelStudio is going ... and, if you're curious, where it has been.
|
||||
|
||||
====[http://eiffelstudio.origo.ethz.ch/ EiffelStudio on Origo]====
|
||||
|
||||
:[http://eiffelstudio.origo.ethz.ch/ EiffelStudio on Origo] contains blogs and forums focusing on Eiffel and EiffelStudio topics.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----
|
||||
|
||||
==[[uuid:b8c10baa-4f50-adfe-a6f8-9cb56a8f1917|Glossary of Object Technology]]==
|
||||
|
||||
----
|
||||
|
||||
|
||||
This is a relatively comprehensive glossary of terms used in Object-Oriented Analysis, Design, and programming, but are not specific to the Eiffel Language, since object-oriented principles can be applied to any programming language. It contains all the terms from the glossary in [[Object-Oriented Software Construction, 2nd Edition]], plus others used in this website, added for clarity and ease of reference.
|
||||
|
||||
This glossary is useful all by itself, since a review of it can serve as a refresher (in case you have been away from Object Technology for a while). It is used in this website to assist the reader by providing easy links to technical terms that are used throughout the website.
|
||||
|
||||
Additionally, it is possible to link to terms in this glossary from other websites by using links that look like this:
|
||||
|
||||
:<nowiki>http://docs.eiffel.com/book/guide/glossary-object-technology#Attribute</nowiki>
|
||||
|
||||
or a version that will survive the page being moved:
|
||||
|
||||
:<nowiki>http://docs.eiffel.com/isedoc/uuid/b8c10baa-4f50-adfe-a6f8-9cb56a8f1917#Attribute</nowiki>
|
||||
|
||||
Note that the anchor (the part after the "#") has to be spelled and capitalized exactly like the term on the page. (Use underscore characters to replace spaces.)
|
||||
|
||||
----
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
[[Property:title|Offline use of the Eiffel Documentation]]
|
||||
[[Property:link_title|Download Documentation]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|e5f003f6-c732-c648-fd67-91f6642130f0]]
|
||||
It is possible to download the books of the Eiffel online documentation for viewing offline with a web browser.
|
||||
|
||||
To do this you use a [http://docs.eiffel.com/static/ web page] which has links to downloadable files that contain copies of the documentation in different forms and quantities.
|
||||
|
||||
|
||||
[[Image:static documentation page|Downloadable documentation]]
|
||||
|
||||
|
||||
The files are ".7z" files, meaning that they are compressed archives in [http://www.7-zip.org 7-zip] format. So, you can use any 7-zip compatible expander to unpack the files.
|
||||
|
||||
You'll notice that the options for downloading come in three groups:
|
||||
|
||||
# HTML: Multiple pages per book.
|
||||
# HTML: One big page per book.
|
||||
# WikiText+meta: raw files containing wikitext (backup)
|
||||
|
||||
You should choose your files from one of the HTML options (the WikiText option is used for backup).
|
||||
|
||||
It is possible also to download one documentation "book" at a time, or to download all books in one archive.
|
||||
|
||||
The files are static copies of the content of the online documentation, as reflected by the dates shown on the web page.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
11
documentation/21.11/_others/why-eiffel/index.wiki
Normal file
@@ -0,0 +1,11 @@
|
||||
[[Property:title|Why Eiffel?]]
|
||||
[[Property:description|arguments for using Eiffel]]
|
||||
[[Property:weight|11]]
|
||||
[[Property:uuid|df007537-c0dd-2ea6-233b-764ad483eb65]]
|
||||
This book collects arguments for using Eiffel.
|
||||
|
||||
Even though we in the Eiffel community know that Eiffel is the most advanced object-oriented software development framework on this planet, that fact may not be so obvious to everyone else. Consequently, we felt that it would be helpful to provide some brief documents that spell out the reasons why the people who have chosen Eiffel have been so successful.
|
||||
|
||||
You may find the information helpful if you are simply curious about Eiffel, if you are actively looking for a better development framework, or if you are busy trying to convince others to try Eiffel.
|
||||
|
||||
|
||||
1
documentation/21.11/_templates/Beta.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl header-message">[[Image:LogoBeta|24px]] '''Beta documentation:''' [[How to contribute to documentation#Beta|see definition]].</p>
|
||||
3
documentation/21.11/_templates/Beta.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Beta
|
||||
author=vwheeler
|
||||
path=content/beta
|
||||
2
documentation/21.11/_templates/Caution.tpl
Normal file
@@ -0,0 +1,2 @@
|
||||
<p style="margin-left: 10px; margin-right: 50px; border: 1px solid #FFB55F; padding: 10px; background-color: #FFEEBF; color: black;">[[Image:LogoWarning|24px]] '''Caution:''' {{{1}}}</p>
|
||||
|
||||
3
documentation/21.11/_templates/Caution.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Caution
|
||||
author=admin
|
||||
path=content/caution-0
|
||||
1
documentation/21.11/_templates/Info.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl info-message">[[Image:LogoInformation|24px]] '''Info: '''{{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Info.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Info
|
||||
author=admin
|
||||
path=content/info
|
||||
1
documentation/21.11/_templates/Inline-Error.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<span class="tpl error-message">{{{1}}}</span>
|
||||
1
documentation/21.11/_templates/Inline-Info.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<span class="tpl info-message">{{{1}}}</span>
|
||||
1
documentation/21.11/_templates/Inline-Success.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<span class="tpl success-message">{{{1}}}</span>
|
||||
1
documentation/21.11/_templates/Inline-Warning.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<span class="tpl warning-message">{{{1}}}</span>
|
||||
1
documentation/21.11/_templates/Key.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<span class="tpl key-message">{{{1}}}</span>
|
||||
3
documentation/21.11/_templates/Key.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Key
|
||||
author=admin
|
||||
path=content/key
|
||||
1
documentation/21.11/_templates/Note.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl note-message">[[Image:LogoInformation|24px]] '''Note: '''{{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Note.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Note
|
||||
author=admin
|
||||
path=content/note
|
||||
1
documentation/21.11/_templates/Recommended.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl recommended-message">[[Image:LogoRecommended|24px]] '''Recommended: '''{{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Recommended.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Recommended
|
||||
author=admin
|
||||
path=content/recommended
|
||||
1
documentation/21.11/_templates/ReviewRequested.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl header-message" style="background-color: #FFFFFF; border-color: black">[[Image:LogoReviewRequested|24px]] '''Review requested: ''' [[How to contribute to documentation#ReviewRequested|see definition]].</p>
|
||||
3
documentation/21.11/_templates/ReviewRequested.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=ReviewRequested
|
||||
author=vwheeler
|
||||
path=content/reviewrequested
|
||||
1
documentation/21.11/_templates/Rule.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl rule-message">[[Image:LogoRule|24px]] '''Rule -- {{{name}}}:''' {{{text}}}</p>
|
||||
3
documentation/21.11/_templates/Rule.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Rule
|
||||
author=halw
|
||||
path=content/rule
|
||||
1
documentation/21.11/_templates/Sample.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl sample-message">[[Image:LogoInformation|24px]] '''Sample:''' {{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Sample.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Sample
|
||||
author=admin
|
||||
path=content/sample
|
||||
1
documentation/21.11/_templates/SeeAlso.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl seealso-message">[[Image:LogoInformation|24px]] '''See Also:''' {{{1}}}</p>
|
||||
3
documentation/21.11/_templates/SeeAlso.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=SeeAlso
|
||||
author=admin
|
||||
path=content/seealso
|
||||
1
documentation/21.11/_templates/Tip.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl tip-message">[[Image:LogoInformation|24px]] '''Tip: '''{{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Tip.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Tip
|
||||
author=admin
|
||||
path=content/tip
|
||||
1
documentation/21.11/_templates/UnderConstruction.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl header-message">[[Image:LogoConstruction|24px]] '''Under construction:''' [[How to contribute to documentation#UnderConstruction|see definition]].</p>
|
||||
@@ -0,0 +1,3 @@
|
||||
title=UnderConstruction
|
||||
author=vwheeler
|
||||
path=content/underconstruction
|
||||
1
documentation/21.11/_templates/UpdateNeeded.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl header-message">[[Image:LogoUpdateNeeded|24px]] '''Update Needed:''' [[How to contribute to documentation#UpdateNeeded|see definition]].</p>
|
||||
3
documentation/21.11/_templates/UpdateNeeded.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=UpdateNeeded
|
||||
author=vwheeler
|
||||
path=content/updateneeded
|
||||
1
documentation/21.11/_templates/Warning.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl warning-message">[[Image:LogoWarning|24px]] '''Warning:''' {{{1}}}</p>
|
||||
3
documentation/21.11/_templates/Warning.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=Warning
|
||||
author=admin
|
||||
path=content/warning
|
||||
1
documentation/21.11/_templates/definition.tpl
Normal file
@@ -0,0 +1 @@
|
||||
<p class="tpl definition-message">[[Image:LogoDefinition|24px]] '''Definition -- {{{1}}}''': {{{2}}}</p>
|
||||
3
documentation/21.11/_templates/definition.tpl.data
Normal file
@@ -0,0 +1,3 @@
|
||||
title=definition
|
||||
author=halw
|
||||
path=content/definition
|
||||
44
documentation/21.11/contribute/documentation.wiki
Normal file
@@ -0,0 +1,44 @@
|
||||
[[Property:title|How to contribute to documentation]]
|
||||
[[Property:link_title|To documentation]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:uuid|A2DED192-B50A-4E59-B214-FDC3FEDC7A44]]
|
||||
|
||||
= Current documentation system =
|
||||
* The documentation is written using wikitext syntax (similar to wikipedia).
|
||||
* Each documentation page is stored in a wiki file on disk.
|
||||
* Those files come from the subversion repository: [https://svn.eiffel.com/eiffel-org/trunk/documentation/trunk] .
|
||||
* The outline of book are following the underlying directory structure, and each wiki file can have properties that hold metadata such as:
|
||||
<code>
|
||||
[[Property:title|The page title]]
|
||||
[[Property:link_title|short title]]
|
||||
[[Property:weight|5]]
|
||||
</code>
|
||||
** '''link_title''' is used to have a short title in menu, or various links.
|
||||
** '''weight''' is used to order sibling pages (lower weight goes before, upper weight goes after).
|
||||
|
||||
= To contribute =
|
||||
* First, you can post comment on any page (see comment form at the bottom of each page).
|
||||
* As one would contribute to any source maintained on a subversion repository, one can contribute via the repository [https://svn.eiffel.com/eiffel-org/trunk/documentation/trunk/] and provide patch.
|
||||
* Note there is also a git mirror at [https://github.com/eiffelsoftware/eiffel-org] so you can also contribute via github by sending pull request.
|
||||
|
||||
= Step by step with git =
|
||||
* Go to [https://github.com/eiffelsoftware/eiffel-org] for the project, then git clone on your machine.
|
||||
* create a git branch.
|
||||
* add or edit the files locally.
|
||||
* once you want to share your changes.
|
||||
** git commit your changes.
|
||||
** git push them to your github repository.
|
||||
** then create a pull request so that the Eiffel.org documentation team can review and integrate the changes.
|
||||
* See current pull requests at [https://github.com/EiffelSoftware/eiffel-org/pulls].
|
||||
|
||||
= Step by step with subversion =
|
||||
* <code>svn checkout https://svn.eiffel.com/eiffel-org/trunk/documentation/trunk/</code>.
|
||||
* add or edit the files locally.
|
||||
* once you want to share your changes.
|
||||
** svn update.
|
||||
** Send the patch via [https://codereview.appspot.com/]. (note: follow the instructions from codereview site, you will need to use a python script "upload.py" distributed by the codereview site).
|
||||
* See current patches at [https://codereview.appspot.com/search?base=https://svn.eiffel.com/eiffel-org/trunk/documentation/trunk/].
|
||||
|
||||
= Live editing on this site =
|
||||
* If you are a trusted editor, you can edit the documentation directly.
|
||||
* To be a trusted editor, please request it via the [https://www.eiffel.org/contact contact] page (do not forget to mention who you are and why you think you should be a trusted editor).
|
||||
123
documentation/21.11/contribute/editing_help.wiki
Normal file
@@ -0,0 +1,123 @@
|
||||
[[Property:title|Help to edit documentation]]
|
||||
[[Property:link_title|Editing help]]
|
||||
[[Property:weight|3]]
|
||||
|
||||
= Wikitext syntax =
|
||||
* Have a look at [https://en.wikipedia.org/wiki/Help:Wiki_markup Wikipedia markup] documentation.
|
||||
* The current website does not support the full Wikipedia syntax, but still most of the needed cases.
|
||||
|
||||
* To embed inline code:
|
||||
** `` `foo.bar` ``
|
||||
** `<code>foo.bar</code>`
|
||||
** `<eiffel>foo.bar</eiffel>`
|
||||
|
||||
* To embed block code:
|
||||
|
||||
```xml
|
||||
<code lang="eiffel">
|
||||
class FOOBAR
|
||||
</code>
|
||||
```
|
||||
|
||||
```xml
|
||||
<eiffel>
|
||||
class FOOBAR
|
||||
</eiffel>
|
||||
```
|
||||
|
||||
<code lang="text">
|
||||
```eiffel
|
||||
class FOOBAR
|
||||
```
|
||||
</code>
|
||||
|
||||
Note: if you do not specify the lang, it is defaulted to "eiffel"
|
||||
|
||||
|
||||
|
||||
= Templates =
|
||||
== Top page templates ==
|
||||
Used to qualify the current page.
|
||||
|
||||
=== ReviewRequested ===
|
||||
:<nowiki>{{ReviewRequested|This is a ReviewRequested message}}</nowiki>
|
||||
{{ReviewRequested|This is a ReviewRequested message}}
|
||||
|
||||
=== UnderConstruction ===
|
||||
:<nowiki>{{UnderConstruction|This is a UnderConstruction message}}</nowiki>
|
||||
{{UnderConstruction|This is a UnderConstruction message}}
|
||||
|
||||
=== UpdateNeeded ===
|
||||
:<nowiki>{{UpdateNeeded|This is a UpdateNeeded message}}</nowiki>
|
||||
{{UpdateNeeded|This is a UpdateNeeded message}}
|
||||
|
||||
=== Beta ===
|
||||
:<nowiki>{{Beta|This is a beta message}}</nowiki>
|
||||
{{Beta|This is a beta message}}
|
||||
|
||||
|
||||
== Block templates ==
|
||||
=== Caution ===
|
||||
:<nowiki>{{Caution|This is a caution message}}</nowiki>
|
||||
{{Caution|This is a caution message}}
|
||||
|
||||
=== Definition ===
|
||||
:<nowiki>{{Definition|abc|This is a Definition message}}</nowiki>
|
||||
{{Definition|abc|This is a Definition message}}
|
||||
|
||||
=== Info ===
|
||||
:<nowiki>{{Info|This is a Info message}}</nowiki>
|
||||
{{Info|This is a Info message}}
|
||||
|
||||
|
||||
=== Note ===
|
||||
:<nowiki>{{Note|This is a Note message}}</nowiki>
|
||||
{{Note|This is a Note message}}
|
||||
|
||||
=== Recommended ===
|
||||
:<nowiki>{{Recommended|This is a Recommended message}}</nowiki>
|
||||
{{Recommended|This is a Recommended message}}
|
||||
|
||||
=== Rule ===
|
||||
:<nowiki>{{Rule|name=abc|text=This is a Rule message}}</nowiki>
|
||||
{{Rule|name=abc|text=This is a Rule message}}
|
||||
|
||||
=== Sample ===
|
||||
:<nowiki>{{Sample|This is a Sample message}}</nowiki>
|
||||
{{Sample|This is a Sample message}}
|
||||
|
||||
=== SeeAlso ===
|
||||
:<nowiki>{{SeeAlso|This is a SeeAlso message}}</nowiki>
|
||||
{{SeeAlso|This is a SeeAlso message}}
|
||||
|
||||
=== Tip ===
|
||||
:<nowiki>{{Tip|This is a Tip message}}</nowiki>
|
||||
{{Tip|This is a Tip message}}
|
||||
|
||||
=== Warning ===
|
||||
:<nowiki>{{Warning|This is a Warning message}}</nowiki>
|
||||
{{Warning|This is a Warning message}}
|
||||
|
||||
|
||||
== Inline templates ==
|
||||
|
||||
=== Key ===
|
||||
:<nowiki>This is a {{Key|key message}} in the text. </nowiki>
|
||||
This is a {{Key|key message}} in the text.
|
||||
|
||||
=== Error ===
|
||||
:<nowiki>This is a {{Inline-Error|error message}} in the text. </nowiki>
|
||||
This is a {{Inline-Error|error message}} in the text.
|
||||
|
||||
=== Info ===
|
||||
:<nowiki>This is a {{Inline-Info|info message}} in the text. </nowiki>
|
||||
This is a {{Inline-Info|info message}} in the text.
|
||||
|
||||
=== Success ===
|
||||
:<nowiki>This is a {{Inline-Success|success message}} in the text. </nowiki>
|
||||
This is a {{Inline-Success|success message}} in the text.
|
||||
|
||||
=== Warning ===
|
||||
:<nowiki>This is a {{Inline-Warning|warning message}} in the text. </nowiki>
|
||||
This is a {{Inline-Warning|warning message}} in the text.
|
||||
|
||||
10
documentation/21.11/contribute/index.wiki
Normal file
@@ -0,0 +1,10 @@
|
||||
[[Property:title|How to contribute]]
|
||||
[[Property:description|How to contribute]]
|
||||
[[Property:link_title|Contribute]]
|
||||
[[Property:weight|6]]
|
||||
[[Property:uuid|56480505-4CD5-4C8A-AA3D-120FD573DFA9]]
|
||||
|
||||
= How to contribute to Eiffel ? =
|
||||
|
||||
Check page [https://www.eiffel.org/contribute] .
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
[[Property:modification_date|Fri, 04 Jan 2019 15:06:26 GMT]]
|
||||
[[Property:publication_date|Thu, 03 Jan 2019 18:00:43 GMT]]
|
||||
[[Property:uuid|146E241E-C367-4F16-9CCE-6F11E5F7860A]]
|
||||
[[Property:weight|1]]
|
||||
[[Property:title|Eiffel Code Comments]]
|
||||
|
||||
==Comment Mark Up ==
|
||||
The Eiffel compiler and EiffelStudio's code browsing tools support a special, light-weight mark up in comments and strings for referencing classes and features. EiffelStudio's code browsing tools use this mark up to better facilitate code navigation and browsing. In addition, marked up comments and strings will be examined and altered when performing a class or feature ''rename'' refactoring.
|
||||
|
||||
===Syntax===
|
||||
The syntax for marking up classes and features is very compact, to ensure retained legibility. You'll see no need for XML or other types of verbose mark up found in other languages, which can impede the comment's very nature as a quick reference.
|
||||
|
||||
To mark up a class reference, surround the class name in an open (` { `) and matching closing (` } `) brace:
|
||||
|
||||
<e>
|
||||
-- See {DEBUG_OUTPUT} for more information.
|
||||
</e>
|
||||
|
||||
To mark up a feature reference, implemented in the same class or parent, surround the name with two single back quotes (`` `...` ``):
|
||||
|
||||
<e>
|
||||
-- See `debug_output` for more information.
|
||||
</e>
|
||||
|
||||
The earlier convention, which you will still find in much existing code, used a single back quote for opening and a matching normal quote for closing, as in
|
||||
|
||||
<e>
|
||||
-- See `debug_output' for more information.
|
||||
</e>
|
||||
|
||||
The new convention, with back quotes both for opening and for closing, is the recommended one.
|
||||
|
||||
|
||||
In the case where a reference to a feature is not accessible to the containing class directly, use a combination of the class reference mark up and a feature name, ''sans'' quotation marks:
|
||||
|
||||
<e>
|
||||
-- See {DEBUG_OUTPUT}.debug_output for more information.
|
||||
</e>
|
||||
|
||||
The rules that apply for comments, as described above, can also be utilized in any manifest or verbatim string:
|
||||
|
||||
<e>
|
||||
note
|
||||
description: "Augments searching facilities of {STRING_8}"
|
||||
</e>
|
||||
|
||||
==Precursor Comments==
|
||||
|
||||
{{Version|6.2}}
|
||||
|
||||
Precursor comments declarations are a new mechanism added to EiffelStudio 6.2 to replicate a parent feature declaration's comments in the redefined/effective feature. The purpose of the mechanism is to reduce comment duplication, ease comment maintenance and facilitate augmentation.
|
||||
|
||||
For the purpose of demonstration, take the following deferred interface:
|
||||
<e>
|
||||
deferred class
|
||||
BASE
|
||||
|
||||
feature -- Query
|
||||
|
||||
test (a_arg: INTEGER): BOOLEAN
|
||||
-- Comments for a feature.
|
||||
--
|
||||
-- `a_arg`: An integer value.
|
||||
-- `Result`: Could be True or False.
|
||||
deferred
|
||||
end
|
||||
|
||||
end
|
||||
</e>
|
||||
|
||||
And effective implementation of it:
|
||||
|
||||
<e>
|
||||
class
|
||||
TEST
|
||||
|
||||
inherit
|
||||
BASE
|
||||
|
||||
feature -- Query
|
||||
|
||||
test (a_arg: INTEGER): BOOLEAN
|
||||
-- <Precursor>
|
||||
do
|
||||
end
|
||||
|
||||
end
|
||||
</e>
|
||||
|
||||
<e>TEST</e> instead of replicating the comment makes use of the precursor comment declaration (<e>-- <Precursor></e>), which supporting code browsing tool will expand to show the precursor feature's contracts. The declaration is optional but is only supported for existing code out there that do not have comments due to lax implementation. Even though optional, it is strongly recommended that you use <e>-- <Precursor></e> comment declaration, as it indicates to any reader the feature is a redefinition or effective implementation of a parent feature declaration.
|
||||
|
||||
=== Comment Augmentation ===
|
||||
The precursor comments declaration also supports augmentation. All a comment author has to do is to write additional comments before and/or after the precursor comment declaration. As a requirement, the precursor comment declaration must appear on a separate line for no other purpose except for clarity. Failure to do so will results in the rendering of the comments as they are declared in the feature, i.e. with <e>-- <Precursor></e> as is.
|
||||
|
||||
<e>
|
||||
test (a_arg: INTEGER): BOOLEAN
|
||||
-- Comments before the original comments from {BASE}.
|
||||
--
|
||||
-- <Precursor>
|
||||
--
|
||||
-- Some additional comments.
|
||||
do
|
||||
end
|
||||
</e>
|
||||
|
||||
Using the code browsing facilities of [[EiffelStudio]] the reader will be presented with an expanded comment, for the effective version of feature <e>test</e>, that now read
|
||||
|
||||
<e>
|
||||
-- Comments before the original comments from {BASE}.
|
||||
--
|
||||
-- Comments for a feature.
|
||||
--
|
||||
-- `a_arg`: An integer value.
|
||||
-- `Result`: Could be True or False.
|
||||
--
|
||||
-- Some additional comments.
|
||||
</e>
|
||||
|
||||
For clarity it is a good idea to separate the agumented comments from the precursor comment declaration. Using the same example above but removing the one line spacing above and below the precursor comment declaration would results in the following, less readable comment:
|
||||
|
||||
<e>
|
||||
-- Comments before the original comments from {BASE}.
|
||||
-- Comments for a feature.
|
||||
--
|
||||
-- `a_arg`: An integer value.
|
||||
-- `Result`: Could be True or False.
|
||||
-- Some additional comments.
|
||||
</e>
|
||||
|
||||
However, that said, it is pure discretion to use additional spacing or not. Some situation do not call for, other do and some might (when the original comment changes.)
|
||||
|
||||
=== Multiple Redefinitions and Selection ===
|
||||
With Eiffel supporting multiple inheritance, a scenario will arise where two inherited redefine features are joined in a descendant.
|
||||
|
||||
By default the precursor comment declaration is replaced by the first located inherited feature comment, which may cause documentation irregularities. Because precursor comments are not signification to compilation they are not checked during compilation, such as is the way with the use of <e>Precursor</e>, resulting a compile time error when not selecting the parent class to call into. This can cause documentation irregularities because there is no guarantee that they feature comments viewed one project will be the same in another.
|
||||
|
||||
To facilitate correct documentation the precursor comment declaration can use an optional select clause, just like using <e>Precursor</e> in the Eiffel code.
|
||||
|
||||
<e>
|
||||
f (a_arg: INTEGER): BOOLEAN
|
||||
-- <Precursor {BASE}>
|
||||
do
|
||||
end
|
||||
</e>
|
||||
|
||||
This will have exactly the same effect as using <e>-- <Precursor></e> when <e>f</e> is made effective/redefined from a single parent. However, when making effective/redefining from multiple parents then comments will come from the parent class declaration in <e>BASE</e>.
|
||||
|
||||
Again, because precursor comments do not affect compilation they are not checked at compile time. Specifying an incorrect class will yield a warning message in [[EiffelStudio]]'s code browsing tools, to the effect:
|
||||
|
||||
<e>
|
||||
-- Unable to retrieve the comments from redefinition of {CLASS_NAME}.
|
||||
</e>
|
||||
|
||||
=== Library Documentation Generation ===
|
||||
Precursor comments are supported in all code browsing/documentation facilities, whether is be the integrated [[Contract Viewer]], the [[Feature Relation Tool]] or the Eiffel documentation generation facilities. Using <e>-- <Precursor></e> will ensure the comments are brought up from a parent declaration.
|
||||
@@ -0,0 +1,93 @@
|
||||
[[Property:modification_date|Mon, 03 Dec 2018 10:00:43 GMT]]
|
||||
[[Property:publication_date|Tue, 30 Oct 2018 14:56:21 GMT]]
|
||||
[[Property:uuid|0CD0A1B2-42F8-48E0-B419-61B4DC076C1B]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:title|Eiffel Coding Standard]]
|
||||
|
||||
==Language consideration==
|
||||
* Do not put a blank line between
|
||||
:* '''create''' and creation instructions
|
||||
:* '''inherit''' and parent clauses
|
||||
* Do not use assertion clauses without tag names.
|
||||
|
||||
A sample of proper formatting of code:
|
||||
<e>note
|
||||
description: "Descr...."
|
||||
date: "$date: $"
|
||||
|
||||
class A
|
||||
|
||||
inherit
|
||||
B
|
||||
rename
|
||||
f as g
|
||||
end
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make (a: INTEGER)
|
||||
-- Initialize Current with `a`.
|
||||
do
|
||||
end
|
||||
|
||||
invariant
|
||||
a_positive: a > 0
|
||||
|
||||
end</e>
|
||||
|
||||
==Style==
|
||||
* If instructions:
|
||||
<e>if expr1 then
|
||||
...
|
||||
elseif expr2 then
|
||||
...
|
||||
else
|
||||
...
|
||||
end</e>
|
||||
|
||||
If expressions are very long, break them on conjunctions as in:
|
||||
<e>if
|
||||
expr1 and then
|
||||
expr2
|
||||
then
|
||||
...
|
||||
end</e>
|
||||
|
||||
* Loop instructions:
|
||||
<e>from
|
||||
...
|
||||
until
|
||||
...
|
||||
loop
|
||||
...
|
||||
end</e>
|
||||
|
||||
* Inspect instructions:
|
||||
<e>inspect expr
|
||||
when val1 then ....
|
||||
else
|
||||
...
|
||||
end</e>
|
||||
|
||||
or
|
||||
|
||||
<e>inspect
|
||||
expr
|
||||
when val1 then
|
||||
...
|
||||
else
|
||||
...
|
||||
end</e>
|
||||
|
||||
* For punctuation, we always have
|
||||
** a space before, and no after `(`
|
||||
** no space before, and space after `)` `,` `:` or `;`
|
||||
|
||||
<e>require
|
||||
a_tag: query (a, b, c) or other_query (c, d)
|
||||
local
|
||||
i: INTEGER; j: INTEGER
|
||||
</e>
|
||||
@@ -0,0 +1,236 @@
|
||||
[[Property:uuid|FF8DA311-55E5-4314-8B0C-AADB4645E686]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:title|Local Declaration Guidelines]]
|
||||
|
||||
Local declaration style guidelines for contributing to the Eiffel Software code repository.
|
||||
|
||||
== Feature Arguments ==
|
||||
Feature arguments should begin with the prefix ''<e>a_</e>'' and nothing more. The prefix ''<e>a_</e>'' represent a contraction of the word ''argument'' and does not represent the singular inflection - a ''noun'' - Therefore it is '''not''' valid to utilize ''an'' when the suffixed argument word begins with a vowel. The following is a correct usage:
|
||||
|
||||
<e>
|
||||
perform (a_string: STRING; a_integer: STRING): CHARACTER
|
||||
-- An example using routine argument variable names.
|
||||
do
|
||||
end
|
||||
</e>
|
||||
|
||||
Here, the second argument ''<e>a_integer</e>'', is not considered ''A Integer'' but ''The Argument Integer'', hence the use if <e>a_</e> instead of ''<e>_an_</e>''.
|
||||
|
||||
=== Indexing Routine Argument Variable Names ===
|
||||
In rare cases there is a need to use the same name on a routine's arguments, which of course no useful language would allow. Instead a slight form of indexing needs to be applied. In this case the use of ''<e>other</e>'' embedded in the variable name would suffice for most cases.
|
||||
|
||||
<e>
|
||||
compare_strings (a_string: READABLE_STRING_GENERAL; a_other_string: like a_string): INTEGER_8
|
||||
-- An example using 'other' to index the second routine argument name
|
||||
do
|
||||
...
|
||||
end
|
||||
</e>
|
||||
|
||||
=== In-line Agent Routine Arguments ===
|
||||
When working with an in-line agent, to prevent conflicts with the enclosing routine's arguments, the prefix ''<e>ia_</e>'' should be used. The same rules regarding English language rules apply here as they do to routine arguments. The ''<e>ia_</e>'' prefix represents an ''In-line Argument''.
|
||||
|
||||
<e>
|
||||
perform (a_string: STRING; a_integer: STRING)
|
||||
-- An example using in-line agent argument variable names.
|
||||
do
|
||||
process (agent (ia_string: STRING; ia_integer: INTEGER)
|
||||
do
|
||||
...
|
||||
end (a_string, a_integer))
|
||||
end
|
||||
</e>
|
||||
|
||||
==== Nested In-line Agent Routine Arguments ====
|
||||
Although rare, a nested in-line agents need exists. When dealing with nested in-line agent routine argument names the prefix should contain the nested index, with the container in-line agent using either a ''1'' or no index in the prefix names. First/Top-level in-line agents (those that are not nested) can use the aforementioned ''<e>ia_</e>'' prefix or use ''<e>i1a_</e>'', the former being preferred. A second-level (first nested level) in-line agent should use the prefix ''<e>i2a_</e>'', third-level ''<e>i3a_</e>'' and so forth.
|
||||
|
||||
<e>
|
||||
perform (a_string: STRING; a_integer: STRING)
|
||||
-- An example using in-line agent argument variable names.
|
||||
do
|
||||
process (agent (ia_string: STRING; ia_integer: INTEGER)
|
||||
do
|
||||
-- An example of an nested, in-line agent
|
||||
process (agent (i2a_string: STRING; i2a_integer: INTEGER)
|
||||
do
|
||||
....
|
||||
end (ia_string.as_lower, ia_integer)
|
||||
end (a_string, a_integer))
|
||||
end
|
||||
</e>
|
||||
|
||||
== Local Declarations ==
|
||||
Routine local declaration should also be prefixed to prevent potential conflicts between routine arguments or class attributes. The prefix ''<e>l_</e>'' is typically used for variable moniker names longer than two character. There are other exceptions, these are discussed below.
|
||||
|
||||
=== Well Known Variable Names ===
|
||||
Indexing/counter variables, as used in iteration loops, should not use a local prefix and should be terse. The variable ''<e>i</e>'' should be use to indicate it is an index variable. Additional index variables should follow alphabetically from ''<e>i</e>'' onwards.
|
||||
|
||||
Generally, paired with an indexing/counter variable, a stopping condition count or number-of-items variable is also used. There are two conventions used for this, generally used interchangeably; A count will use the same rules for local declarations and be called ''<e>l_count</e>'', a number-of-items variable will use a well-known contracted variable name '<e>nb</e>''.
|
||||
|
||||
<e>
|
||||
perform (a_array: ARRAY [INTEGER])
|
||||
-- An example using index and number-of-items local variable names.
|
||||
local
|
||||
i, nb: INTEGER
|
||||
do
|
||||
from
|
||||
i := a_array.lower
|
||||
nb := a_array.upper
|
||||
until
|
||||
i > nb
|
||||
loop
|
||||
...
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
</e>
|
||||
|
||||
The case will commonly arise when multiple counters/number-of-items variables need to be used. In such cases the counter/number-of-items variable should be suffixed with the associated indexing/counter variable name. This is akin to [http://en.wikipedia.org/wiki/BASIC BASIC]'s <code>NEXT x</code> instruction:
|
||||
|
||||
<e>
|
||||
perform (a_array: ARRAY [ARRAY [INTEGER]])
|
||||
-- An example using multiple index and number-of-items local variable names.
|
||||
local
|
||||
l_sub_array: ARRAY [INTEGER]
|
||||
i, nb_i: INTEGER
|
||||
j, nb_j: INTEGER
|
||||
do
|
||||
from
|
||||
i := a_array.lower
|
||||
nb_i := a_array.upper
|
||||
until
|
||||
i > nb_i
|
||||
loop
|
||||
l_item := a_array[i]
|
||||
if l_item /= Void then
|
||||
from
|
||||
j := l_item.lower
|
||||
nb_j := l_item.upper
|
||||
until
|
||||
j > nb_j
|
||||
loop
|
||||
...
|
||||
j := j + 1
|
||||
end
|
||||
end
|
||||
i := i + 1
|
||||
end
|
||||
end
|
||||
</e>
|
||||
|
||||
==== Other Well-Known Names ====
|
||||
|
||||
There are a number of other well know and simpler to use local variable names:
|
||||
|
||||
* ''<e>c</e>'' for any type of character.
|
||||
* ''<e>e</e>'' for any type of exception (descendant of EXCEPTION).
|
||||
* ''<e>s</e>'' for any type of string (descendant of READABLE_STRING_GENERAL).
|
||||
* ''<e>uc</e>'' for a Unicode character.
|
||||
* ''<e>us</e>'' for a Unicode string (descendant of READABLE_STRING_32).
|
||||
* ''<e>nb</e>'' for a number or count of elements.
|
||||
|
||||
==== Rescue Clauses ====
|
||||
|
||||
When adding a rescue clause with a retry a state variable, typically used to determine if a <e>retry</e> has been performed, there is no need to use a local declaration prefix. In fact, it's recommended there is no prefix. Instead just use a variable named ''<e>retried</e>'':
|
||||
|
||||
<e>
|
||||
perform
|
||||
-- An example using a rescue/retry local variable name.
|
||||
local
|
||||
retried: BOOLEAN
|
||||
do
|
||||
if not retried then
|
||||
...
|
||||
end
|
||||
rescue
|
||||
retried := True
|
||||
retry
|
||||
end
|
||||
</e>
|
||||
|
||||
=== Object Tests ===
|
||||
Object test locals obey the same rules and other standard local declarations, that it, prefixing a variable moniker with ''<e>l_</e>''. However, due to the current scoping rules of object-tests, where no object test local may be reused, extraneous guidelines need to be defined.
|
||||
|
||||
<e>
|
||||
close
|
||||
-- An example using object-test scoped local variable names.
|
||||
do
|
||||
if attached {DISPOSABLE_I} Current as l_disposable then
|
||||
l_disposable.dispose
|
||||
end
|
||||
end
|
||||
</e>
|
||||
|
||||
==== In Contracts ====
|
||||
Object tests may need to be defined in contracts, especially when projects/libraries are configured to use Void-Safe compilation checks. To prevent variable name conflicts from arising a secondary prefix should be used to define an object-test local. Again using ''<e>l_</e>'' but this time prefixed with the first character of the enclosing assertion clause. Such rules would dictated the following prefixes to be used in object-tests, for assertion clauses:
|
||||
* ''<e>rl_</e>'' for <e>require</e>
|
||||
* ''<e>el_</e>'' for <e>ensure</e>
|
||||
* ''<e>cl_</e>'' for <e>check</e>
|
||||
* ''<e>ll_</e>'' for <e>loop</e>
|
||||
* ''<e>il_</e>'' for loop <e>invariant</e>
|
||||
* ''<e>vl_</e>'' for loop <e>variant</e>
|
||||
|
||||
<e>
|
||||
close
|
||||
-- An example using object-test scoped local variable names in contracts.
|
||||
require
|
||||
is_interface_usable: attached {USABLE_I} Current as rl_usable implies rl_usable.is_interface_usable
|
||||
do
|
||||
...
|
||||
ensure
|
||||
not_is_interface_usable: attached {USABLE_I} Current as el_usable implies not el_usable.is_interface_usable
|
||||
end
|
||||
</e>
|
||||
|
||||
No prefix, other than ''<e>l_</e>'' is needed for class invariants because no conflicts in variable name reuse exist in an invariant scope.
|
||||
|
||||
=== In-line Agents ===
|
||||
There is no real preferred convention for local declaration inside in-line agents and the ''<e>l_</e>'' prefix should be used if possible. However, for clarity this cannot always be such the case. When such as scenario arises the use of ''<e>il_</e>'' (in-line local) is preferred. It is recommended that all locals utilize the same prefix and '''not''' mix ''<e>l_</e>'' and <e>il_</e>''!
|
||||
|
||||
<e>
|
||||
l_action := agent (ia_string: READABLE_STRING_GENERAL)
|
||||
local
|
||||
il_i, il_count: INTEGER
|
||||
do
|
||||
....
|
||||
end
|
||||
</e>
|
||||
|
||||
Notice that even well-known local declaration names are prefixed, this is to avoid conflicts with the containing routine or in-line agent as well as providing consistency in the naming of local variables.
|
||||
|
||||
With nested in-line agents use the same name index injection guideline, placing the nested index after the initial ''<e>i</e>'' prefix. For a second level in-line agent, this would be ''<e>i2l_</e>''.
|
||||
|
||||
== Indexing Variable Names ==
|
||||
There will be times when variable names clash with one another and there is no choice but to apply the last-stop effort to naturally indexed variable names to suit. This last-stop effort is really a last-stop. Other attempts should be made to create unique variable names before applying natural indexing.
|
||||
|
||||
Natural indexing concerns itself with suffixing variables with a sequential natural index. The only exception is the first local declaration which may or may not have the primary index suffix ''<e>_1</e>''. To better illustrate, the following code examples are both valid uses of natural indexing:
|
||||
|
||||
<e>
|
||||
perform
|
||||
-- An example of using natural sequential indexes to avoid variable name clashes.
|
||||
local
|
||||
l_item_1: ITEM
|
||||
l_item_2: ITEM
|
||||
l_item_3: ITEM
|
||||
do
|
||||
...
|
||||
end
|
||||
</e>
|
||||
|
||||
or
|
||||
|
||||
<e>
|
||||
perform
|
||||
-- An example with the first index elided, which is also valid.
|
||||
local
|
||||
l_item: ITEM
|
||||
l_item_2: ITEM
|
||||
l_item_3: ITEM
|
||||
do
|
||||
...
|
||||
end
|
||||
</e>
|
||||
|
||||
If local declaration have to be indexed when first writing the code then it is far better to be explicit and use a natural sequential index for all similar local declaration (the former example). The latter example is valid and would exist when modifying existing code. There is no hard or fast rule here, each is valid as long as the indexes are sequential.
|
||||
|
||||
The examples apply to all variable declaration, not just local declarations.
|
||||
@@ -0,0 +1,766 @@
|
||||
[[Property:uuid|46FFB0ED-CE10-4CA5-8F10-5E1D0AB6EE46]]
|
||||
[[Property:weight|4]]
|
||||
[[Property:title|Style Guidelines]]
|
||||
|
||||
Style Guidelines that EiffelStudio developers should use and are not intended or suggestions for developing code with the Eiffel language. The guidelines are to promote consistency in API design, making EiffelStudio's code base more readable to all.
|
||||
|
||||
==Status of this page==
|
||||
[I am starting this page by copy-pasting from existing references. It will be edited and cleaned up later on.[[User:Bertrand Meyer|Bertrand Meyer]] 12:35, 22 May 2008 (PDT)
|
||||
|
||||
=From ''Object-Oriented Software Construction''=
|
||||
|
||||
Implementing the object-oriented method requires paying attention to many details of style, which a less ambitious approach might consider trifles.
|
||||
|
||||
==COSMETICS MATTERS!==
|
||||
Although the rules appearing hereafter are not as fundamental as the principles of object-oriented software construction covered in earlier chapters, it would be foolish to dismiss them as just “cosmetics”. Good software is good in the large and in the small, in its high-level architecture and in its low-level details. True, quality in the details does not guarantee quality of the whole; but sloppiness in the details usually indicates that something more serious is wrong too. (If you cannot get the cosmetics right, why should your customers believe that you can master the truly difficult aspects?) A serious engineering process requires doing everything right: the grandiose and the mundane.
|
||||
|
||||
So you should not neglect the relevance of such seemingly humble details as text layout and choice of names. True, it may seem surprising to move on, without lowering our level of attention, from the mathematical notion of sufficient completeness in formal specifications (in the chapter on abstract data types) to whether a semicolon should be preceded by a space (in the present chapter). The explanation is simply that both issues deserve our care, in the same way that when you write quality O-O software both the design and the realization will require your attention.
|
||||
|
||||
We can take a cue from the notion of style in its literary sense. Although the first determinant of good writing is the author’s basic ability to tell a story and devise a coherent structure, no text is successful until everything works: every paragraph, every sentence and every word.
|
||||
|
||||
===Applying the rules in practice===
|
||||
Some of the rules of this chapter can be checked or, better yet, enforced from the start by software tools. Tools will not do everything, however, and there is no substitute for care in writing every piece of the software.
|
||||
|
||||
There is often a temptation to postpone the application of the rules, writing things casually at first and thinking “I will clean up everything later on; I do not even know how much of this will eventually be discarded”. This is not the recommended way. Once you get used to the rules, they do not add any significant delay to the initial writing of the software; even without special tools, it is always more costly to fix the text later than to write it properly from the start. And given the pressure on software developers, there is ever a risk that you will forget or not find the time to clean things up. Then someone who is asked later to take up your work will waste more time than it would have cost you to write the proper header comments, devise the right feature names, apply the proper layout. That someone may be you.
|
||||
|
||||
===Terseness and explicitness===
|
||||
Software styles have oscillated between the terse and the verbose. In programming languages, the two extremes are perhaps APL and Cobol. The contrast between the Fortran-C-C++ line and the Algol-Pascal-Ada tradition — not just the languages themselves, but the styles they have bred — is almost as stark.
|
||||
|
||||
What matters for us is clarity and, more generally, quality. Extreme forms of terseness and verbosity can both work against these goals. Cryptic C programs are unfortunately not limited to the famous “obfuscated C” and “Obfuscated C++” contests; but the almost equally famous DIVIDE DAYS BY 7 GIVING WEEKS of Cobol is a waste of everyone’s attention.
|
||||
|
||||
The style that follows from this chapter’s rules is a particular mix of Algol-like explicitness (although not, it is hoped, verbosity) and telegram-style terseness. It never begrudges keystrokes, even lines, when they truly help make the software readable; for example, you will find rules that enjoin using clear identifiers based on full words, not abbreviations, as it is foolish to save a few letters by calling a feature disp (ambiguous) rather than display (clear and precise), or a class ACCNT (unpronounceable) rather than ACCOUNT. There is no tax on keystrokes. But at the same time when it comes to eliminating waste and unneeded redundancies the rules below are as pitiless as the recommendations of a General Accounting Office Special Commission on Improving Government. They limit header comments to indispensable words, getting rid of all the non-essential “the” and other such amenities; they proscribe over-qualification of feature names (as in account_balance in a class ACCOUNT, where balance is perfectly sufficient); against dominant mores, they permit the grouping of related components of a complex construct on a single line, as in from i := 1 invariant i <= n until i = n loop; and so on.
|
||||
|
||||
This combination of terseness and explicitness is what you should seek in your own texts. Do not waste space, as exaggerated size will in the end mean exaggerated complexity; but do not hesitate to use space when it is necessary to enhance clarity.
|
||||
|
||||
Also remember, if like many people you are concerned about how much smaller the text of an object-oriented implementation will be than the text of a comparable C, Pascal, Ada or Fortran program, that the only interesting answer will appear at the level of a significant system or subsystem. If you express a basic algorithm — at the level of Quicksort, say, or Euclid’s algorithm — in C and in the notation of this book, expect the O-O version to be at least as large. In many cases, if you apply the principles thoroughly, it will be larger, since it will include assertions and more type information. Yet in ISE’s experience of looking at medium-scale systems we have sometimes found (without being able to give a general law, as the circumstances vary considerably) the object-oriented solution to be several times smaller. Why? This is not due to terseness at the “micro” level but to systemwide application of the architectural techniques of the O-O method:
|
||||
|
||||
Genericity is one of the key factors. We have found C programs that repeated essentially the same C code many times to handle different types. With a generic class — or for that matter a generic Ada package — you immediately get rid of that redundancy. It is disturbing in this respect to see that Java, a recent O-O language based on C, does not support genericity.
|
||||
|
||||
Inheritance is also fundamental in gathering commonalities and removing duplications.
|
||||
|
||||
Dynamic binding replaces many complex decision structures by much shorter calls.
|
||||
|
||||
Assertions and the associated idea of Design by Contract avoid redundant error checking, a principal source of bloat.
|
||||
|
||||
The exception mechanism gets rid of some error code.
|
||||
|
||||
If you are concerned with source size, make sure to concentrate on these architectural aspects. You should also be terse in expressing algorithms, but never skimp on keystrokes at the expense of clarity.
|
||||
|
||||
===The role of convention===
|
||||
Most rules define a single permissible form, with no variants. The few exceptions include font use, which is governed by external considerations (what looks good in a book may not be visible on overhead transparencies), and semicolons, for which there exist two opposite schools with equally forceful arguments (although we will have a few universal rules anyway). In all other cases, in line with the introductory methodology chapter’s exhortations against wishy-washiness, the rules leave about as much room to doubt as a past due reminder from the Internal Revenue Service.
|
||||
|
||||
The rules are rooted in a careful analysis of what works and what works less well, resulting from many years of observation; some of the rationale will appear in the discussion. Even so, some rules may appear arbitrary at first, and indeed in a few cases the decision is a matter of taste, so that reasonable persons working from the same assumptions may disagree. If you object to one of the recommended conventions, you should define your own, provided you explain it in detail and document it explicitly; but do think carefully before making such a decision, so obvious are the advantages of abiding by a universal set of rules that have been systematically applied to thousands of classes over more than ten years, and that many people know and understand.
|
||||
|
||||
As noted in an earlier chapter (in the more general context of design principles), many of the style rules were originally developed for libraries, and then found their way into ordinary software development. In object technology, of course, all software is developed under the assumption that even if it is not reusable yet it might eventually be made reusable, so it is natural to apply the same style rules right from the start.
|
||||
|
||||
===Self-practice===
|
||||
Like the design rules of the preceding chapters, the style rules which follow have been carefully applied to the many examples of this book. The reasons are obvious: one should practice what one preaches; and, more fundamentally, the rules do support clarity of thought and expression, which can only be good for a detailed presentation of the object-oriented method.
|
||||
|
||||
The only exceptions are a few occasional departures from the rules on software text layout. These rules do not hesitate to spread texts over many lines, for example by requiring that every assertion clause have its own label. Lines are not a scarce resource on computer screens; it has been observed that with the computer age we are reversing the direction of the next-to-last revolution in written communication, the switch from papyrus rolls to page-structured books. But this text is definitely a book, structured into pages, and a constant application of the layout-related rules would have made it even bigger than it is.
|
||||
|
||||
The cases of self-dispensation affect only two or three layout-related rules, and will be noted in their presentation below. Any exception only occurs after the first few examples of a construct in the book have applied the rules scrupulously.
|
||||
|
||||
Such exceptions are only justified for a paper presentation. Actual software texts should apply the rules literally.
|
||||
|
||||
===Discipline and creativity===
|
||||
It would be a mistake to protest against the rules of this chapter (and others) on the grounds that they limit developer creativity. A consistent style favors rather than hampers creativity by channeling it to where it matters. A large part of the effort of producing software is spent reading existing software and making others read what is being written. Individual vagaries benefit no one; common conventions help everyone.
|
||||
|
||||
Some of the software engineering literature of the nineteen-seventies propounded the idea of “egoless programming”: developing software so that it does not reflect anything of its authors’ personality, thereby making developers interchangeable. Applied to system design, this goal is clearly undesirable, even if some managers may sometimes long for it (as in this extract of a programming management book quoted by Barry Boehm: “ºthe programmer[‘s] creative instincts should be totally dulled to insure uniform and understandable programming”, to which Boehm comments: “Given what we know about programmers and their growth motivation, such advice is a clear recipe for disaster”).
|
||||
|
||||
What quality software requires is egoful design with egoless expression.
|
||||
|
||||
More than style standards, what would seem to require justification is the current situation of software development, with its almost total lack of style standards. In no other discipline that demands to be called “engineering” is there such room for such broad personal variations of whim and fancy. To become more professional, software development needs to regulate itself.
|
||||
|
||||
==CHOOSING THE RIGHT NAMES==
|
||||
The first aspect that we need to regulate is the choice of names. Feature names, in particular, will be strictly controlled for everyone’s benefit.
|
||||
|
||||
===General rules===
|
||||
What matters most is the names of classes and features which will be used extensively by the authors of classes that rely on yours.
|
||||
|
||||
For feature and class names, use full words, not abbreviations, unless the abbreviations are widely accepted in the application domain. In a class PART describing parts in an inventory control system, call number, not num, the feature (query) giving the part number. Typing is cheap; software maintenance is expensive. An abbreviation such as usa in a Geographical Information System or copter in a flight control system, having gained an independent status as a word of its own, is of course acceptable. In addition, a few standard abbreviations have gained recognition over the years, such as PART for PARTIAL in class names such as PART_COMPARABLE describing objects equipped with a partial order relation.
|
||||
|
||||
In choosing names, aim for clarity. Do not hesitate to use several words connected by underscores, as in ANNUAL_RATE, a class name, or yearly_premium, a feature name.
|
||||
|
||||
Although modern languages do not place any limit on the length of identifiers, and treat all letters as significant, name length should remain reasonable. Here the rule is not the same for classes and for features. Class names are input only occasionally (in class headers, type declarations, inheritance clauses and a few other cases) and should describe an abstraction as completely as possible, so PRODUCT_QUANTITY_INDEX_EVALUATOR may be fine. For features, there is seldom a need for more than two or possibly three underscore-connected words. In particular, do not overqualify feature names. If a feature name appears too long, it is usually because it is overqualified:
|
||||
|
||||
===Composite Feature Name rule===
|
||||
Do not include in a feature name the name of the underlying data abstraction (which should serve as the class name).
|
||||
|
||||
|
||||
The feature giving the part number in class PART should be called just number, not part_number. Such over-qualification is a typical beginner’s mistake; the resulting names obscure rather than illuminate the text. Remember that every use of the feature will unambiguously indicate the class, as in part1 l number where part1 must have been declared with a certain type, PART or a descendant.
|
||||
|
||||
For composite names, it is better to avoid the style, popularized by Smalltalk and also used in such libraries as the X Window System, of joining several words together and starting the internal ones with an upper-case letter, as in yearlyPremium. Instead, separate components with underscores, as in yearly_ premium. The use of internal upper-case letters is ugly; it conflicts with the conventions of ordinary language; and it leads to cryptic names, hence to possible errors (compare aLongAndRatherUnreadableIdentifier with an_even_longer_but_ perfectly_clear_choice_of_name).
|
||||
|
||||
Sometimes, every instance of a certain class contains a field representing an instance of another class. This suggests using the class name also as attribute name. You may for example have defined a class RATE and, in class ACCOUNT, need one attribute of type RATE, for which it seems natural to use the name rate — in lower case, according to the rules on letter case stated below. Although you should try to find a more specific name, you may, if this fails, just declare the feature as rate: RATE. The rules on identifier choice explicitly permit assigning the same name to a feature and a class. Avoid the style of prefixing the name with the, as in the_rate, which only adds noise.
|
||||
|
||||
===Local entities and routine arguments===
|
||||
The emphasis on clear, spelled-out names applies to features and classes. Local entities and arguments of a routine only have a local scope, so they do not need to be as evocative. Names that carry too much meaning might almost decrease the software’s readability by giving undue weight to ancillary elements. So it is appropriate to declare local entities (here in routines of TWO_WAY_LIST in the Base libraries) as
|
||||
<e>
|
||||
move (i: INTEGER)
|
||||
-- Move cursor i positions, or after if i is too large.
|
||||
local
|
||||
c: CURSOR; counter: INTEGER; p: like FIRST_ELEMENT
|
||||
|
||||
remove
|
||||
-- Remove current item; move cursor to right neighbor (of after if none).
|
||||
local
|
||||
succ, pred, removed: like first_element
|
||||
</e>
|
||||
|
||||
If succ and pred had been features they would have been called successor and predecessor. It is also common to use the names new for a local entity representing a new object to be created by a routine, and other for an argument representing an object of the same type as the current one, as in the declaration for clone in GENERAL:
|
||||
<e>
|
||||
frozen clone (other: GENERAL): like other
|
||||
</e>
|
||||
|
||||
===Letter case===
|
||||
Letter case is not significant in our notation, as it is too dangerous to let two almost identical identifiers denote different things. But strongly recommended guidelines help make class texts consistent and readable:
|
||||
|
||||
Class names appear in all upper case: POINT, LINKED_LIST, PRICING_MODEL. Formal generic parameters too, usually with just one letter: G.
|
||||
|
||||
Names of non-constant attributes, routines other than once functions, local entities and routine arguments appear in all lower case: balance, deposit, succ, i.
|
||||
|
||||
Constant attributes have their first letter in upper case and the rest in lower case: Pi: INTEGER is 3.1415926524; Welcome_message: STRING is "Welcome!". This applies to unique values, which are constant integers.
|
||||
|
||||
The same convention applies to once functions, the equivalent of constants for non-basic types: Error_window, Io. Our first example, the complex number i, remained in lower case for compatibility with mathematical conventions.
|
||||
|
||||
This takes care of developer-chosen names. For reserved words, we distinguish two categories. Keywords such as do and class play a strictly syntactic role; they are written in lower case, and will appear in boldface (see below) in printed texts. A few reserved words are not keywords because they carry an associated semantics; written with an initial upper case since they are similar to constants, they include Current, Result, Precursor, True and False.
|
||||
|
||||
===Grammatical categories===
|
||||
Precise rules also govern the grammatical category of the words from which identifiers are derived. In some languages, these rules can be applied without any hesitation; in English, as noted in an earlier chapter, they will leave more flexibility.
|
||||
|
||||
The rule for class names has already been given: you should always use a noun, as in ACCOUNT, possibly qualified as in LONG_TERM_SAVINGS_ACCOUNT, except for the case of deferred classes describing a structural property, which may use an adjective as in NUMERIC or REDEEMABLE.
|
||||
|
||||
Routine names should faithfully reflect the Command-Query separation principle:
|
||||
|
||||
Procedures (commands) should be verbs in the infinitive or imperative, possibly with complements: make, move, deposit, set_color.
|
||||
|
||||
Attributes and functions (queries) should never be imperative or infinitive verbs; never call a query get_value, but just value. Non-boolean query names should be nouns, such as number, possibly qualified as in last_month_balance. Boolean queries should use adjectives, as in full. In English, because of possible confusions between adjectives and verbs (empty, for example, could mean “is this empty?” or “empty this!”), a frequent convention for boolean queries is the is_ form, as in is_empty.
|
||||
|
||||
===Standard names===
|
||||
You will have noted, throughout this book, the recurrence of a few basic names, such as put and item. They are an important part of the method.
|
||||
|
||||
Many classes will need features representing operations of a few basic kinds: insert an element into a structure, replace the value of an element, access a designated elementº Rather than devising specific names for the variants of these operations in every class, it is preferable to apply a standard terminology throughout.
|
||||
|
||||
Here are the principal standard names. We can start with creation procedures, for which the recommended is make for the most common creation procedure of a class. Non-vanilla creation procedures may be called make_some_qualification, for example make_polar and make_cartesian for a POINT or COMPLEX class.
|
||||
|
||||
====For commands the most common names are:====
|
||||
|
||||
*extend: Add an element.
|
||||
*replace: Replace an element.
|
||||
*force: Like put but may work in more cases; for example put for arrays has a precondition to require the index to be within bounds, but force has no precondition and will resize the array if necessary.
|
||||
*remove: Remove an (unspecified) element.
|
||||
*prune: Remove a specific element.
|
||||
*wipe_out: Remove all elements.
|
||||
|
||||
====For non-boolean queries (attributes or functions):====
|
||||
*item: The basic query for accessing an element: in ARRAY, the element at a given index; in STACK classes, the stack top; in QUEUE classes, the oldest element; and so on.
|
||||
*infix "@": A synonym for item in a few cases, notably ARRAY.
|
||||
: -- Note: no longer necessary; use bracket alias instead. Still present in existing libraries.
|
||||
*count: Number of usable elements in a structure.
|
||||
*capacity: Physical size allocated to a bounded structure, measured in number of potential elements. The invariant should include 0 <= count and count <= capacity.
|
||||
|
||||
====For boolean queries:====
|
||||
*is_empty: Is the structure devoid of elements?
|
||||
*is_full: Is there no more room in the representation to add elements? (Normally the same as count = capacity.)
|
||||
*has: Is a certain element present? (The basic membership test.)
|
||||
*is_extendible: Can an element be added? (May serve as a precondition to extend.)
|
||||
*is_prunable: Can an element be removed? (May serve as a precondition to remove and prune.)
|
||||
*is_readable: Is there an accessible element? (May serve as precondition to item and remove.)
|
||||
*is_writable: Is it possible to change an element? (May variously serve as precondition to extend, replace, put etc.)
|
||||
|
||||
::Note: the variants without `is_' are also widely used, e.g. `prunable', but the `is_' form is now recommended.
|
||||
|
||||
A few name choices which may seem strange at first are justified by considerations of clarity and consistency. For example prune goes with prunable and extend with extendible; delete and add might seem more natural, but then s l deletable and s l addable would carry the wrong connotation, since the question is not whether s can be deleted or added but whether we can add elements to it or delete elements from it. The verbs prune and extend, with the associated queries, convey the intended meaning.
|
||||
|
||||
===The benefits of consistent naming===
|
||||
The set of names sketched above is one of the elements that most visibly contribute to the distinctive style of software construction developed from the principles of this book.
|
||||
|
||||
Is the concern for consistency going too far? One could fear that confusion could result from routines that bear the same name but internally do something different. For example item for a stack will return the top element, and for an array will return an element corresponding to the index specified by the client.
|
||||
|
||||
With a systematic approach to O-O software construction, using static typing and Design by Contract, this fear is not justified. To learn about a feature, a client author can rely on four kinds of property, all present in the short form of the enclosing class:
|
||||
*Its name.
|
||||
*Its signature (number and type of arguments if a routine, type of result if a query).
|
||||
*Its precondition and postcondition if any.
|
||||
*Its header comment.
|
||||
|
||||
A routine also has a body, but that is not part of what client authors are supposed to use.
|
||||
|
||||
Three of these elements will differ for the variants of a basic operation. For example in the short form of class STACK you may find the feature
|
||||
<e>
|
||||
put (x: G)
|
||||
-- Push x on top.
|
||||
require
|
||||
writable: not full
|
||||
ensure
|
||||
not_empty: not empty
|
||||
pushed: item = x
|
||||
</e>
|
||||
whereas its namesake will appear in ARRAY as
|
||||
<e>
|
||||
put (x: G; i: INTEGER)
|
||||
-- Replace by x the entry of index i
|
||||
require
|
||||
not_too_small: i >= lower
|
||||
not_too_large: i <= upper
|
||||
ensure
|
||||
replaced: item (i) = x
|
||||
</e>
|
||||
|
||||
The signatures are different (one variant takes an index, the other does not); the preconditions are different; the postconditions are different; and the header comments are different. Using the same name put, far from creating confusion, draws the reader’s attention to the common role of these routines: both provide the basic element change mechanism.
|
||||
|
||||
This consistency has turned out to be one of the most attractive aspects of the method and in particular of the libraries. New users take to it quickly; then, when exploring a new class which follows the standard style, they feel immediately at home and can zero in on the features that they need.
|
||||
|
||||
==USING CONSTANTS==
|
||||
Many algorithms will rely on constants. As was noted in an early chapter of this book, constants are widely known for the detestable practice of changing their values; we should prepare ourselves against the consequences of such fickleness.
|
||||
|
||||
===Manifest and symbolic constants===
|
||||
The basic rule is that uses of constants should not explicitly rely on the value:
|
||||
|
||||
====Symbolic Constant principle====
|
||||
Do not use a manifest constant, other than the zero elements of basic operations, in any construct other than a symbolic constant declaration.
|
||||
|
||||
|
||||
In this principle, a manifest constant is a constant given explicitly by its value, as in 50 (integer constant) or "Cannot find file" (string constant). The principle bars using instructions of the form
|
||||
<e>
|
||||
population_array l make (1, 50)
|
||||
</e>
|
||||
or
|
||||
<e>
|
||||
print ("Cannot find file") -- See mitigating comment below about this case
|
||||
</e>
|
||||
|
||||
Instead, you should declare the corresponding constant attributes, and then, in the bodies of the routines that need the values, denote them through the attribute names:
|
||||
<e>
|
||||
US_state_count: INTEGER = 50
|
||||
File_not_found: STRING = "Cannot find file"
|
||||
</e>
|
||||
|
||||
<e>
|
||||
population_array l make (1, state_count)
|
||||
</e>
|
||||
|
||||
<e>
|
||||
print (file_not_found)
|
||||
</e>
|
||||
|
||||
The advantage is obvious: if a new state is added, or the message needs to be changed, you have only have to update one easy-to-locate declaration.
|
||||
|
||||
The use of 1 together with state_count in the first instruction is not a violation of the principle, since its prohibition applies to manifest constants “other than zero elements of basic operations”. These zero elements, which you may use in manifest form, include the integers 0 and 1 (zero elements of addition and multiplication), the real number 0.0, the null character written '%0', the empty string " ". Using a symbolic constant One every time you need to refer to the lower bound of an array (1 using the default convention) would lead to an unsustainable style — pedantic, and in fact less readable because of its verbosity. Sometimes, Freud is supposed to have said, a cigar is just a cigar; sometimes One is just 1.
|
||||
|
||||
Some other times 1 is just a system parameter that happens to have the value one today but could become 4,652 later — its role as addition’s zero element being irrelevant. Then it should be declared as a symbolic constant, as in Processor_count: INTEGER is 1 in a system that supports multiple processors and is initially applied to one processor.
|
||||
|
||||
The Symbolic Constant principle may be judged too harsh in the case of simple manifest strings used just once, such as "Cannot find file" above. Some readers may want to add this case to the exception already stated in the principle (replacing the qualification by “other than manifest string constants used only once in the same class, and zero elements of basic operations”). This book has indeed employed a few manifest constants in simple examples. Such a relaxation of the rule is acceptable, but in the long run it is probably preferable to stick to the rule as originally given even if the result for string constants looks a little pedantic at times. One of the principal uses of string constants, after all, is for messages to be output to users; when a successful system initially written for the home market undergoes internationalization, it will be that much less translation work if all the user-visible message strings (at least any of them that actually appear in the software text) have been put in symbolic constant declarations.
|
||||
|
||||
====Where to put constant declarations====
|
||||
If you need more than a handful of local constant attributes in a class, you have probably uncovered a data abstraction — a certain concept characterized by a number of numeric or character parameters.
|
||||
|
||||
It is desirable, then, to group the constant declarations into a class, which can serve as ancestor to any class needing the constants (although some O-O designers prefer to use the client relation in this case). An example in the Base libraries is the class ASCII, which declares constant attributes for the different characters in the ASCII character set and associated properties.
|
||||
|
||||
==HEADER COMMENTS AND NOTE CLAUSES==
|
||||
Although the formal elements of a class text should give as much as possible of the information about a class, they must be accompanied by informal explanations. Header comments of routines and feature clause answer this need together with the note clause of each class.
|
||||
|
||||
'''Terminology''': in earlier Eiffel versions the keyword <b>indexing</b> was used instead of <b>note</b>,
|
||||
and "note clauses" were called "indexing clauses"
|
||||
|
||||
===Routine header comments: an exercise in corporate downsizing===
|
||||
|
||||
Like those New York street signs that read “Don’t even think of parking here!”, the sign at the entrance of your software department should warn “Don’t even think of writing a routine without a header comment”. The header comment, coming just after the is for a routine, expresses its purpose concisely; it will be kept by the short and flat-short forms:
|
||||
<e>
|
||||
distance_to_origin: REAL
|
||||
-- Distance to point (0, 0)
|
||||
local
|
||||
origin: POINT
|
||||
do
|
||||
create origin
|
||||
Result := distance (origin)
|
||||
end
|
||||
</e>
|
||||
Note the indentation: one step further than the start of the routine body, so that the comment stands out.
|
||||
|
||||
Header comments should be informative, clear, and terse. They have a whole style of their own, which we can learn by looking at an initially imperfect example and improve it step by step. In a class CIRCLE we might start with
|
||||
|
||||
<e>
|
||||
tangent_from (p: POINT): LINE
|
||||
-- Return the tangent line to the current circle going through the point p,
|
||||
-- if the point is outside of the current circle.
|
||||
require
|
||||
outside_circle: not has (p)
|
||||
</e>
|
||||
|
||||
There are many things wrong here. First, the comment for a query, as here, should not start with “Return theº” or “Compute theº”, or in general use a verbal form; this would go against the Command-Query Separation principle. Simply name what the query returns, typically using a qualified noun for a non-boolean query (we will see below what to use for a boolean query and a command). Here we get:
|
||||
|
||||
<e>
|
||||
-- The tangent line to the current circle going through the point p,
|
||||
-- if the point p is outside of the current circle
|
||||
</e>
|
||||
|
||||
Since the comment is not a sentence but simply a qualified noun, the final period disappears. Next we can get rid of the auxiliary words, especially the, where they are not required for understandability. Telegram-like style is desirable for comments. (Remember that readers in search of literary frills can always choose Proust novels instead.)
|
||||
<e>
|
||||
--Tangent line to current circle from point p,
|
||||
-- if point p is outside current circle
|
||||
</e>
|
||||
|
||||
The next mistake is to have included, in the second line, the condition for the routine’s applicability; the precondition, not has (p), which will be retained in the short form where it appears just after the header comment, expresses this condition clearly and unambiguously. There is no need to paraphrase it: this could lead to confusion, if the informal phrasing seems to contradict the formal precondition, or even to errors (a common oversight is a precondition of the form x >= 0 with a comment stating “applicable only to positive x”, rather than “non-negative”); and there is always a risk that during the software’s evolution the precondition will be updated but not the comment. Our example becomes:
|
||||
<e>
|
||||
-- Tangent line to current circle from point p.
|
||||
</e>
|
||||
|
||||
Yet another mistake is to have used the words line to refer to the result and point to refer to the argument: this information is immediately obvious from the declared types, LINE and POINT. With a typed notation we can rely on the formal type declarations — which again will appear in the short form — to express such properties; repeating them in the informal text brings nothing. So:
|
||||
<e>
|
||||
-- Tangent to current circle from p.
|
||||
</e>
|
||||
|
||||
The mistakes of repeating type information and of duplicating the precondition’s requirements point to the same general rule: in writing header comments, assume the reader is competent in the fundamentals of the technology; do not include information that is obvious from the immediately adjacent short form text. This does not mean, of course, that you should never specify a type; the earlier example, -- Distance to point (0,0), could be ambiguous without the word point.
|
||||
|
||||
When you need to refer to the current object represented by a class, use phrasing such as current circle, current number and so on as above, rather than referring explicitly to the entity Current. In many cases, however, you can avoid mentioning the current object altogether, since it is clear to everyone who can read a class text that features apply to the current object. Here, for example, we just need
|
||||
<e>
|
||||
-- Tangent from p.
|
||||
</e>
|
||||
|
||||
At this stage — three words, starting from twenty-two, an 87% reduction that would make the toughest Wall Street exponent of corporate downsizing jealous — it seems hard to get terser and we can leave our comment alone.
|
||||
|
||||
A few more general guidelines. We have noted the uselessness of “Return the ” in queries; other noise words and phrases to be avoided in routines of all kinds include “This routine computes”, “This routine returns”; just say what the routine does, not that it does it. Instead of
|
||||
<e>
|
||||
-- This routine records the last outgoing call.
|
||||
</e>
|
||||
write
|
||||
<e>
|
||||
-- Record outgoing call.
|
||||
</e>
|
||||
As illustrated by this example, header comments for commands (procedures) should be in the imperative or infinitive (the same in English), in the style of marching orders. They should end with a period. For boolean-valued queries, the comment should always be in the form of a question, terminated by a question mark:
|
||||
<e>
|
||||
has (v: G): BOOLEAN is
|
||||
-- Does v appear in list?
|
||||
</e>
|
||||
|
||||
A convention governs the use of software entities — attributes, arguments — appearing in comments. In typeset texts such as the above they will appear in italics (more on font conventions below); in the source text they should always appear between an opening quote (“backquote”) and a closing quote; the original text for the example is then:
|
||||
|
||||
<e>
|
||||
-- Does ‘v’ appear in list?
|
||||
</e>
|
||||
Tools such as the short class abstracter will recognize this convention when generating typeset output. Note that the two quotes should be different: ‘v’, not ’v’.
|
||||
|
||||
Be consistent. If a function of a class has the comment Length of string, a routine of the same class should not say Update width of string if it affects the same property.
|
||||
|
||||
All these guidelines apply to routines. Because an exported attribute should be externally indistinguishable from argumentless functions — remember the Uniform Access principle — it should also have a comment, which will appear on the line following the attribute’s declaration, with the same indentation as for functions:
|
||||
|
||||
<e>
|
||||
count: INTEGER
|
||||
-- Number of students in course
|
||||
</e>
|
||||
For secret attributes a comment is desirable too but the rule is less strict.
|
||||
|
||||
===Feature clause header comments===
|
||||
As you will remember, a class may have any number of feature clauses:
|
||||
<e>
|
||||
note
|
||||
</e>
|
||||
|
||||
<e>
|
||||
class LINKED_LIST [G]
|
||||
inherit
|
||||
</e>
|
||||
|
||||
<e>
|
||||
creation
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Initialization
|
||||
make
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Access
|
||||
item: G
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Status report
|
||||
before: BOOLEAN
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Status setting
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Element change
|
||||
put_left (v: G)
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Removal
|
||||
remove
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature {NONE} -- Implementation
|
||||
first_element: LINKABLE [G].
|
||||
</e>
|
||||
|
||||
<e>
|
||||
end -- class LINKED_LIST
|
||||
</e>
|
||||
One of the purposes of having several feature clauses is to allow different features to have different export privileges; in this example everything is generally available except the secret features in the last clause. But another consequence of this convention is that you could, and should, group features by categories. A comment on the same line as the keyword feature should characterize the category. Such comments are, like header comments of routines, recognized an preserved by documentation tools such as short.
|
||||
|
||||
Eighteen categories and the corresponding comments have been standardized for the Base libraries, so that every feature (out of about 2000 in all) belongs to one of them. The example above illustrates some of the most important categories. Status report corresponds to options (set by features in the Status setting category, not included in the example). Secret and selectively exported features appear in the Implementation category. These standard categories always appear in the same order, which the tools know (through a user-editable list) and will preserve or reinstate in their output. Within each category, the tools list the features alphabetically for ease of retrieval.
|
||||
|
||||
The categories cover a wide range of application domains, although for special areas you may need to add your own categories.
|
||||
|
||||
===Note clauses===
|
||||
Similar to header comments but slightly more formal are note clauses, appearing at the beginning of a class:
|
||||
<e>
|
||||
note
|
||||
description: "Sequential lists, in chained representation"
|
||||
names: "Sequence", "List"
|
||||
contents: GENERIC
|
||||
representation: chained
|
||||
date: "$Date: 96/10/20 12:21:03 $"
|
||||
revision: "$Revision: 2.4$"
|
||||
|
||||
class LINKED_LIST [G]
|
||||
inherit
|
||||
</e>
|
||||
|
||||
Note clauses proceed from the same Self-Documentation principle that has led to built-in assertions and header comments: include as much as possible of the documentation in the software itself. For properties that do not directly appear in the formal text, you may include note entries, all of the form
|
||||
|
||||
<e>
|
||||
note_term: note_value, note_value,
|
||||
</e>
|
||||
where the note_term is an identifier and each note_value is some basic element such as a string, an integer and so on. Entries can indicate alternative names under which potential client authors might search for the class (names), contents type (contents), implementation choices (representation), revision control information, author information, and anything else that may facilitate understanding the class and retrieving it through keyword-based search tools — tools that support reuse and enable software developers to find their way through a potentially rich set of reusable components.
|
||||
|
||||
Both the note terms and the note values are free-form, but the possible choices should be standardized for each project. A set of standard choices has been used throughout the Base libraries; the above example illustrates six of the most common entry kinds. Every class must have a description entry, introducing as index_value a string describing the role of the class, always expressed in terms of the instances (as Sequential listsº, not “this class describes sequential lists”, or “sequential list”, or “the notion of sequential list” etc.). Most significant class texts in this book — but not short examples illustrating a specific point — include the description entry.
|
||||
|
||||
===Non-header comments===
|
||||
The preceding rules on comments applied to standardized comments, appearing at specific places — feature declarations and beginning of feature clauses — and playing a special role for class documentation.
|
||||
|
||||
As in all forms of software development, there is also a need for comments within routine bodies, to provide further explanations
|
||||
|
||||
Another use of comments, although frequent in the practice of software development, does not figure much in software engineering and programming methodology textbooks. I am referring here to the technique of transforming some part of the code into comments, either because it does not work, or because it is not ready yet. This practice is clearly a substitute for better tools and techniques of configuration management. It has enriched the language with a new verb form, comment out, whose potential, surprisingly enough, has not yet been picked up by hip journalists, even though the non-technical applications seem attractive and indeed endless: “The last elections have enabled Congress to comment out the President”, “Letterman was commented out of the Academy Awards”, and so on.
|
||||
|
||||
Every comment should be of a level of abstraction higher than the code it documents. A famous counter-example is -- Increase i by 1 commenting the instruction i := i + 1. Although not always that extreme, the practice of writing comments that paraphrase the code instead of summarizing its effect is still common.
|
||||
|
||||
Low-level languages cry for ample commenting. It is a good rule of thumb, for example, that for each line of C there should be a comment line; not a negative reflection on C, but a consequence that in modern software development the role of C is to encapsulate machine-oriented and operating-system-level operations, which are tricky by nature and require a heavy explanatory apparatus. In the O-O part, non-header comments will appear much more sparsely; they remain useful when you need to explain some delicate operation or foresee possible confusion. In its constant effort to favor prevention over cure, the method decreases the need for comments through a modular style that yields small, understandable routines, and through its assertion mechanisms: preconditions and postconditions of routines, to express their semantics formally; class invariants; check instructions to express properties expected to hold at certain stages; the systematic naming conventions introduced earlier in this chapter. More generally, the secret of clear, understandable software is not adding comments after the fact but devising coherent and stable system structures right from the start.
|
||||
|
||||
==TEXT LAYOUT AND PRESENTATION==
|
||||
The next set of rules affects how we should physically write our software texts on paper — real, or simulated on a screen. More than any others, they prompt cries of “Cosmetics!”; but such cosmetics should be as important to software developers as Christian Dior’s are to his customers. They play no little role in determining how quickly and accurately your software will be understood by its readers — maintainers, reusers, customers.
|
||||
|
||||
===Layout ===
|
||||
The recommended layout of texts results from the general form of the syntax of our notation, which is roughly what is known as an “operator grammar”, meaning that a class text is a sequence of symbols alternating between “operators” and “operands”. An operator is a fixed language symbol, such as a keyword (do etc.) or a separator (semicolon, comma º); an operand is a programmer-chosen symbol (identifier or constant).
|
||||
|
||||
Based on this property, the textual layout of the notation follows the comb-like structure introduced by Ada; the idea is that a syntactically meaningful part of a class, such as an instruction or an expression, should either:
|
||||
|
||||
Fit on a line together with a preceding and succeeding operators.
|
||||
|
||||
Be indented just by itself on one or more lines — organized so as to observe the same rules recursively.
|
||||
|
||||
Each branch of the comb is a sequence of alternating operators and operands; it should normally begin and end with an operator. In the space between two branches you find either a single operand or, recursively, a similar comb-like structure.
|
||||
|
||||
As an example, depending on the size of its constituents a, b and c, you may spread out a conditional instruction as
|
||||
<e>
|
||||
if c then a else b end
|
||||
</e>
|
||||
or
|
||||
<e>
|
||||
if
|
||||
c
|
||||
then
|
||||
a
|
||||
else
|
||||
b
|
||||
end
|
||||
</e>
|
||||
or
|
||||
<e>
|
||||
if c then
|
||||
a
|
||||
else b end
|
||||
</e>
|
||||
You would not, however, use a line containing just if c or c end, since they include an operand together with something else, and are missing an ending operator in the first case and a starting operator in the second.
|
||||
|
||||
Similarly, you may start a class, after the note clause, with
|
||||
<e>
|
||||
class C inherit -- [1]
|
||||
</e>
|
||||
or
|
||||
<e>
|
||||
class C feature -- [2]
|
||||
</e>
|
||||
or
|
||||
<e>
|
||||
class -- [3]
|
||||
C
|
||||
feature
|
||||
</e>
|
||||
but not
|
||||
<e>
|
||||
class C -- [4]
|
||||
feature
|
||||
</e>
|
||||
because the first line would violate the rule. Forms [1] and [2] are used in this book for small illustrative classes; since most practical classes have one or more labeled feature clauses, they should in the absence of an inherit clause use form [3] (rather than [2]):
|
||||
<e>
|
||||
class
|
||||
C
|
||||
feature -- Initialization
|
||||
</e>
|
||||
|
||||
<e>
|
||||
feature -- Access
|
||||
</e>
|
||||
etc.
|
||||
|
||||
===Height and width===
|
||||
Like most modern languages, our notation does not attach any particular significance to line separations except to terminate comments, so that you can include two or more instructions (or two or more declarations) on a single line, separated by semicolons:
|
||||
|
||||
<e>
|
||||
count := count + 1; forth
|
||||
</e>
|
||||
|
||||
This style is for some reason not very popular (and many tools for estimating software size still measure lines rather than syntactical units); most developers seem to prefer having one instruction per line. It is indeed not desirable to pack texts very tightly; but in some cases a group of two or three short, closely related instructions can be more readable if they all appear on one line.
|
||||
|
||||
In this area it is best to defer to your judgment and good taste. If you do apply intra-line grouping, make sure that it remains moderate, and consistent with the logical relations between instructions. The Semicolon Style principle seen later in this chapter requires any same-line instructions to be separated by a semicolon.
|
||||
|
||||
For obvious reasons of space, this book makes a fair use of intra-line grouping, consistent with these guidelines. It also avoids splitting multi-line instructions into more lines than necessary; on this point one can recommend the book’s style for general use: there is really no reason to split from i:= 1 invariant i <= n until i = n loop or if a = b then. Whatever your personal taste, do observe the Comb structure.
|
||||
|
||||
===Indenting details===
|
||||
The comb structure uses indentation, achieved through tab characters (not spaces, which are messy, error-prone, and not reader-parameterizable).
|
||||
|
||||
Here are the indentation levels for the basic kinds of construct, illustrated by the example on the facing page:
|
||||
|
||||
*Level 0: the keywords introducing the primitive clauses of a class. This includes note (beginning of a note clause), class (beginning of the class body), feature (beginning of a feature clause, except if on the same line as class), invariant (beginning of an invariant clause, not yet seen) and the final end of a class.
|
||||
*Level 1: beginning of a feature declaration; note entries; invariant clauses.
|
||||
*Level 2: the keywords starting the successive clauses of a routine. This includes require, local, do, once, ensure, rescue, end.
|
||||
*Level 3: the header comment for a routine or (for consistency) attribute; declarations of local entities in a routine; first-level instructions of a routine.
|
||||
|
||||
Within a routine body there may be further indentation due to the nesting of control structures. For example the earlier if a then º instruction contains two branches, each of them indented. These branches could themselves contain loops or conditional instructions, leading to further nesting (although the style of object-oriented software construction developed in this book leads to simple routines, seldom reaching high levels of nesting).
|
||||
|
||||
A check instruction is indented, together with the justifying comment that normally follows it, one level to the right of the instruction that it guards.
|
||||
<e>
|
||||
note
|
||||
description: "Example for formating"
|
||||
class EXAMPLE inherit
|
||||
MY_PARENT
|
||||
redefine f1, f2 end
|
||||
MY_OTHER_PARENT
|
||||
rename
|
||||
g1 as old_g1, g2 as old_g2
|
||||
redefine
|
||||
g1
|
||||
select
|
||||
g2
|
||||
end
|
||||
creation
|
||||
make
|
||||
feature -- Initialization
|
||||
make
|
||||
-- Do something.
|
||||
require
|
||||
some_condition: correct (x)
|
||||
local
|
||||
my_entity: MY_TYPE
|
||||
do
|
||||
if a then
|
||||
b; c
|
||||
else
|
||||
other_routine
|
||||
check max2 > max1 + x ^ 2 end
|
||||
-- Because of the postcondition of other_routine.
|
||||
new_value := old_value / (max2 – max1)
|
||||
end
|
||||
end
|
||||
feature -- Access
|
||||
my_attribute: SOME_TYPE
|
||||
-- Explanation of its role (aligned with comment for make)
|
||||
|
||||
... Other feature declarations and feature clauses ...
|
||||
|
||||
invariant
|
||||
upper_bound: x <= y
|
||||
end -- class EXAMPLE
|
||||
</e>
|
||||
Note the trailer comment after the end of the class, a systematic convention.
|
||||
|
||||
===Spaces===
|
||||
White space contributes as much to the effect produced by a software text as silence to the effect of a musical piece.
|
||||
|
||||
The general rule, for simplicity and ease of remembering, is to follow as closely as possible the practice of standard written language. By default we will assume this language to be English, although it may be appropriate to adapt the conventions to the slightly different rules of other languages.
|
||||
|
||||
Here are some of the consequences. You will use a space:
|
||||
|
||||
Before an opening parenthesis, but not after:
|
||||
<e>f (x) (not f (x), the C style, or f ( x)).</e>
|
||||
|
||||
After a closing parenthesis unless the next character is a punctuation sign such as a period or semicolon; but not before. Hence:
|
||||
<e>proc1 (x); x := f1 (x) + f2 (y)</e>
|
||||
|
||||
After a comma but not before: \
|
||||
<e>g (x, y, z)</e>.
|
||||
|
||||
After the two dash signs that start a comment:<e> -- A comment.</e>
|
||||
|
||||
Similarly, the default rule for semicolons is to use a space after but not before:
|
||||
<e>
|
||||
p1; p2 (x); p3 (y, z)
|
||||
</e>
|
||||
|
||||
Here, however, some people prefer, even for English-based software texts, the French style of including a space both before and after, which makes the semicolon stand out and emphasizes the symmetry between the components before and after it:
|
||||
<e>
|
||||
p1 ; p2 (x) ; p3 (y, z)
|
||||
</e>
|
||||
|
||||
Choose either style, but then use it consistently. (This book uses the English style.) English and French styles have the same difference for colons as for semicolons; since, however, the software notation only uses colons for declarations, in which the two parts — the entity being declared and its type — do not play a symmetric role, it seems preferable to stick to the English style, as in your_entity: YOUR_TYPE.
|
||||
|
||||
Spaces should appear before and after arithmetic operators, as in a + b. (For space reasons, this book has omitted the spaces in a few cases, all of the form n+1.)
|
||||
|
||||
For periods the notation departs from the conventions of ordinary written language since it uses periods for a special construct, as originally introduced by Simula. As you know, a l r means: apply feature r to the object attached to a. In this case there is a space neither before nor after the period. To avoid any confusion, this book makes the period bigger, as illustrated: l rather than just .
|
||||
|
||||
There is another use of the period: as decimal point in real numbers, such as 3.14. Here, to avoid any confusion, the period is not made any bigger.
|
||||
|
||||
Some European languages use a comma rather than a period as the separator between integral and fractional parts of numbers. Here the conflict is irreconcilable, as in English the comma serves to separate parts of big numbers, as in “300,000 dollars”, where other languages would use a space. The committee discussions for Algol 60 almost collapsed when some continental members refused to bow to the majority’s choice of the period; the stalemate was resolved when someone suggested distinguishing between a reference language, fixed, and representation languages, parameterizable. (In retrospect, not such a great idea, at least not if you ever have to compile the same program in two different countries!) Today, few people would make this a point of contention, as the spread of digital watches and calculators built for world markets have accustomed almost everyone to alternate between competing conventions.
|
||||
|
||||
===Precedence and parentheses===
|
||||
The precedence conventions of the notation conform to tradition and to the “Principle of Least Surprise” to avoid errors and ambiguities.
|
||||
|
||||
Do not hesitate, however, to add parentheses for clarity; for example you may write (a = (b + c)) implies (u /= v) even though the meaning of that expression would be the same if all parentheses were removed. The examples in this book have systematically over-parenthesized expressions, in particular assertions, risking heaviness to avert uncertainty.
|
||||
|
||||
===The War of the Semicolons===
|
||||
Two clans inhabit the computing world, and the hatred between them is as ferocious as it is ancient. The Separatists, following Algol 60 and Pascal, fight for the recognition of the semicolon as a separator between instructions; the Terminatists, rallied behind the contrasting flags of PL/I, C and Ada, want to put a semicolon behind every instruction.
|
||||
|
||||
Each side’s arguments are endlessly relayed by its propaganda machine. The Terminatists worship uniformity: if every instruction is terminated by the same marker, no one ever has to ask the question “do I need a semicolon here?” (the answer in Terminatist languages is always yes, and anyone who forgets a semicolon is immediately beheaded for high treason). They do not want to have to add or remove a semicolon because an instruction has been moved from one syntactical location to another, for example if it has been brought into a conditional instruction or taken out of it.
|
||||
|
||||
The Separatists praise the elegance of their convention and its compatibility with mathematical practices. They see do instruction1; instruction2; instruction3 end as the natural counterpart of f (argument1, argument2, argument3). Who in his right mind, they ask, would prefer f (argument1, argument2, argument3,) with a superfluous final comma? They contend, furthermore, that the Terminatists are just a front for the Compilists, a cruel people whose only goal is to make life easy for compiler writers, even if that means making it hard for application developers.
|
||||
|
||||
The Separatists constantly have to fight against innuendo, for example the contention that Separatist languages will prevent you from including extra semicolons. Again and again they must repeat the truth: that every Separatist language worthy of the name, beginning with the venerated Patriarch of the tribe, Algol 60, has supported the notion of empty instruction, permitting all of
|
||||
<e>
|
||||
a; b; c
|
||||
a; b; c;
|
||||
; a ;; b ;;; c;
|
||||
</e>
|
||||
to be equally valid, and to mean exactly the same thing, as they only differ by the extra empty instructions of the last two variants, which any decent compiler will discard anyway. They like to point out how much more tolerant this convention makes them: whereas their fanatical neighbors will use any missing semicolon as an excuse for renewed attacks, the Separatists will gladly accept as many extra semicolons as a Terminatist transfuge may still, out of habit, drop into an outwardly Separatist text.
|
||||
|
||||
Modern propaganda needs science and statistics, so the Terminatists have their own experimental study, cited everywhere (in particular as the justification for the Terminatist convention of the Ada language): a 1975 measurement of the errors made by two groups of 25 programmers each, using languages that, among other distinguishing traits, treated semicolons differently. The results show the Separatist style causing almost ten times as many errors! Starting to feel the heat of incessant enemy broadcasts, the Separatist leadership turned for help to the author of the present book, who remembered a long-forgotten principle: quoting is good, but reading is better. So he fearlessly went back to the original article and discovered that the Separatist language used in the comparison — a mini-language meant only for “teaching students the concepts of asynchronous processes” — treats an extra semicolon after the final instruction of a compound, as in begin a; b; end, as an error! No real Separatist language, as noted above, has ever had such a rule, which would be absurd in any circumstance (as an extra semicolon is obviously harmless), and is even more so in the context of the article’s experiment since some of the subjects apparently had Terminatist experience from PL/I and so would have been naturally prone to add a few semicolons here and there. It then seems likely, although the article gives no data on this point, that many of the semicolon errors were a result of such normally harmless additions — enough to disqualify the experiment, once and for all, as a meaningful basis for defending Terminatism over Separatism.
|
||||
|
||||
On some of the other issues it studies, the article is not marred by such flaws in its test languages, so that it still makes good reading for people interested in language design.
|
||||
|
||||
All this shows, however, that it is dangerous to take sides in such a sensitive debate, especially for someone who takes pride in having friends in both camps. The solution adopted by the notation of this book is radical:
|
||||
|
||||
====Semicolon Syntax rule====
|
||||
Semicolons, as markers to delimit instructions, declarations or assertion clauses, are optional in almost all the positions where they may appear in the notation of this book.
|
||||
|
||||
|
||||
“Almost” because of a few rare cases, not encountered in this book, in which omitting the semicolon would cause a syntactical ambiguity.
|
||||
|
||||
The Semicolon Syntax rule means you can choose your style:
|
||||
|
||||
*Terminatist: every instruction, declaration or assertion clause ends with a semicolon.
|
||||
*Separatist: semicolons appear between successive elements but not, for example, after the last declaration of a feature or local clause.
|
||||
*Moderately Separatist: like the Separatist style, but not worrying about extra semicolons that may appear as a result of habit or of elements being moved from one context to another.
|
||||
*Discardist: no semicolons at all (except as per the Semicolon Style principle below).
|
||||
|
||||
This is one of the areas where it is preferable to let each user of the notation follow his own inclination, as the choice cannot cause serious damage. But do stick, at least across a class and preferably across an entire library or application, to the style that you have chosen (although this will not mean much for the Moderately Separatist style, which is by definition lax), and observe the following principle:
|
||||
|
||||
====Semicolon Style principle====
|
||||
If you elect to include semicolons as terminators (Terminatist style), do so for all applicable elements.
|
||||
|
||||
If you elect to forego semicolons, use them only when syntactically unavoidable, or to separate elements that appear on the same line.
|
||||
|
||||
|
||||
The second clause governs elements that appear two or more to a line, as in
|
||||
<e>
|
||||
found := found + 1; forth
|
||||
</e>
|
||||
|
||||
which should always include the semicolon; omitting it would make the line quite confusing.
|
||||
|
||||
Just for once, this discussion has no advice here, letting you decide which of the four styles you prefer. Since the earliest version of the notation required semicolons — in other words, it had not yet been tuned to support the Semicolon Syntax rule — the first edition of this book used a Separatist style. For the present one I dabbled into a few experiments; after polling a sizable group of co-workers and experienced users of the notation, I found (apart from a handful of Terminatists) an almost equal number of Discardists and Separatists. Some of the Discardists were very forceful, in particular a university professor who said that the main reason his students loved the notation is that they do not need semicolons — a comment which any future language designer, with or without grandiose plans, should find instructive or at least sobering.
|
||||
|
||||
You should defer to your own taste as long as it is consistent and respects the Semicolon Style principle. (As to this book: for a while I stuck to the original Separatist style, more out of habit than of real commitment; then, hearing the approach of the third millenium and its call to start a new life free of antique superstitions, I removed all the semicolons over a single night of utter debauchery.)
|
||||
|
||||
===Assertions===
|
||||
You should label assertion clauses to make the text more readable:
|
||||
<e>
|
||||
require
|
||||
not_too_small: index >= lower
|
||||
</e>
|
||||
|
||||
This convention also helps produce useful information during testing and debugging since, as you will remember, the assertion label will be included in the run-time message produced if you have enabled monitoring of assertions and one of them gets violated.
|
||||
|
||||
This convention will spread an assertion across as many lines as it has clauses. As a consequence, it is one of the rules to which the present book has made a few exceptions, again in the interest of saving space. When collapsing several clauses on one line, you should actually remove the labels for readability:
|
||||
<e>
|
||||
require
|
||||
index >= lower; index <= upper
|
||||
</e>
|
||||
In normal circumstances, that is to say for software texts rather than a printed textbook, better stick to the official rule and have one labeled clause per line.
|
||||
|
||||
==FONTS==
|
||||
In typeset software texts, the following conventions, used throughout this book and related publications, are recommended.
|
||||
|
||||
===Basic font rules===
|
||||
|
||||
Print software elements (class names, feature names, entitiesº) in italics to distinguish them from non-software text elements. This facilitates their inclusion in sentences of the non-software text, such as “We can see that the feature number is a query, not an attribute”. (The word number denotes the name of the feature; you do not want to mislead your reader into believing that you are talking about the number of features!)
|
||||
|
||||
Keywords, such as class, feature, invariant and the like, appear in boldface.
|
||||
|
||||
This was also the convention of the first edition of this book. At some stage it seemed preferable to use boldface italics which blends more nicely with italics. What was esthetically pleasing, however, turned out to hamper quality; some readers complained that the keywords did not stand out clearly enough, hence the return to the original convention. This is a regrettable case of fickleness. [M 1994a] and a handful of books by other authors show the intermediate convention.
|
||||
|
||||
Keywords play a purely syntactic role: they have no semantics of their own but delimit those elements, such as feature and class names, that do carry a semantic value. As noted earlier in this chapter, there are also a few non-keyword reserved words, such as Current and Result, which have a denotation of their own — expressions or entities. They are written in non-bold italics, with an initial upper-case letter.
|
||||
|
||||
Following the tradition of mathematics, symbols — colons and semicolons : ;, brackets [ ], parentheses ( ), braces { }, question and exclamation marks ? ! and so on — should always appear in roman (straight), even when they separate text in italics. Like keywords, they are purely syntactic elements.
|
||||
|
||||
Comments appear in roman. This avoids any ambiguity when a feature name — which, according to the principles seen earlier, will normally be a word from ordinary language — or an argument name appears in a comment; the feature name will be in italics and hence will stand out. For example:
|
||||
<e>
|
||||
accelerate (s: SPEED; t: REAL)
|
||||
-- Bring speed to s in at most t seconds.
|
||||
</e>
|
||||
<e>
|
||||
set_number (n: INTEGER)
|
||||
-- Make n the new value of number.
|
||||
</e>
|
||||
|
||||
In the software text itself, where no font variations are possible, such occurrences of formal elements in comments should follow a specific convention already mentioned earlier: they will appear preceded by a back quote ‘ and followed by a normal quote ’ , as in
|
||||
<e>
|
||||
-- Make ‘n’ the new value of ‘number’.
|
||||
</e>
|
||||
(Remember that you must use two different quote characters for opening and closing.) Tools that process class texts and can produce typeset output, such as short and flat, know this convention and so can make sure the quoted elements are printed in italics.
|
||||
|
||||
===Other font conventions===
|
||||
The preceding font conventions work well for a book, an article or a Web page. Some contexts, however, may call for different approaches. In particular, elements in plain italics, and sometimes even bold italics, are not always readable when projected on a projection screen, especially if what you are projecting is the output of a laptop computer with a relatively small display.
|
||||
|
||||
In such cases I have come to using the following conventions:
|
||||
|
||||
Use non-italics boldface for everything, as this projects best.
|
||||
|
||||
Choose a wide enough font, such as Bookman (for which boldface may be called “demibold”).
|
||||
|
||||
Instead of italics versus roman versus bold, use color to distinguish the various elements: keywords in black; comments in red; the rest (entities, feature names, expressionsº) in blue. More colors can be used to highlight special elements.
|
||||
|
||||
These conventions seem to work well, although there is always room for improvement, and new media will undoubtedly prompt new conventions.
|
||||
|
||||
===Color===
|
||||
The particularly attentive reader may by now have come to notice another convention used by this book: for added clarity, all formal elements — software texts or text extracts, but also mathematical elements — appear in color. This technique, which of course cannot be presented as a general requirement, enhances the effect of the rules seen so far on font usage.
|
||||
|
||||
==BIBLIOGRAPHICAL NOTES==
|
||||
*[Waldén 1995] is the source of the idea of showing by example that even a longer separated_by_underscores identifier is easier to read than an internalUpperCase identifier.
|
||||
*[Gannon 1975] is an experimental study of the effect of various language design choices on error rates.
|
||||
*The rules on standard feature names were first presented in [M 1990b] and are developed in detail in [M 1994a].
|
||||
*I received important comments from Richard Wiener on students’ appreciation of the optionality of semicolons, and from Kim Waldén on the respective merits of bold italics and plain bold.
|
||||
|
||||
==EXERCISES==
|
||||
===Header comment style===
|
||||
Rewrite the following header comments in the proper style:
|
||||
<e>
|
||||
reorder (s: SUPPLIER; t: TIME)
|
||||
-- Reorders the current part from supplier s, to be delivered
|
||||
-- on time t; this routine will only work if t is a time in the future.
|
||||
require
|
||||
not_in_past: t >= Now
|
||||
</e>
|
||||
<e>
|
||||
next_reorder_date: TIME
|
||||
-- Yields the next time at which the current part is scheduled
|
||||
-- to be reordered.
|
||||
</e>
|
||||
|
||||
===Semicolon ambiguity===
|
||||
Can you think of a case in which omitting a semicolon between two instructions or assertions could cause syntactic ambiguity, or at least confuse a simple-minded parser? (Hint: a feature call can have as its target a parenthesized expression, as in (vector1 + vector2) l count.)
|
||||
4
documentation/21.11/eiffel/Coding_Standards/index.wiki
Normal file
@@ -0,0 +1,4 @@
|
||||
[[Property:uuid|9396770A-E53B-4629-84A9-CB2A6680AAAD]]
|
||||
[[Property:weight|5]]
|
||||
[[Property:title|Coding Standards]]
|
||||
Below are the coding and style guidelines followed at Eiffel Software to write the Eiffel and C code of EiffelStudio.
|
||||
@@ -0,0 +1,68 @@
|
||||
[[Property:modification_date|Thu, 22 Nov 2018 19:50:45 GMT]]
|
||||
[[Property:publication_date|Thu, 22 Nov 2018 19:50:45 GMT]]
|
||||
[[Property:title|Example: Command line arguments]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|ba852d83-3c02-4d38-088a-60b76fe5c63f]]
|
||||
==Description==
|
||||
|
||||
Retrieve the list of command-line arguments given to the program.
|
||||
Example command line:
|
||||
<code lang="text">
|
||||
myprogram -c "alpha beta" -h "gamma"
|
||||
</code>
|
||||
|
||||
==Notes==
|
||||
|
||||
This class inherits functionality for dealing with command line arguments from class <code lang="eiffel">ARGUMENTS</code>. It uses the feature <code lang="eiffel">separate_character_option_value</code> to return the values by option name for each of the two arguments. <code lang="eiffel">ARGUMENTS</code> provides a rich set of features for command line argument processing.
|
||||
|
||||
The simple version in [[#Solution|Solution]] below is as submitted to Rosetta Code to illustrate class <code lang="eiffel">ARGUMENTS</code>, but it should be noted that <code lang="eiffel">separate_character_option_value</code> is of a detached type and will return a void reference if no value is found for a specified character option. Therefore, a safer version of the use of <code lang="eiffel">separate_character_option_value</code> would include object test on the result:
|
||||
|
||||
<code>
|
||||
if attached separate_character_option_value ('c') as l_val then
|
||||
print ("Command line argument value for option 'c' is: ")
|
||||
print (l_val + "%N")
|
||||
end
|
||||
if attached separate_character_option_value ('h') as l_val then
|
||||
print ("Command line argument value for option 'h' is: ")
|
||||
print (l_val + "%N")
|
||||
end
|
||||
</code>
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/Command-line_arguments Rosetta Code]
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
inherit
|
||||
ARGUMENTS
|
||||
create
|
||||
make
|
||||
feature {NONE} -- Initialization
|
||||
make
|
||||
-- Print values for arguments with options 'c' and 'h'.
|
||||
do
|
||||
print ("Command line argument value for option 'c' is: ")
|
||||
print (separate_character_option_value ('c') + "%N")
|
||||
print ("Command line argument value for option 'h' is: ")
|
||||
print (separate_character_option_value ('h') + "%N")
|
||||
io.read_line -- Keep console window open
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output (for command line arguments: -c "alpha beta" -h "gamma")==
|
||||
|
||||
<code lang="text">
|
||||
Command line argument value for option 'c' is: alpha beta
|
||||
Command line argument value for option 'h' is: gamma
|
||||
</code>
|
||||
|
||||
|
||||
{{SeeAlso|[[Execution_profiles|How to run with arguments]]}}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
[[Property:title|Example: Environment variables]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|60c39a34-0794-4c1f-a150-7431afa3e693]]
|
||||
==Description==
|
||||
|
||||
Using features from the class <code>EXECUTION_ENVIRONMENT</code> to create and retrieve an environment variable.
|
||||
|
||||
==Notes==
|
||||
|
||||
The <code>make</code> procedure of the class <code>APPLICATION</code> below uses the features <code>put</code> and <code>get</code>, inherited from the class <code>EXECUTION_ENVIRONMENT</code>, to create the environment variable <code>MY_VARIABLE</code> with value "Hello World!", and then to retrieve the value by key and print it.
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
inherit
|
||||
EXECUTION_ENVIRONMENT
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
make
|
||||
-- Create and retrieve an environment variable.
|
||||
do
|
||||
put ("Hello World!", "MY_VARIABLE")
|
||||
print (get ("MY_VARIABLE"))
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output==
|
||||
|
||||
<code lang="text">
|
||||
Hello World!
|
||||
</code>
|
||||
|
||||
|
||||
52
documentation/21.11/eiffel/Examples/example-file-io.wiki
Normal file
@@ -0,0 +1,52 @@
|
||||
[[Property:title|Example: File IO]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|b26aa8e3-5963-94ae-b523-642c8b79637b]]
|
||||
==Description==
|
||||
|
||||
Create a file "output.txt" containing the contents of "input.txt".
|
||||
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/File_IO Rosetta Code: File IO]
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
create input_file.make_open_read ("input.txt")
|
||||
create output_file.make_open_write ("output.txt")
|
||||
|
||||
from
|
||||
input_file.read_character
|
||||
until
|
||||
input_file.exhausted
|
||||
loop
|
||||
output_file.put (input_file.last_character)
|
||||
input_file.read_character
|
||||
end
|
||||
|
||||
input_file.close
|
||||
output_file.close
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
input_file: PLAIN_TEXT_FILE
|
||||
output_file: PLAIN_TEXT_FILE
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
|
||||
218
documentation/21.11/eiffel/Examples/example-polymorphism.wiki
Normal file
@@ -0,0 +1,218 @@
|
||||
[[Property:title|Example: Polymorphism]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|e4a9db32-c087-21b7-f0d6-4685f0ce249d]]
|
||||
==Description==
|
||||
|
||||
Create a class POINT and its heir CIRCLE to demonstrate polymorphic attachment and dynamic binding.
|
||||
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/Polymorphism Rosetta Code: Polymorphism]
|
||||
|
||||
Solution varies from Rosetta Code description (e. g., feature <code>out</code> is redefined in this solution, versus feature <code>print</code>.)
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
POINT
|
||||
inherit
|
||||
ANY
|
||||
redefine
|
||||
out
|
||||
end
|
||||
create
|
||||
make, make_origin
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_x, a_y: INTEGER)
|
||||
-- Create with values `a_x' and `a_y'
|
||||
do
|
||||
set_x (a_x)
|
||||
set_y (a_y)
|
||||
ensure
|
||||
x_set: x = a_x
|
||||
y_set: y = a_y
|
||||
end
|
||||
|
||||
make_origin
|
||||
-- Create at origin
|
||||
do
|
||||
ensure
|
||||
x_set: x = 0
|
||||
y_set: y = 0
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
x: INTEGER assign set_x
|
||||
-- Horizontal axis coordinate
|
||||
|
||||
y: INTEGER assign set_y
|
||||
-- Vertical axis coordinate
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_x (a_x: INTEGER)
|
||||
-- Set `x' coordinate to `a_x'
|
||||
do
|
||||
x := a_x
|
||||
ensure
|
||||
x_set: x = a_x
|
||||
end
|
||||
|
||||
set_y (a_y: INTEGER)
|
||||
-- Set `y' coordinate to `a_y'
|
||||
do
|
||||
y := a_y
|
||||
ensure
|
||||
y_set: y = a_y
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
out: STRING
|
||||
-- Display as string
|
||||
do
|
||||
Result := "Point: x = " + x.out + " y = " + y.out
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
<code>
|
||||
class
|
||||
CIRCLE
|
||||
|
||||
inherit
|
||||
POINT
|
||||
rename
|
||||
make as point_make
|
||||
redefine
|
||||
make_origin,
|
||||
out
|
||||
end
|
||||
create
|
||||
make, make_origin, make_from_point
|
||||
|
||||
feature -- Initialization
|
||||
|
||||
make (a_x, a_y, a_r: INTEGER)
|
||||
-- Create with values `a_x' and `a_y' and `a_r'
|
||||
require
|
||||
non_negative_radius_argument: a_r >= 0
|
||||
do
|
||||
point_make (a_x, a_y)
|
||||
set_r (a_r)
|
||||
ensure
|
||||
x_set: x = a_x
|
||||
y_set: y = a_y
|
||||
r_set: r = a_r
|
||||
end
|
||||
|
||||
make_origin
|
||||
-- Create at origin with zero radius
|
||||
do
|
||||
Precursor
|
||||
ensure then
|
||||
r_set: r = 0
|
||||
end
|
||||
|
||||
make_from_point (a_p: POINT; a_r: INTEGER)
|
||||
-- Initialize from `a_r' with radius `a_r'.
|
||||
require
|
||||
non_negative_radius_argument: a_r >= 0
|
||||
do
|
||||
set_x (a_p.x)
|
||||
set_y (a_p.y)
|
||||
set_r (a_r)
|
||||
ensure
|
||||
x_set: x = a_p.x
|
||||
y_set: y = a_p.y
|
||||
r_set: r = a_r
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
r: INTEGER assign set_r
|
||||
-- Radius
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_r (a_r: INTEGER)
|
||||
-- Set radius (`r') to `a_r'
|
||||
require
|
||||
non_negative_radius_argument: a_r >= 0
|
||||
do
|
||||
r := a_r
|
||||
ensure
|
||||
r_set: r = a_r
|
||||
end
|
||||
|
||||
feature -- Output
|
||||
|
||||
out: STRING
|
||||
-- Display as string
|
||||
do
|
||||
Result := "Circle: x = " + x.out + " y = " + y.out + " r = " + r.out
|
||||
end
|
||||
|
||||
invariant
|
||||
|
||||
non_negative_radius: r >= 0
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
local
|
||||
my_point: POINT
|
||||
my_circle: CIRCLE
|
||||
do
|
||||
create my_point.make_origin
|
||||
print (my_point.out + "%N")
|
||||
|
||||
create {CIRCLE} my_point.make_origin
|
||||
print (my_point.out + "%N")
|
||||
|
||||
create my_point.make (10, 15)
|
||||
print (my_point.out + "%N")
|
||||
|
||||
create {CIRCLE} my_point.make (20, 25, 5)
|
||||
print (my_point.out + "%N")
|
||||
|
||||
create my_circle.make (30, 35, 10)
|
||||
print (my_circle.out + "%N")
|
||||
|
||||
create my_circle.make_from_point (my_point, 35)
|
||||
print (my_circle.out + "%N")
|
||||
end
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output==
|
||||
|
||||
<code lang="text">
|
||||
Point: x = 0 y = 0
|
||||
Circle: x = 0 y = 0 r = 0
|
||||
Point: x = 10 y = 15
|
||||
Circle: x = 20 y = 25 r = 5
|
||||
Circle: x = 30 y = 35 r = 10
|
||||
Circle: x = 20 y = 25 r = 35
|
||||
</code>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
[[Property:title|Example: Reverse a string]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|d888d308-6bb7-edd5-ee25-92d04b5658d3]]
|
||||
==Description==
|
||||
|
||||
Reverse the order of the characters in a give string of characters.
|
||||
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/Reverse_a_string Rosetta Code]
|
||||
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
create
|
||||
make
|
||||
feature
|
||||
make
|
||||
-- Demonstrate string reversal.
|
||||
do
|
||||
my_string := "Hello World!"
|
||||
my_string.mirror
|
||||
print (my_string)
|
||||
end
|
||||
my_string: STRING
|
||||
-- Used for reversal
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output==
|
||||
|
||||
<code lang="text">
|
||||
!dlroW olleH
|
||||
</code>
|
||||
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
[[Property:title|Example: Self-initializing attributes and assigner commands]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|dbc107a4-42cd-606a-71b2-e0b70ac5482e]]
|
||||
==Description==
|
||||
|
||||
Example of using a [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attribute]] and an [[ET: The Dynamic Structure: Execution Model#Assigner commands|assigner command]].
|
||||
|
||||
==Notes==
|
||||
|
||||
The concepts of [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attributes]] and [[ET: The Dynamic Structure: Execution Model#Assigner commands|assigner commands]] are independent of one another. However, this example shows how each works in a small amount of code.
|
||||
|
||||
The example consists of two classes: a root class, and class <code>PERSON</code>. The <code>PERSON</code> class has a self-initializing attribute of type <code>STRING</code> named <code>mood</code>. If <code>mood</code> is accessed before it is explicitly initialized, then the self-initializing code after the keyword <code>attribute</code> will be executed, setting the default mood to "Happy".
|
||||
|
||||
The attribute <code>mood</code> also has an assigner command, the procedure <code>set_mood</code>, designated as such by the <code>assign</code> keyword. This allows clients of class <code>PERSON</code> to appear to assign directly to <code>mood</code>. However, the assigner command <code>set_mood</code> will always get executed, and its precondition will be in force during such an apparent assignment.
|
||||
|
||||
The root class <code>APPLICATION</code> creates an instance of <code>PERSON</code> and prints the value of <code>mood</code>, getting the self-iniitalized value. Then it assigns to <code>mood</code>. When it prints again, it gets the updated value.
|
||||
|
||||
==Source==
|
||||
|
||||
Adapted from an example given on the Eiffel Software Users Group.
|
||||
|
||||
==Solution==
|
||||
|
||||
A root class:
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Print and set mood of `my_person'.
|
||||
do
|
||||
create my_person
|
||||
print ("Mood: " + my_person.mood + "%N")
|
||||
my_person.mood := "Ecstatic"
|
||||
print ("Mood: " + my_person.mood + "%N")
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
my_person: PERSON
|
||||
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
Class PERSON:
|
||||
|
||||
<code>
|
||||
class
|
||||
PERSON
|
||||
|
||||
feature -- Access
|
||||
|
||||
mood: STRING assign set_mood
|
||||
attribute
|
||||
Result := "Happy"
|
||||
end
|
||||
|
||||
feature -- Element change
|
||||
|
||||
set_mood (a_string: STRING)
|
||||
require
|
||||
single_token: a_string.occurrences (' ') = 0
|
||||
do
|
||||
mood := a_string
|
||||
ensure
|
||||
mood_set: mood = a_string
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
==Output==
|
||||
|
||||
<code>
|
||||
Mood: Happy
|
||||
Mood: Ecstatic
|
||||
</code>
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
[[Property:title|Example: Sieve of Eratosthenes]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|e825c874-4266-b5ee-501c-221e6940dacd]]
|
||||
==Description==
|
||||
|
||||
Deliver prime numbers up to a specified integer limit. Compute prime numbers using sieve of Eratosthenes.
|
||||
|
||||
==Notes==
|
||||
|
||||
This example uses the ''iteration'' (<code>across</code>) form of the Eiffel loop construct to traverse a list, an array, and an integer interval.
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/Sieve_of_Eratosthenes Rosetta Code]
|
||||
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
|
||||
create
|
||||
make
|
||||
|
||||
feature
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
across primes_through (100) as ic loop print (ic.item.out + " ") end
|
||||
end
|
||||
|
||||
primes_through (a_limit: INTEGER): LINKED_LIST [INTEGER]
|
||||
-- Prime numbers through `a_limit'
|
||||
require
|
||||
valid_upper_limit: a_limit >= 2
|
||||
local
|
||||
l_tab: ARRAY [BOOLEAN]
|
||||
do
|
||||
create Result.make
|
||||
create l_tab.make_filled (True, 2, a_limit)
|
||||
across
|
||||
l_tab as ic
|
||||
loop
|
||||
if ic.item then
|
||||
Result.extend (ic.target_index)
|
||||
across ((ic.target_index * ic.target_index) |..| l_tab.upper).new_cursor.with_step (ic.target_index) as id
|
||||
loop
|
||||
l_tab [id.item] := False
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output==
|
||||
|
||||
<code lang="text">
|
||||
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
|
||||
</code>
|
||||
|
||||
|
||||
54
documentation/21.11/eiffel/Examples/example-sleep.wiki
Normal file
@@ -0,0 +1,54 @@
|
||||
[[Property:title|Example: Sleep]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|a846db1c-2096-43a9-bb8b-a233c9e21421]]
|
||||
==Description==
|
||||
|
||||
Write a program that does the following in this order:
|
||||
# Input an amount of time to sleep in whatever units are most natural for your language (milliseconds, seconds, ticks, etc.). This unit should be noted in comments or in a description.
|
||||
# Print "Sleeping..."
|
||||
# Sleep the main thread for the given amount of time.
|
||||
# Print "Awake!"
|
||||
# End.
|
||||
|
||||
==Notes==
|
||||
|
||||
The feature <code lang="eiffel">sleep</code> is defined in the library class <code>EXECUTION_ENVIRONMENT</code>. So the demonstration class <code>APPLICATION</code> inherits from <code>EXECUTION_ENVIRONMENT</code> in order to make <code lang="eiffel">sleep</code> available.
|
||||
|
||||
<code lang="eiffel">sleep</code> takes an argument which declares the number of nanoseconds to suspend the thread's execution.
|
||||
|
||||
==Source==
|
||||
|
||||
Problem description from [http://rosettacode.org/wiki/Sleep Rosetta Code]
|
||||
|
||||
==Solution==
|
||||
|
||||
<code>
|
||||
class
|
||||
APPLICATION
|
||||
inherit
|
||||
EXECUTION_ENVIRONMENT
|
||||
create
|
||||
make
|
||||
feature -- Initialization
|
||||
make
|
||||
-- Sleep for a given number of nanoseconds.
|
||||
do
|
||||
print ("Enter a number of nanoseconds: ")
|
||||
io.read_integer_64
|
||||
print ("Sleeping...%N")
|
||||
sleep (io.last_integer_64)
|
||||
print ("Awake!%N")
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==Output (sleeping 10 seconds)==
|
||||
|
||||
<code lang="text">
|
||||
Enter a number of nanoseconds: 10000000000
|
||||
Sleeping...
|
||||
Awake!
|
||||
</code>
|
||||
|
||||
|
||||
10
documentation/21.11/eiffel/Examples/index.wiki
Normal file
@@ -0,0 +1,10 @@
|
||||
[[Property:title|Examples]]
|
||||
[[Property:description|how common programming problems can be solved using Eiffel]]
|
||||
[[Property:weight|6]]
|
||||
[[Property:uuid|1a59e03b-8bf0-8426-43b4-577761e40790]]
|
||||
Here you will find examples of how common programming problems can be solved using Eiffel.
|
||||
|
||||
A set of examples is also included with the EiffelStudio distribution kit.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
[[Property:modification_date|Mon, 10 Sep 2018 09:10:34 GMT]]
|
||||
[[Property:publication_date|Mon, 10 Sep 2018 09:10:34 GMT]]
|
||||
[[Property:title|Introduction to the Examples Book]]
|
||||
[[Property:weight|-1]]
|
||||
[[Property:uuid|044fa742-f3ca-9f5b-01cc-7194ee172b08]]
|
||||
|
||||
EiffelStudio comes with a rich set of examples that you can use to learn how to use the many Eiffel facilities and libraries. You should look first to the examples distributed with EiffelStudio as your primary source of samples of Eiffel in use.
|
||||
|
||||
The examples in this book are somewhat different in nature and serve a different purpose.
|
||||
|
||||
Although some of the examples included here are provided by Eiffel Software, the intent is that the majority of the entries will be contributed by people like you who use Eiffel daily to solve real problems.
|
||||
|
||||
The inspiration for this book is the many ''program chrestomathies'' on the World-Wide Web. In natural language, a chrestomathy is a set of literary passages explicitly selected for the purpose of helping learn a language. A program chrestomathy is a set of problems for which solutions are represented in various programming languages with the aim of allowing programmers to compare language capabilities and programming techniques.
|
||||
|
||||
Program chrestomathies vary widely. At one end of the spectrum [http://99-bottles-of-beer.net/ 99 Bottles of Beer] has collected solutions in over one thousand programming languages, all targeted to a single problem: generate and print the complete lyrics of the song ''99 Bottles of Beer on the Wall''. There are several "Hello world!" chrestomathies. Other sites host multiple programming problems, all with solutions in many languages. One large multi-problem site is [http://rosettacode.org/wiki/Main_Page Rosetta Code]. In fact, Rosetta Code maintains a [http://rosettacode.org/wiki/Help:Similar_Sites list of links to many of the Web's other programming chrestomathy projects].
|
||||
|
||||
Eiffel has a presence on many of these sites. Still, the more examples, the better.
|
||||
|
||||
The purpose of the examples in this book, then, is two-fold. First, we get a set of Eiffel examples in the Eiffel online documentation with solutions to a different set of problems than the examples distributed with EiffelStudio. Second, examples from this set can be migrated to Rosetta Code or one of the other chrestomathies to improve Eiffel's presence on those sites. (The caveat to contributors is clear: '''Contribute only work that you have the authority to release, and only if you are willing to have your work shared on one or more of the program chrestomathies.''' By submitting content to this Examples book, you agree to release that content under terms no more restrictive than the GNU Free Documentation License.)
|
||||
|
||||
Sites like Rosetta Code and [http://en.literateprograms.org/LiteratePrograms:Welcome Literate Programs] offer a wide variety of programming problems or tasks for comparison of languages and techniques. Rosetta Code provides an index to the [http://rosettacode.org/wiki/Reports:Tasks_not_implemented_in_Eiffel tasks not yet implemented in Eiffel].
|
||||
|
||||
This book should include, but not necessarily be limited to, certain of the problems used as challenges by program chrestomathies.
|
||||
|
||||
|
||||
|
||||
6
documentation/21.11/eiffel/Language_reference/index.wiki
Normal file
@@ -0,0 +1,6 @@
|
||||
[[Property:title|Language reference]]
|
||||
[[Property:link_title|Language]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:uuid|17412f30-0451-4b2b-bdec-578ca2e619a6]]
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
[[Property:modification_date|Wed, 11 Sep 2019 23:28:26 GMT]]
|
||||
[[Property:publication_date|Wed, 11 Sep 2019 23:28:26 GMT]]
|
||||
[[Property:uuid|C652AC71-8BAD-4387-A46C-21C9F5C3A68F]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:title|Conditional expression]]
|
||||
[[Property:link_title|Conditional]]
|
||||
|
||||
[[Eiffel_programming_language_syntax#Conditionals|Conditional expressions]] compute a value using different expressions depending on one or more conditions. If all expressions have the same type, the conditional expression as a whole has this type as well:
|
||||
|
||||
<e>
|
||||
if time < noon then
|
||||
"Good morning"
|
||||
elseif time < evening then
|
||||
"Good afternoon"
|
||||
else
|
||||
"Good evening"
|
||||
end
|
||||
</e>
|
||||
|
||||
has type `STRING`.
|
||||
|
||||
If the types of the expressions are different, the [[Types#Common_ancestor_types|common ancestor type]] is used as a type of the whole expression.
|
||||
|
||||
<e>
|
||||
if time < noon then
|
||||
"Good morning"
|
||||
else
|
||||
Void
|
||||
end
|
||||
</e>
|
||||
|
||||
has type `detachable STRING`.
|
||||
@@ -0,0 +1,85 @@
|
||||
[[Property:uuid|3C1A6DEF-A6F1-4E64-A0BE-C07BDB382C93]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:title|Manifest array]]
|
||||
|
||||
A manifest array is an expression denoting an array by simply listing its elements, as in `<<1, 4, 9, 16, 25>>`. The lower index is always `1` and the upper index is the number of items, `5` in this example.
|
||||
|
||||
The type of a manifest array is always `ARRAY [T]` where `T` is a type to which all the elements conform, `INTEGER` in the previous example. In case of a possible ambiguity you can make the type explicit, as in `{ARRAY [COMPARABLE]} <<7, "Eiffel">>`, where both `INTEGER`, the type of `7`, and `STRING`, the type of `"Eiffel"`, conform to `COMPARABLE`.
|
||||
|
||||
== What are manifest arrays good for? ==
|
||||
|
||||
Use a manifest array to initialize an element by simply listing its initial elements. For example, with the declaration
|
||||
|
||||
```eiffel
|
||||
squares: ARRAY [INTEGER]
|
||||
```
|
||||
|
||||
you can initialize `squares` through
|
||||
|
||||
```eiffel
|
||||
squares := <<1, 4, 9, 16, 25>>
|
||||
```
|
||||
|
||||
This is simpler than the alternative, which would be to create the array explicitly and give a value to every element in turn:
|
||||
```eiffel
|
||||
-- Arguments to `make_filled` are: default value, lower bound, upper bound.
|
||||
create squares.make_filled (0, 1, 5)
|
||||
squares [1] := 1
|
||||
squares [2] := 4
|
||||
squares [3] := 9
|
||||
squares [4] := 16
|
||||
squares [5] := 25
|
||||
```
|
||||
|
||||
The first form, with the manifest array, is shorter, but the effect is the same.
|
||||
|
||||
Manifest arrays are normal arrays, not restricted in any way. You can for example add elements to them, as in
|
||||
|
||||
```eiffel
|
||||
-- Arguments to `force` are: value, position.
|
||||
squares.force (36, 6)
|
||||
```
|
||||
|
||||
which will resize the array to bounds 1 and 6.
|
||||
|
||||
== Type of a manifest array: the implicit case ==
|
||||
|
||||
If you do not explicitly specify an array type, the type of the manifest array is as follows:
|
||||
|
||||
* For an empty manifest array `<<>>`: `ARRAY [NONE]`. (In the following cases we assume the array is not empty.)
|
||||
|
||||
* If all elements are of the same exact type `T`: `ARRAY [T]`.
|
||||
|
||||
* If the types of all elements all conform to a type `T`: `ARRAY [T]`. Note that in this case `T` is unique since two different types cannot conform to each other. (The preceding case, all types identical, is a special case of this one, since a type conforms to itself.)
|
||||
|
||||
* Otherwise: `ARRAY [ANY]`.
|
||||
|
||||
As an example of the third case (conformance of all elements to one of them), assume `POLYGON` and `CIRCLE` both conform to `FIGURE`. Then the manifest array `<<a_polygon, a_figure, a_circle>>`, with `a_polygon` of type `POLYGON` and so on, is `ARRAY [FIGURE]`.
|
||||
|
||||
== Type of a manifest array: the explicit case ==
|
||||
|
||||
With the preceding rule, the type of `<<7, "Eiffel">>` is the most general possible one, `ARRAY [ANY]`, since `INTEGER` and `STRING` do not conform to each other (either way). If you are not happy with this default type, you can make the array type explicit by writing it in braces:
|
||||
|
||||
```eiffel
|
||||
{ARRAY [COMPARABLE]} <<7, "Eiffel">>
|
||||
```
|
||||
|
||||
The rule in such a case is that in `{ARRAY [T]} <<element1, element2, ...>>` the types of all elements must conform to `T`.
|
||||
|
||||
As another example, with
|
||||
|
||||
```eiffel
|
||||
figures: ARRAY [FIGURE]
|
||||
```
|
||||
|
||||
you cannot assign `<<a_polygon, a_circle>>` to `figures` since the type of the manifest array is `ARRAY [ANY]`. To make this assignment possible, use an explicit type:
|
||||
|
||||
```eiffel
|
||||
figures := {ARRAY [FIGURE]} <<a_polygon, a_circle>>
|
||||
```
|
||||
|
||||
You can also use this form to give an explicit type to an empty array, which would otherwise be of type `ARRAY [NONE]`. For example, with `figures` declared as above:
|
||||
|
||||
```eiffel
|
||||
figures := {ARRAY [FIGURE]} <<>>
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
[[Property:uuid|F904B70B-4C34-459B-A146-E10C7EC30136]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:title|Expressions]]
|
||||
|
||||
[[Eiffel%20programming%20language%20syntax#Expressions|Expressions]] are used to compute a value at run-time and have an associated type at compile-time.
|
||||
@@ -0,0 +1,44 @@
|
||||
[[Property:uuid|88764AFC-7DC5-4547-8B8C-4C0A489B0620]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:title|Types]]
|
||||
|
||||
== Common ancestor type ==
|
||||
|
||||
A '''common ancestor type''' is a type computed for a list of types using the following algorithm:
|
||||
|
||||
# Add `NONE` to the list of types (to make sure the list is never empty).
|
||||
# If there is a separate type in the list, add a mark `separate` in front of all non-separate types in the list.
|
||||
# If there is a detachable type in the list, add a mark `detachable` in front of all attached types in the list.
|
||||
# If there is a type in the list to which all other types conform, it is the common ancestor type.
|
||||
# Otherwise, add `ANY` to the list and repeat steps starting from step #2.
|
||||
|
||||
|
||||
Here are some examples:
|
||||
{|
|
||||
! Type list
|
||||
! Common ancestor type
|
||||
|-
|
||||
| (empty)
|
||||
| <e>NONE</e>
|
||||
|-
|
||||
| <e>BOOLEAN</e>
|
||||
| <e>BOOLEAN</e>
|
||||
|-
|
||||
| <e>BOOLEAN, BOOLEAN</e>
|
||||
| <e>BOOLEAN</e>
|
||||
|-
|
||||
| <e>INTEGER_32, REAL_64, COMPARABLE</e>
|
||||
| <e>COMPARABLE</e>
|
||||
|-
|
||||
| <e>INTEGER_32, REAL_64</e>
|
||||
| <e>ANY</e>
|
||||
|-
|
||||
| <e>INTEGER_32, detachable COMPARABLE</e>
|
||||
| <e>detachable COMPARABLE</e>
|
||||
|-
|
||||
| <e>INTEGER_32, separate COMPARABLE</e>
|
||||
| <e>separate COMPARABLE</e>
|
||||
|-
|
||||
| <e>detachable STRING, separate COMPARABLE</e>
|
||||
| <e>detachable separate COMPARABLE</e>
|
||||
|}
|
||||
@@ -0,0 +1,525 @@
|
||||
[[Property:modification_date|Thu, 13 Aug 2020 00:59:54 GMT]]
|
||||
[[Property:publication_date|Wed, 11 Sep 2019 14:10:27 GMT]]
|
||||
[[Property:title|Eiffel programming language reserved words]]
|
||||
[[Property:link_title|Reserved words]]
|
||||
[[Property:weight|1]]
|
||||
[[Property:uuid|047ce062-45de-f25c-f356-ee8ec0fc2d1d]]
|
||||
In the Eiffel programming language, there are certain words that are considered "reserved". These words have specific meanings recognized by the compiler. As such, it is invalid to attempt to use a reserved word as an ordinary language identifier.
|
||||
|
||||
The reserved words listed in the ISO/ECMA standard are shown below with a brief explanation of their meanings. Links are given where appropriate to the syntax definitions and to descriptions in the online documentation. Occasionally, references to the June 2006 standard document are used and are recognizable as clause numbers in parentheses, i.e., three integers separated by dots, for example: (8.14.1)
|
||||
|
||||
|
||||
{{info|The list below includes all the Eiffel reserved words. Some of these words are considered ''language keywords'' while others are not. The distinction is that language keywords are reserved words that are used only as syntactical markers, and have no inherent semantic value. Examples are the keywords <code>do</code> and <code>end</code>. Non-keyword reserved words are those that do carry semantic value, such as <code>True</code> and <code>Current</code>.}}
|
||||
|
||||
|
||||
{{note|The set of reserved words supported by the Eiffel Software implementation may vary somewhat from those specified in the current standard. See the [[Differences between standard ECMA-367 and Eiffel Software implementation|"differences" chapter of the online documentation]] for information on these variances.}}
|
||||
|
||||
|
||||
==Reserved words==
|
||||
|
||||
===across===
|
||||
|
||||
Introduces an [[ET: Instructions#Loop|iteration]].
|
||||
|
||||
===agent===
|
||||
|
||||
Used to specify an [[ET: Agents|agent]].
|
||||
|
||||
:[[Eiffel programming language syntax#Agents|Syntax.]]
|
||||
|
||||
|
||||
===alias===
|
||||
|
||||
Used to identify an alternative or alias feature name.
|
||||
|
||||
:[[Eiffel programming language syntax#Feature names|Syntax.]]
|
||||
|
||||
[[ET: The Dynamic Structure: Execution Model#Infix and prefix notations|Usage for infix/prefix notations.]]
|
||||
|
||||
[[ET: The Static Picture: System Organization#External software|Usage in interfaces to external software.]]
|
||||
|
||||
:[[Eiffel programming language syntax#External routines|Syntax.]]
|
||||
|
||||
|
||||
===all===
|
||||
|
||||
Used in [[ET: Inheritance#Changing the export status|export adaptation]] to indicate that a chosen export status applies to all features inherited from a given parent.
|
||||
|
||||
:[[Eiffel programming language syntax#Export adaptation|Syntax.]]
|
||||
|
||||
|
||||
===and===
|
||||
|
||||
The logical conjunction [[Eiffel programming language syntax#Operators|operator]]. Strict when used alone, nonstrict when used with [[#then|then]].
|
||||
|
||||
|
||||
===as===
|
||||
|
||||
Used when [[ET: Inheritance#Multiple inheritance and renaming|renaming]] features in descendant classes.
|
||||
|
||||
:[[Eiffel programming language syntax#Rename clauses|Syntax.]]
|
||||
|
||||
|
||||
===assign===
|
||||
|
||||
Used to designate [[ET: The Dynamic Structure: Execution Model#Abstraction|assigner commands]].
|
||||
|
||||
:[[Eiffel programming language syntax#Assigner marks|Syntax.]]
|
||||
|
||||
|
||||
===attribute===
|
||||
|
||||
Introduces an attribute body, as in [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attributes]].
|
||||
|
||||
:[[Eiffel programming language syntax#Attribute bodies|Syntax.]]
|
||||
|
||||
|
||||
===check===
|
||||
|
||||
Identifies a [[ET: Other Mechanisms#Check|check instruction]].
|
||||
|
||||
:[[Eiffel programming language syntax#Check instructions|Syntax.]]
|
||||
|
||||
|
||||
===class===
|
||||
|
||||
Used in a class header in the declaration of a [[ET: The Dynamic Structure: Execution Model#A simple class|class]].
|
||||
|
||||
:[[Eiffel programming language syntax#Class headers|Class header syntax.]]
|
||||
|
||||
|
||||
===convert===
|
||||
|
||||
Used in converter clauses.
|
||||
|
||||
:[[Eiffel programming language syntax#Converter clauses|Syntax.]]
|
||||
|
||||
Used in feature names for operator aliases, supporting mixed type expressions causing a conversion of the target (8.5.14).
|
||||
|
||||
:[[Eiffel programming language syntax#Feature names|Syntax.]]
|
||||
|
||||
|
||||
===create===
|
||||
|
||||
In the creators part of a class, introduces those procedures which can be used to [[ET: The Dynamic Structure: Execution Model#Creating and initializing objects|initialize instances]].
|
||||
|
||||
:[[Eiffel programming language syntax#Creators parts|Syntax.]]
|
||||
|
||||
Introduces a [[ET: The Dynamic Structure: Execution Model#Creating and initializing objects|creation instruction]].
|
||||
|
||||
:[[Eiffel programming language syntax#Creation instructions|Syntax.]]
|
||||
|
||||
Introduces a creation expression (8.20.18)
|
||||
|
||||
:[[Eiffel programming language syntax#Creation expressions|Syntax.]]
|
||||
|
||||
In [[ET: Inheritance#Constrained genericity|constrained genericity]], introduces a list of names of features which can be used as creation procedures with a generic class for a particular formal generic parameter. (8.12.10)
|
||||
|
||||
:[[Eiffel programming language syntax#Generic constraints|Syntax.]]
|
||||
|
||||
|
||||
===Current===
|
||||
|
||||
A predefined entity indicating the current object.
|
||||
|
||||
:[[Eiffel programming language syntax#Entities and variables|Entity syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Types|Anchored types syntax.]]
|
||||
|
||||
|
||||
===debug===
|
||||
|
||||
Introduces a [[ET: Other Mechanisms#Debug|debug instruction]].
|
||||
|
||||
:[[Eiffel programming language syntax#Debug Instructions|Syntax.]]
|
||||
|
||||
|
||||
===deferred===
|
||||
|
||||
Used in class header to indicate a [[ET: Inheritance#Deferred features and classes|deferred class]].
|
||||
|
||||
:[[Eiffel programming language syntax#Class headers|Syntax.]]
|
||||
|
||||
Used in routine body to indicate a [[ET: Inheritance#Deferred features and classes|deferred feature]].
|
||||
|
||||
:[[Eiffel programming language syntax#Routine bodies|Syntax.]]
|
||||
|
||||
|
||||
===do===
|
||||
|
||||
Introduces a sequence of instructions as a routine body, as shown in the [[ET: Hello World|Hello World]] example.
|
||||
|
||||
:[[Eiffel programming language syntax#Routine bodies|Syntax.]]
|
||||
|
||||
|
||||
===else===
|
||||
|
||||
Used in [[ET-_Instructions#Conditional|conditional]] and [[ET-_Instructions#Multi-branch|multi-branch]] instructions to introduce a sequence of instructions to be executed in the case that no specified conditions are met.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Multi-branch instructions|Multi-branch syntax.]]
|
||||
|
||||
Used in a [[Conditional_expression|conditional expression]] to compute a value in the case that no specified conditions are met.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional expression syntax.]]
|
||||
|
||||
Used as part of the double reserved word <code>or else</code>, the semi-strict disjunction operator.
|
||||
|
||||
:[[Eiffel programming language syntax#Operators|Syntax.]]
|
||||
|
||||
Used after the reserved word [[#require|<code>require</code>]] as a precondition extension, allowing the weakening of an inherited precondition (8.10.3).
|
||||
|
||||
:[[Eiffel programming language syntax#Assertions|Syntax.]]
|
||||
|
||||
|
||||
===elseif===
|
||||
|
||||
Used in [[ET-_Instructions#Conditional|conditional]] instructions to effect a "multi-branch" choice instruction.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Syntax.]]
|
||||
|
||||
Used in a [[Conditional_expression|conditional expression]] to effect a "multi-branch" choice to compute of a value.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional expression syntax.]]
|
||||
|
||||
|
||||
===end===
|
||||
|
||||
Serves to terminate several Eiffel programming language constructs.
|
||||
|
||||
:Syntax for:
|
||||
::[[Eiffel programming language syntax#Class declarations|Class declarations]]
|
||||
::[[Eiffel programming language syntax#Feature bodies|Feature bodies]]
|
||||
::[[Eiffel programming language syntax#Inheritance parts|Inheritance parts]]
|
||||
::[[Eiffel programming language syntax#Check instructions|Check instructions]]
|
||||
::[[Eiffel programming language syntax#Generic constraints|Generic constraints: renaming and constraint creators]]
|
||||
::[[Eiffel programming language syntax#Conditionals|Conditional instructions]]
|
||||
::[[Eiffel programming language syntax#Multi-branch instructions|Multi-branch instructions]]
|
||||
::[[Eiffel programming language syntax#Conditionals|Conditional expressions]]
|
||||
::[[Eiffel programming language syntax#Loops|Loops]]
|
||||
::[[Eiffel programming language syntax#Debug instructions|Debug instructions]]
|
||||
|
||||
|
||||
===ensure===
|
||||
|
||||
Introduces a [[ET: Design by Contract (tm), Assertions and Exceptions#Expressing assertions|postcondition]].
|
||||
|
||||
When followed by the reserved word [[#then|<code>then</code>]] denotes a postcondition extension, allowing the strengthening of an inherited postcondition (8.10.3).
|
||||
|
||||
:[[Eiffel programming language syntax#Assertions|Syntax.]]
|
||||
|
||||
|
||||
===expanded===
|
||||
|
||||
Used in a class header to indicate that a class is [[ET: The Dynamic Structure: Execution Model#Type categories|expanded]].
|
||||
|
||||
:[[Eiffel programming language syntax#Class headers|Syntax.]]
|
||||
|
||||
|
||||
===export===
|
||||
|
||||
Used to [[ET: Inheritance#Changing the export status|change the export status]] (availability to clients) of inherited features.
|
||||
|
||||
:[[Eiffel programming language syntax#Export adaptation|Syntax.]]
|
||||
|
||||
|
||||
===external===
|
||||
|
||||
Denotes an [[ET: The Static Picture: System Organization#External software|external routine]]. External routines are commonly defined to interface with [[C externals|C external routines]] and [[C++ Externals|C++ external routines]].
|
||||
|
||||
:[[Eiffel programming language syntax#External routines|Syntax]]
|
||||
|
||||
|
||||
===False===
|
||||
|
||||
Boolean manifest constant.
|
||||
|
||||
:[[Eiffel programming language syntax#Manifest constants|Syntax.]]
|
||||
|
||||
|
||||
===feature===
|
||||
|
||||
Introduces a [[ET: Hello World|feature clause]].
|
||||
|
||||
:[[Eiffel programming language syntax#Feature parts|Syntax.]]
|
||||
|
||||
|
||||
===from===
|
||||
|
||||
Used in [[ET: Other Mechanisms#Loop|loop]] initialization.
|
||||
|
||||
:[[Eiffel programming language syntax#Loops|Syntax.]]
|
||||
|
||||
|
||||
===frozen===
|
||||
|
||||
Used in a class header to mark a class explicitly as frozen. A frozen class prohibits it from serving as a "conforming parent" to other classes. (8.4.5).
|
||||
|
||||
:[[Eiffel programming language syntax#Class headers|Syntax.]]
|
||||
|
||||
Used in a feature declaration to mark a feature as frozen. A frozen feature cannot be redefined by heir classes.
|
||||
|
||||
:[[Eiffel programming language syntax#New feature lists|Syntax.]]
|
||||
|
||||
Used with a formal generic parameter to indicate that conformance of generic derivations of the class require identical actual generic parameters. (8.12.3)
|
||||
|
||||
:[[Eiffel programming language syntax#Formal generic parameters|Syntax.]]
|
||||
|
||||
|
||||
===if===
|
||||
|
||||
Used to introduce a [[ET-_Instructions#Conditional|conditional]].
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional syntax.]]
|
||||
|
||||
Used to introduce a [[Conditional_expression|Conditional expression]].
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional expression syntax.]]
|
||||
|
||||
|
||||
===implies===
|
||||
|
||||
The semi-strict logical implication [[Eiffel programming language syntax#Operators|operator]].
|
||||
|
||||
|
||||
===inherit===
|
||||
|
||||
Used in an [[ET: Inheritance|inherit]] clause.
|
||||
|
||||
:[[Eiffel programming language syntax#Inheritance parts|Syntax.]]
|
||||
|
||||
|
||||
===inspect===
|
||||
|
||||
Introduces a [[ET-_Instructions#Multi-branch|multi-branch]] instruction.
|
||||
|
||||
:[[Eiffel programming language syntax#Multi-branch instructions|Syntax.]]
|
||||
|
||||
|
||||
===invariant===
|
||||
|
||||
Used to introduce an invariant assertion as a [[ET: Design by Contract (tm), Assertions and Exceptions#Class invariants|class invariant]] or [[ET: Instructions#Loop|loop invariant]].
|
||||
|
||||
:[[Eiffel programming language syntax#Assertions|Assertions syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Class declarations|Syntax of class declaration including class invariant.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Loops|Syntax of loop including loop invariant.]]
|
||||
|
||||
|
||||
===like===
|
||||
|
||||
Used in the declaration of an [[ET: Inheritance#Covariance and anchored declarations|anchored]] entity.
|
||||
|
||||
:[[Eiffel programming language syntax#Types|Syntax.]]
|
||||
|
||||
|
||||
===local===
|
||||
|
||||
Introduces the [[ET: The Dynamic Structure: Execution Model#Entities|local variable]] declarations in a feature body.
|
||||
|
||||
:[[Eiffel programming language syntax#Feature bodies|Feature bodies syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Local variables|Local variable declarations syntax.]]
|
||||
|
||||
|
||||
===loop===
|
||||
|
||||
Introduces a [[ET: Other Mechanisms#Loop|loop]] body.
|
||||
|
||||
:[[Eiffel programming language syntax#Loops|Syntax.]]
|
||||
|
||||
|
||||
===not===
|
||||
|
||||
The logical negation [[Eiffel programming language syntax#Operators|operator]].
|
||||
|
||||
|
||||
===note===
|
||||
|
||||
Used to begin a Notes part, in a [[Eiffel programming language syntax#Class declarations|class declaration]], a [[Eiffel programming language syntax#Feature declarations|feature declaration]], or a [[Eiffel programming language syntax#Check instructions|check instruction]].
|
||||
|
||||
:[[Eiffel programming language syntax#Notes|Syntax.]]
|
||||
|
||||
|
||||
===obsolete===
|
||||
|
||||
Used to mark [[ET: Other Mechanisms#Obsolete features and classes|obsolete features and classes]].
|
||||
|
||||
:[[Eiffel programming language syntax#Feature declarations|Feature declarations syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Class declarations|Class declarations declarations syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Obsolete marks|Obsolete mark syntax.]]
|
||||
|
||||
|
||||
===old===
|
||||
|
||||
Introduces an ''old expression''. Old expressions are valid only in the [[ET: Design by Contract (tm), Assertions and Exceptions#Postconditions|postconditions]] of routines.
|
||||
|
||||
:[[Eiffel programming language syntax#Old postcondition expressions|Syntax.]]
|
||||
|
||||
|
||||
===once===
|
||||
|
||||
Used to introduce [[ET: Other Mechanisms#Once routines and shared objects|once routines]] and once string expressions.
|
||||
|
||||
:[[Eiffel programming language syntax#Routine bodies|Once routine syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Expressions|Once string syntax.]]
|
||||
|
||||
|
||||
===only===
|
||||
|
||||
Used in an ''only postcondition clause''. (8.9.11)
|
||||
|
||||
:[[Eiffel programming language syntax#"Old" postcondition expressions|Syntax.]]
|
||||
|
||||
|
||||
===or===
|
||||
|
||||
The logical disjunction [[Eiffel programming language syntax#Operators|operator]]. Strict when used alone, nonstrict when used with [[#else|else]].
|
||||
|
||||
|
||||
===Precursor===
|
||||
|
||||
Allows a redefined routine to access the routine it redefines, i.e, its [[ET: Inheritance#Redefinition|precursor]].
|
||||
|
||||
:[[Eiffel programming language syntax#Precursor|Syntax.]]
|
||||
|
||||
|
||||
===redefine===
|
||||
|
||||
Used in an [[Eiffel programming language syntax#Inheritance parts|inheritance part]] of a [[Eiffel programming language syntax#Class declarations|class declaration]] to list those inherited features which, in the heir class, will receive new implementations, specifications, or both, i.e, those features being [[ET: Inheritance#Redefinition|redefined]].
|
||||
|
||||
:[[Eiffel programming language syntax#Redefinition|Redefine syntax.]]
|
||||
|
||||
|
||||
===rename===
|
||||
|
||||
Used in an [[Eiffel programming language syntax#Inheritance parts|inheritance part]] of a [[Eiffel programming language syntax#Class declarations|class declaration]] to [[ET: Inheritance#Multiple inheritance and renaming|provide alternative names]] for inherited features in an heir class.
|
||||
|
||||
Used to rename features in a [[Eiffel programming language syntax#Generic constraints|generic constraint]]. (8.12.8).
|
||||
|
||||
:[[Eiffel programming language syntax#Rename clauses|Syntax.]]
|
||||
|
||||
|
||||
===require===
|
||||
|
||||
Introduces a [[ET: Design by Contract (tm), Assertions and Exceptions#Expressing assertions|precondition]].
|
||||
|
||||
When followed by the reserved word [[#else|<code>else</code>]] denotes a precondition extension, allowing the weakening of an inherited precondition (8.10.3).
|
||||
|
||||
:[[Eiffel programming language syntax#Assertions|Syntax.]]
|
||||
|
||||
|
||||
|
||||
===rescue===
|
||||
|
||||
Introduces a [[ET: Design by Contract (tm), Assertions and Exceptions#Exception handling|rescue clause]] in a [[Eiffel programming language syntax#Feature bodies|feature body]].
|
||||
|
||||
:[[Eiffel programming language syntax#Rescue clauses|Syntax.]]
|
||||
|
||||
|
||||
===Result===
|
||||
|
||||
A predefined [[ET: The Dynamic Structure: Execution Model#Entities|entity]] used to represent the final result of a function.
|
||||
|
||||
:[[Eiffel programming language syntax#Entities and variables|Syntax.]]
|
||||
|
||||
|
||||
===retry===
|
||||
|
||||
An [[Eiffel programming language syntax#Instructions|instruction]] valid only in [[Eiffel programming language syntax#Rescue clauses|rescue clauses]] and used to [[ET: Design by Contract (tm), Assertions and Exceptions#Exception handling|re-execute the routine]] in which it appears.
|
||||
|
||||
:[[Eiffel programming language syntax#Rescue clauses|Syntax.]]
|
||||
|
||||
|
||||
===select===
|
||||
|
||||
Used in an [[Eiffel programming language syntax#Inheritance parts|inheritance part]] of a [[Eiffel programming language syntax#Class declarations|class declaration]] to resolve possible ambiguities related to polymorphism and dynamic binding in the presence of [[ET: Inheritance#Repeated inheritance and selection|repeated inheritance]].
|
||||
|
||||
:[[Eiffel programming language syntax#Select clauses|Syntax.]]
|
||||
|
||||
|
||||
===separate===
|
||||
|
||||
Used to support [[Concurrent programming with SCOOP]].
|
||||
|
||||
|
||||
===then===
|
||||
|
||||
Used in [[ET-_Instructions#Conditional|conditional]] and [[ET-_Instructions#Multi-branch|multi-branch]] instructions to introduce a sequence of instructions to be executed in the case that a condition is met.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional syntax.]]
|
||||
|
||||
:[[Eiffel programming language syntax#Multi-branch instructions|Multi-branch syntax.]]
|
||||
|
||||
Used in a [[Conditional_expression|conditional expression]] to compute of a value in the case that a condition is met.
|
||||
|
||||
:[[Eiffel programming language syntax#Conditionals|Conditional expression syntax.]]
|
||||
|
||||
Used as part of the double reserved word <code>and then</code>, the semi-strict conjunction operator.
|
||||
|
||||
:[[Eiffel programming language syntax#Operators|Syntax.]]
|
||||
|
||||
Used after the reserved word [[#ensure|<code>ensure</code>]] as a postcondition extension, allowing the strengthening of an inherited postcondition (8.10.3).
|
||||
|
||||
:[[Eiffel programming language syntax#Assertions|Syntax.]]
|
||||
|
||||
|
||||
===True===
|
||||
|
||||
Boolean manifest constant.
|
||||
|
||||
:[[Eiffel programming language syntax#Manifest constants|Syntax.]]
|
||||
|
||||
|
||||
===TUPLE===
|
||||
|
||||
Denotes a [[ET: Other Mechanisms#Tuple types|TUPLE type]].
|
||||
|
||||
:[[Eiffel programming language syntax#Tuple types|Syntax.]]
|
||||
|
||||
|
||||
===undefine===
|
||||
|
||||
Used in an [[Eiffel programming language syntax#Inheritance parts|inheritance part]] of a [[Eiffel programming language syntax#Class declarations|class declaration]] to [[ET: Inheritance#Joining and uneffecting|uneffect]] an inherited feature.
|
||||
|
||||
:[[Eiffel programming language syntax#Undefine clauses|Syntax.]]
|
||||
|
||||
|
||||
===until===
|
||||
|
||||
Used in [[ET: Other Mechanisms#Loop|loop]] initialization.
|
||||
|
||||
:[[Eiffel programming language syntax#Loops|Syntax.]]
|
||||
|
||||
|
||||
===variant===
|
||||
|
||||
Introduces a [[ET: Instructions#Loop|loop variant]].
|
||||
|
||||
:[[Eiffel programming language syntax#Variants|Syntax.]]
|
||||
|
||||
|
||||
===Void===
|
||||
|
||||
A predefined entity name representing a [[ET: The Dynamic Structure: Execution Model#Basic operations|void (a.k.a., null) reference]].
|
||||
|
||||
|
||||
===when===
|
||||
|
||||
Used in a [[ET-_Instructions#Multi-branch|multi-branch instruction]] to introduce cases.
|
||||
|
||||
:[[Eiffel programming language syntax#Multi-branch instructions|Syntax.]]
|
||||
|
||||
|
||||
===xor===
|
||||
|
||||
The exclusive disjunction [[Eiffel programming language syntax#Operators|operator]].
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,785 @@
|
||||
[[Property:modification_date|Mon, 29 Jul 2019 16:52:51 GMT]]
|
||||
[[Property:publication_date|Mon, 29 Apr 2019 14:08:51 GMT]]
|
||||
[[Property:title|Eiffel programming language syntax]]
|
||||
[[Property:link_title|Syntax]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|4CB56AD5-1586-41F6-9E81-085F47E992DC]]
|
||||
The syntax specification shown here is a less complete and less formal version of that which is in the Eiffel ISO/ECMA standard document. The format is BNF-E. The Language Specification section of the standard document includes an overview of BNF-E.
|
||||
|
||||
There are a few parts of the syntax that are either non-production or non-representable in BNF-E. Some of these have been omitted from the following specification. These omitted parts of the syntax definition add to the precision of the specification, but knowledge of them is not always vital for developers.
|
||||
|
||||
In the BNF-E representation, generally non-terminals which are defined in the same group of productions in which they are used are not linked. However when a non-terminal is defined outside a group in which it is used, it is linked to the group in which it is defined.
|
||||
|
||||
__TOC__
|
||||
|
||||
The following section contains those non-production elements of the specification that are used later in the BNF-E specification.
|
||||
|
||||
==Eiffel non-production elements==
|
||||
|
||||
===Identifiers===
|
||||
|
||||
An '''identifier''' is a sequence of one or more alphanumeric [[#Characters|characters]] of which the first is a letter.
|
||||
|
||||
The definition is augmented by the rule that Identifiers are not valid if they are the same as one of the language's reserved words.
|
||||
|
||||
===Characters===
|
||||
|
||||
Characters are either:
|
||||
|
||||
* All 32-bit, corresponding to Unicode and to the Eiffel type CHARACTER_32.
|
||||
* All 8-bit, corresponding to 8-bit extended ASCII and to the Eiffel type CHARACTER_8
|
||||
|
||||
===Reals===
|
||||
|
||||
A real -- specimen of Real -- is made of the following elements, in the order given:
|
||||
|
||||
* An optional decimal [[#Integers|Integer]], giving the integral part.
|
||||
* A required "." (dot).
|
||||
* An optional decimal [[#Integers|Integer]], giving the fractional part.
|
||||
* An optional exponent, which is the letter ''e'' or ''E'' followed by an optional [[#Manifest constants|Sign]] and a decimal [[#Integers|Integer]].
|
||||
|
||||
No intervening character (blank or otherwise) is permitted between these elements. The integral and fractional parts may not both be absent.
|
||||
|
||||
===Strings===
|
||||
|
||||
A string -- specimen of construct String -- is a sequence of zero or more manifest characters.
|
||||
|
||||
===Simple strings===
|
||||
|
||||
A simple string -- specimen of Simple_string -- is a [[#Strings|String]] consisting of at most one line (that is to say, containing no embedded new-line manifest character), possibly containing [[#Special characters|codes for special characters]].
|
||||
|
||||
===Special characters===
|
||||
|
||||
{| border="2"
|
||||
|+ Special Characters and Their Codes
|
||||
|-
|
||||
! Character
|
||||
! Code
|
||||
! Mnemonic name
|
||||
|-
|
||||
| @ || %A || At-sign
|
||||
|-
|
||||
| BS || %B || Backspace
|
||||
|-
|
||||
| ^ || %C || Circumflex
|
||||
|-
|
||||
| $ || %D || Dollar
|
||||
|-
|
||||
| FF || %F || Form feed
|
||||
|-
|
||||
| \ || %H || Backslash
|
||||
|-
|
||||
| ~ || %L || Tilde
|
||||
|-
|
||||
| NL (LF) || %N || Newline
|
||||
|-
|
||||
| `` ` `` || %Q || Backquote
|
||||
|-
|
||||
| CR || %R || Carriage return
|
||||
|-
|
||||
| # || %S || Sharp
|
||||
|-
|
||||
| HT || %T || Horizontal tab
|
||||
|-
|
||||
| NUL || %U || Null
|
||||
|-
|
||||
| | || %V || Vertical bar
|
||||
|-
|
||||
| % || %% || Percent
|
||||
|-
|
||||
| ' || %' || Single quote
|
||||
|-
|
||||
| " || %" || Double quote
|
||||
|-
|
||||
| [ || %( || Opening bracket
|
||||
|-
|
||||
| ] || %) || Closing bracket
|
||||
|-
|
||||
| { || %< || Opening brace
|
||||
|-
|
||||
| } || %> || Closing brace
|
||||
|}
|
||||
|
||||
* `%/123/` represents the character with decimal code `123` .
|
||||
* And only for manifest character (for now)
|
||||
** `'%/0x2200/'` represents the character with hexadecimal code U+2200 = '∀' (note `'%/0x2200/' = '%/8704/'` )
|
||||
** `'%/0c21000/'` in octal
|
||||
** `'%/0b10001000000000/'` in binary
|
||||
|
||||
|
||||
===Line wrapping parts===
|
||||
|
||||
A sequence of characters consisting of the following, in order:
|
||||
* % (percent character)
|
||||
* Zero or more blanks or tabs
|
||||
* New line (Line feed)
|
||||
* Zero or more blanks or tabs
|
||||
* % (percent character)
|
||||
|
||||
Line wrapping parts are used as separators between one [[#Simple strings|Simple_string]] and the next in a [[#Manifest strings|Basic_manifest_string]] so that the string can be split across lines.
|
||||
|
||||
===New line===
|
||||
|
||||
A specimen of New_line is a New Line.
|
||||
|
||||
|
||||
==Eiffel BNF-E Syntax==
|
||||
|
||||
|
||||
===Class names ===
|
||||
Class_name ::= [[#Identfiers|Identifier]]
|
||||
|
||||
===Class declarations ===
|
||||
Class_declaration ::= <nowiki>[</nowiki>[[#Notes|Notes]]<nowiki>]</nowiki>
|
||||
[[#Class headers|Class_header]] <nowiki>[</nowiki>[[#Formal generic parameters|Formal_generics]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Obsolete marks|Obsolete]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Inheritance parts|Inheritance]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Creators parts|Creators]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Converter clauses|Converters]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Feature parts|Features]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Notes|Notes]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Assertions|Invariant]]<nowiki>]</nowiki>
|
||||
|
||||
<nowiki>[</nowiki>[[#Notes|Notes]]<nowiki>]</nowiki>
|
||||
|
||||
<code>end</code>
|
||||
|
||||
===Notes ===
|
||||
Notes ::= <code>note</code> Note_list
|
||||
|
||||
Note_list ::= {Note_entry ";" ...}*
|
||||
|
||||
Note_entry ::= Note_name Note_values
|
||||
|
||||
Note_name ::= [[#Identifiers|Identifier]] ":"
|
||||
|
||||
Note_values ::= {Note_item ","...}+
|
||||
|
||||
Note_item ::= [[#Identifiers|Identifier]] | [[#Manifest constants|Manifest_constant]]
|
||||
|
||||
===Class headers ===
|
||||
Class_header ::= <nowiki>[Header_mark]</nowiki> <code>class</code> [[#Class names|Class_name]]
|
||||
|
||||
Header_mark ::= <code>deferred</code> | <code>expanded</code> | <code>frozen</code>
|
||||
|
||||
===Obsolete marks ===
|
||||
Obsolete ::= <code>obsolete</code> Message
|
||||
|
||||
Message ::= [[#Manifest strings|Manifest_string]]
|
||||
|
||||
===Feature parts ===
|
||||
Features ::= Feature_clause+
|
||||
|
||||
Feature_clause ::= <code>feature</code> <nowiki>[</nowiki>[[#Clients|Clients]]<nowiki>]</nowiki> <nowiki>[</nowiki>[[#Feature parts|Header_comment]]<nowiki>]</nowiki> Feature_declaration_list
|
||||
|
||||
Feature_declaration_list ::= {[[#Feature declarations|Feature_declaration]] ";" ...}*
|
||||
|
||||
Header_comment ::= [[#Comments|Comment]]
|
||||
|
||||
===Feature declarations ===
|
||||
Feature_declaration ::= [[#New feature lists|New_feature_list]] Declaration_body
|
||||
|
||||
Declaration_body ::= <nowiki>[</nowiki>[[#Formal argument and entity declarations|Formal_arguments]]<nowiki>] [Query_mark] [Feature_value] </nowiki>
|
||||
|
||||
Query_mark ::= Type_mark <nowiki>[</nowiki>[[#Assigner marks|Assigner_mark]]<nowiki>]</nowiki>
|
||||
|
||||
Type_mark ::= ":" [[#Types|Type]]
|
||||
|
||||
Feature_value ::= <nowiki>[Explicit_value] </nowiki>
|
||||
<nowiki>[</nowiki>[[#Obsolete parts|Obsolete]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Feature parts|Header_comment]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Feature bodies|Attribute_or_routine]]<nowiki>]</nowiki>
|
||||
|
||||
Explicit_value ::= "=" [[#Manifest constants|Manifest_constant]]
|
||||
|
||||
|
||||
===New feature lists ===
|
||||
New_feature_list ::= {New_feature "," ...}+
|
||||
|
||||
New_feature ::= <nowiki>[</nowiki><code>frozen</code><nowiki>]</nowiki> [[#Feature names|Extended_feature_name]]
|
||||
|
||||
|
||||
===Feature bodies ===
|
||||
Attribute_or_routine ::= <nowiki>[</nowiki>[[#Assertions|Precondition]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Local variable declarations|Local_declarations]]<nowiki>]</nowiki>
|
||||
Feature_body
|
||||
<nowiki>[</nowiki>[[#Assertions|Postcondition]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Rescue clauses|Rescue]]<nowiki>]</nowiki>
|
||||
<code>end</code>
|
||||
|
||||
Feature_body ::= [[#Routine bodies|Deferred]] | [[#Routine bodies|Effective_routine]] | [[#Attribute bodies|Attribute]]
|
||||
|
||||
|
||||
===Feature names ===
|
||||
Extended_feature_name ::= Feature_name <nowiki>[Alias]</nowiki>
|
||||
|
||||
Feature_name ::= [[#Identfiers|Identifier]]
|
||||
|
||||
Alias ::= <code>alias</code> '"' Alias_name '"' <nowiki>[</nowiki><code>convert</code><nowiki>]</nowiki>
|
||||
|
||||
Alias_name ::= [[#Operators|Operator]] | Bracket
|
||||
|
||||
Bracket ::= "<nowiki>[ ]</nowiki>"
|
||||
|
||||
|
||||
===Operators ===
|
||||
Operator ::= Unary | Binary
|
||||
|
||||
Unary ::= <code>not</code> | "+" | "-" | Free_unary
|
||||
|
||||
Binary ::= <nowiki>"+" | "-" | "*" | "/" | "//" | "\\" | "^" | ".." | "<" | ">" | "<=" | ">=" |</nowiki> <code>and</code> | <code>or</code> | <code>xor</code> | <code>and</code> <code>then</code> | <code>or</code> <code>else</code> | <code>implies</code> | Free_binary
|
||||
|
||||
{{note| Free_unary and Free_binary are free operators that are distinct from (respectively) the ''standard'' unary and binary operators (one- or two-character symbols) explicitly listed in the Unary and Binary productions. See ''Definition: Free operator'' in the standard for more precision.}}
|
||||
|
||||
|
||||
===Assigner marks ===
|
||||
Assigner_mark ::= <code>assign</code> [[#Feature names|Feature_name]]
|
||||
|
||||
|
||||
===Inheritance parts ===
|
||||
Inheritance ::= Inherit_clause+
|
||||
|
||||
Inherit_clause ::= <code>inherit</code> <nowiki>[Non_conformance]</nowiki> Parent_list
|
||||
|
||||
Non_conformance ::= "{" NONE "}"
|
||||
|
||||
Parent_list ::= {Parent ";" ...}+
|
||||
|
||||
Parent ::= [[#Types|Class_type]] <nowiki>[Feature_adaptation]</nowiki>
|
||||
|
||||
Feature_adaptation ::= <nowiki>[</nowiki>[[#Undefine clauses|Undefine]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Redefinition|Redefine]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Rename clauses|Rename]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Export adaptation|New_exports]]<nowiki>]</nowiki>
|
||||
<nowiki>[</nowiki>[[#Select clauses|Select]]<nowiki>]</nowiki>
|
||||
<code>end</code>
|
||||
|
||||
|
||||
|
||||
===Rename clauses ===
|
||||
Rename ::= <code>rename</code> Rename_list
|
||||
|
||||
Rename_list ::= {Rename_pair "," ...}+
|
||||
|
||||
Rename_pair ::= [[#Feature names|Feature_name]] <code>as</code> [[#Feature names|Extended_feature_name]]
|
||||
|
||||
|
||||
===Clients ===
|
||||
Clients ::= "{" Class_list "}"
|
||||
|
||||
Class_list ::= {[[#Class names|Class_name]] "," ...}+
|
||||
|
||||
|
||||
|
||||
===Export adaptation ===
|
||||
New_exports ::= <code>export</code> New_export_list
|
||||
|
||||
New_export_list ::= {New_export_item ";" ...}+
|
||||
|
||||
New_export_item ::= [[#Clients|Clients]] <nowiki>[</nowiki>[[#Feature parts|Header_comment]]<nowiki>]</nowiki> Feature_set
|
||||
|
||||
Feature_set ::= Feature_list | <code>all</code>
|
||||
|
||||
Feature_list ::= {[[#Feature names|Feature_name]] "," ...}+
|
||||
|
||||
|
||||
|
||||
===Formal argument and entity declarations ===
|
||||
Formal_arguments ::= "(" [[#Formal argument and entity declarations|Entity_declaration_list]] ")"
|
||||
|
||||
Entity_declaration_list ::= {Entity_declaration_group ";" ...}+
|
||||
|
||||
Entity_declaration_group ::= Identifier_list [[#Feature declarations|Type_mark]]
|
||||
|
||||
Identifier_list ::= {[[#Identfiers|Identifier]] "," ...}+
|
||||
|
||||
|
||||
===Routine bodies ===
|
||||
Deferred ::= <code>deferred</code>
|
||||
|
||||
Effective_routine ::= Internal | [[#External routines|External]]
|
||||
|
||||
Internal ::= Routine_mark [[#Instructions|Compound]]
|
||||
|
||||
Routine_mark ::= <code>do</code> | Once
|
||||
|
||||
Once ::= <code>once</code> <nowiki>[</nowiki> "("Key_list ")" <nowiki>]</nowiki>
|
||||
|
||||
Key_list ::= {[[#Manifest strings|Manifest_string]] "," ...}+
|
||||
|
||||
|
||||
===Local variable declarations ===
|
||||
Local_declarations ::= <code>local</code> <nowiki>[</nowiki>[[#Formal argument and entity declarations|Entity_declaration_list]]<nowiki>]</nowiki>
|
||||
|
||||
|
||||
===Instructions ===
|
||||
Compound ::= {Instruction ";" ...}*
|
||||
|
||||
Instruction ::= [[#Creation instructions|Creation_instruction]] | [[#Feature calls|Call]] | [[#Assignments|Assignment]] | [[#Assigner calls|Assigner_call]] | [[#Conditionals|Conditional]] | [[#Multi-branch instructions|Multi_branch]]
|
||||
| [[#Loops|Loop]] | [[#Debug instructions|Debug]] | [[#Precursor|Precursor]] | [[#Check instructions|Check]] | [[#Rescue clauses|Retry]]
|
||||
|
||||
|
||||
===Assertions ===
|
||||
Precondition ::= <code>require</code> <nowiki>[</nowiki><code>else</code><nowiki>]</nowiki> Assertion
|
||||
|
||||
Postcondition ::= <code>ensure</code> <nowiki>[</nowiki><code>then</code><nowiki>]</nowiki> Assertion <nowiki>[</nowiki>[[#"Only" postcondition clauses|Only]]<nowiki>]</nowiki>
|
||||
|
||||
Invariant ::= <code>invariant</code> Assertion
|
||||
|
||||
Assertion ::= {Assertion_clause ";" ...}*
|
||||
|
||||
Assertion_clause ::= <nowiki>[</nowiki>Tag_mark<nowiki>]</nowiki> Unlabeled_assertion_clause
|
||||
|
||||
Unlabeled_assertion_clause ::= [[#Expressions|Boolean_expression]] | [[#Comments|Comment]] | `class`
|
||||
|
||||
Tag_mark ::= Tag ":"
|
||||
|
||||
Tag ::= [[#Identfiers|Identifier]]
|
||||
|
||||
{{Note|Unlabeled_assertion_clause of the form `class` can be used only in a postcondition. It marks a feature that does not depend on object state and can be called without a target object using non-object call of the form `{CLASS_NAME}.feature_name (arguments)`.}}
|
||||
|
||||
|
||||
==="Old" postcondition expressions ===
|
||||
Old ::= <code>old</code> [[#Expressions|Expression]]
|
||||
|
||||
|
||||
==="Only" postcondition clauses ===
|
||||
Only ::= <code>only</code> <nowiki>[</nowiki>[[#Export adaptation|Feature_list]]<nowiki>]</nowiki>
|
||||
|
||||
|
||||
===Check instructions ===
|
||||
Check ::= <code>check</code> [[#Assertions|Assertion]] <nowiki>[</nowiki>[[#Notes|Notes]]<nowiki>]</nowiki> <code>end</code>
|
||||
|
||||
|
||||
===Variants ===
|
||||
Variant ::= <code>variant</code> <nowiki>[</nowiki>[[#Assertions|Tag_mark]]<nowiki>]</nowiki> [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Precursor ===
|
||||
Precursor ::= <code>Precursor</code> [Parent_qualification] <nowiki>[</nowiki>[[#Actual arguments|Actuals]]<nowiki>]</nowiki>
|
||||
|
||||
Parent_qualification ::= "{" [[#Class names|Class_name]] "}"
|
||||
|
||||
|
||||
===Redefinition ===
|
||||
Redefine ::= <code>redefine</code> [[#Export adaptation|Feature_list]]
|
||||
|
||||
|
||||
===Undefine clauses ===
|
||||
Undefine ::= <code>undefine</code> [[#Export adaptation|Feature_list]]
|
||||
|
||||
|
||||
===Types ===
|
||||
Type ::= Class_or_tuple_type | [[#Formal generic parameters|Formal_generic_name]] | Anchored
|
||||
|
||||
Class_or_tuple_type ::= Class_type | [[#Tuple types|Tuple_type]]
|
||||
|
||||
Class_type ::= [Attachment_mark] [[#Class names|Class_name]] <nowiki>[</nowiki>[[#Actual generic parameters|Actual_generics]]<nowiki>]</nowiki>
|
||||
|
||||
Attachment_mark ::= "?" | "!"
|
||||
|
||||
Anchored ::= [Attachment_mark] <code>like</code> Anchor
|
||||
|
||||
Anchor ::= [[#Feature names|Feature_name]] | <code>Current</code>
|
||||
|
||||
|
||||
===Actual generic parameters ===
|
||||
Actual_generics ::= <nowiki>"[" Type_list "]"</nowiki>
|
||||
|
||||
Type_list ::= {[[#Types|Type]] "," ...}+
|
||||
|
||||
|
||||
===Formal generic parameters ===
|
||||
Formal_generics ::= <nowiki>"[" Formal_generic_list "]"</nowiki>
|
||||
|
||||
Formal_generic_list ::= {Formal_generic ","...}+
|
||||
|
||||
Formal_generic ::= <nowiki>[</nowiki><code>frozen</code><nowiki>]</nowiki> Formal_generic_name <nowiki>[</nowiki>[[#Generic constraints|Constraint]]<nowiki>]</nowiki>
|
||||
|
||||
Formal_generic_name ::= <nowiki>[?]</nowiki> [[#Identfiers|Identifier]]
|
||||
|
||||
|
||||
===Generic constraints ===
|
||||
Constraint ::= "->" Constraining_types <nowiki>[Constraint_creators]</nowiki>
|
||||
|
||||
Constraining_types ::= Single_constraint | Multiple_constraint
|
||||
|
||||
Single_constraint ::= [[#Types|Type]] [Renaming]
|
||||
|
||||
Renaming ::= [[#Rename clauses|Rename]] <code>end</code>
|
||||
|
||||
Multiple_constraint ::= "{" Constraint_list "}"
|
||||
|
||||
Constraint_list ::= {Single_constraint "," ...}+
|
||||
|
||||
Constraint_creators ::= <code>create</code> [[#Export adaptation|Feature_list]] <code>end</code>
|
||||
|
||||
|
||||
===Manifest arrays ===
|
||||
Manifest_array ::= <nowiki>[</nowiki>Manifest_array_type<nowiki>]</nowiki> <code><<</code> Expression_list <code>>></code>
|
||||
|
||||
Manifest_array_type ::= <code>{</code> [[#Types|Type]] <code>}</code>
|
||||
|
||||
Expression_list ::= {[[#Expressions|Expression]] <code>,</code> ...}*
|
||||
|
||||
|
||||
===Tuple types ===
|
||||
Tuple_type ::= <code>TUPLE</code> <nowiki>[Tuple_parameter_list]</nowiki>
|
||||
|
||||
Tuple_parameter_list ::= <nowiki>"[" Tuple_parameters "]"</nowiki>
|
||||
|
||||
Tuple_parameters ::= [[#Actual generic parameters|Type_list]] | [[#Formal argument and entity declarations|Entity_declaration_list]]
|
||||
|
||||
|
||||
===Manifest tuples ===
|
||||
Manifest_tuple ::= <nowiki>"["</nowiki> [[#Manifest arrays|Expression_list]] <nowiki>"]"</nowiki>
|
||||
|
||||
|
||||
===Converter clauses ===
|
||||
Converters ::= <code>convert</code> Converter_list
|
||||
|
||||
Converter_list ::= {Converter ","...}+
|
||||
|
||||
Converter ::= Conversion_procedure | Conversion_query
|
||||
|
||||
Conversion_procedure ::= [[#Feature names|Feature_name]] "(" "{" [[#Actual generic parameters|Type_list]] "}" ")"
|
||||
|
||||
Conversion_query ::= [[#Feature names|Feature_name]] ":" "{" [[#Actual generic parameters|Type_list]] "}"
|
||||
|
||||
|
||||
===Select clauses ===
|
||||
Select ::= <code>select</code> [[#Export adaptation|Feature_list]]
|
||||
|
||||
|
||||
===Conditionals ===
|
||||
Conditional ::= <code>if</code> Then_part_list <nowiki>[Else_part]</nowiki> <code>end</code>
|
||||
|
||||
Then_part_list ::= {Then_part <code>elseif</code> ...}+
|
||||
|
||||
Then_part ::= [[#Expressions|Boolean_expression]] <code>then</code> [[#Instructions|Compound]]
|
||||
|
||||
Else_part ::= <code>else</code> [[#Instructions|Compound]]
|
||||
|
||||
|
||||
Conditional_expression ::= <code>if</code> Then_part_expression_list <code>else</code> [[#Expressions|Expression]] <code>end</code>
|
||||
|
||||
Then_part_expression_list ::= {Then_part_expression <code>elseif</code> ...}+
|
||||
|
||||
Then_part_expression ::= [[#Expressions|Boolean_expression]] <code>then</code> [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Multi-branch instructions ===
|
||||
Multi_branch ::= <code>inspect</code> [[#Expressions|Expression]] <nowiki>[When_part_list] [Else_part]</nowiki> <code>end</code>
|
||||
|
||||
When_part_list ::= When_part+
|
||||
|
||||
When_part ::= <code>when</code> Choices <code>then</code> [[#Instructions|Compound]]
|
||||
|
||||
Choices ::= {Choice "," ...}+
|
||||
|
||||
Choice ::= [[#Constants|Constant]] | [[#Manifest constants|Manifest_type]] | Constant_interval | Type_interval
|
||||
|
||||
Constant_interval ::= [[#Constants|Constant]] ".." [[#Constants|Constant]]
|
||||
|
||||
Type_interval ::= [[#Manifest constants|Manifest_type]] ".." [[#Manifest constants|Manifest_type]]
|
||||
|
||||
|
||||
===Loops ===
|
||||
Loop ::=<br/>
|
||||
<nowiki>[</nowiki>Iteration<nowiki>]</nowiki><br/>
|
||||
<nowiki>[</nowiki>Initialization<nowiki>]</nowiki><br/>
|
||||
<nowiki>[</nowiki>[[#Assertions|Invariant]]<nowiki>]</nowiki><br/>
|
||||
<nowiki>[</nowiki>Exit_condition<nowiki>]</nowiki><br/>
|
||||
Loop_body<br/>
|
||||
<nowiki>[</nowiki>[[#Variants|Variant]]<nowiki>]</nowiki><br/>
|
||||
<code>end</code>
|
||||
|
||||
Iteration ::= <code>across</code> [[#Expressions|Expression]] <code>as</code> [[#Identfiers|Identifier]]
|
||||
|
||||
Initialization ::= <code>from</code> [[#Instructions|Compound]]
|
||||
|
||||
Exit_condition ::= <code>until</code> [[#Expressions|Boolean_expression]]
|
||||
|
||||
Loop_body ::=<br/>
|
||||
<code>loop</code> [[#Instructions|Compound]] |<br/>
|
||||
<code>all</code> [[#Expressions|Boolean_expression]] |<br/>
|
||||
<code>some</code> [[#Expressions|Boolean_expression]]
|
||||
|
||||
|
||||
===Debug instructions ===
|
||||
Debug ::= <code>debug</code> <nowiki>[</nowiki> "("[[#Routine_bodies|Key_list]] ")" ] [[#Instructions|Compound]] <code>end</code>
|
||||
|
||||
|
||||
===Attribute bodies ===
|
||||
Attribute ::= <code>attribute</code> [[#Instructions|Compound]]
|
||||
|
||||
|
||||
===Entities and variables ===
|
||||
Entity ::= Variable | Read_only
|
||||
|
||||
Variable ::= Variable_attribute | Local
|
||||
|
||||
Variable_attribute ::= [[#Feature names|Feature_name]]
|
||||
|
||||
Local ::= [[#Identfiers|Identifier]] | <code>Result</code>
|
||||
|
||||
Read_only ::= Formal | Constant_attribute | <code>Current</code>
|
||||
|
||||
Formal ::= [[#Identfiers|Identifier]]
|
||||
|
||||
Constant_attribute ::= [[#Feature names|Feature_name]]
|
||||
|
||||
|
||||
===Creators parts ===
|
||||
Creators ::= Creation_clause+
|
||||
|
||||
Creation_clause ::= <code>create</code> <nowiki>[</nowiki>[[#Clients|Clients]]<nowiki>]</nowiki> <nowiki>[</nowiki>[[#Feature parts|Header_comment]]<nowiki>]</nowiki> Creation_procedure_list
|
||||
|
||||
Creation_procedure_list ::= {Creation_procedure ","...}+
|
||||
|
||||
Creation_procedure ::= [[#Feature names|Feature_name]]
|
||||
|
||||
|
||||
===Creation instructions ===
|
||||
Creation_instruction ::= <code>create</code> <nowiki>[Explicit_creation_type]</nowiki> Creation_call
|
||||
|
||||
Explicit_creation_type ::= "{" [[#Types|Type]] "}"
|
||||
|
||||
Creation_call ::= [[#Entities and variables|Variable]] [Explicit_creation_call]
|
||||
|
||||
Explicit_creation_call ::= "." [[#Feature calls|Unqualified_call]]
|
||||
|
||||
|
||||
===Creation expressions ===
|
||||
Creation_expression ::= <code>create</code> [[#Creation instructions|Explicit_creation_type]] <nowiki>[</nowiki>[[#Creation instructions|Explicit_creation_call]]<nowiki>]</nowiki>
|
||||
|
||||
|
||||
===Equality expressions ===
|
||||
Equality ::= [[#Expressions|Expression]] Comparison [[#Expressions|Expression]]
|
||||
|
||||
Comparison ::= "=" | "/=" | "~" | "/~"
|
||||
|
||||
|
||||
===Assignments ===
|
||||
Assignment ::= [[#Entities and variables|Variable]] ":=" [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Assigner calls ===
|
||||
Assigner_call ::= [[#Expressions|Expression]] ":=" [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Feature calls ===
|
||||
Call ::= Object_call | Non_object_call
|
||||
|
||||
Object_call ::= <nowiki>[Target "."] Unqualified_call </nowiki>
|
||||
|
||||
Unqualified_call ::= [[#Feature names|Feature_name]] <nowiki>[</nowiki>[[#Actual arguments|Actuals]]<nowiki>]</nowiki>
|
||||
|
||||
Target ::= [[#Entities and variables|Local]] | [[#Entities and variables|Read_only]] | Call | Parenthesized_target
|
||||
|
||||
Parenthesized_target ::= <code>(</code> [[#Expressions|Expression]] <code>)</code>
|
||||
|
||||
Non_object_call ::= "{" [[#Types|Type]] "}" "." Unqualified_call
|
||||
|
||||
|
||||
===Actual arguments ===
|
||||
Actuals ::= "(" Actual_list ")"
|
||||
|
||||
Actual_list ::= {[[#Expressions|Expression]] "," ...}+
|
||||
|
||||
|
||||
===Object test ===
|
||||
Object_test ::= "{" [[#Identfiers|Identifier]] ":" [[#Types|Type]] "}" [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Rescue clauses ===
|
||||
Rescue ::= <code>rescue</code> [[#Instructions|Compound]]
|
||||
|
||||
Retry ::= <code>retry</code>
|
||||
|
||||
|
||||
===Agents ===
|
||||
Agent ::= Call_agent | Inline_agent
|
||||
|
||||
Call_agent ::= <code>agent</code> [[#Call agent bodies|Call_agent_body]]
|
||||
|
||||
Inline_agent ::= <code>agent</code> <nowiki>[</nowiki>[[#Formal argument and entity declarations|Formal_arguments]]<nowiki>]</nowiki> <nowiki>[</nowiki>[[#Feature declarations|Type_mark]]<nowiki>]</nowiki> <nowiki>[</nowiki>[[#Feature bodies|Attribute_or_routine]]<nowiki>]</nowiki> <nowiki>[</nowiki>[[#Call agent bodies|Agent_actuals]]<nowiki>]</nowiki>
|
||||
|
||||
|
||||
===Call agent bodies ===
|
||||
Call_agent_body ::= Agent_qualified | Agent_unqualified
|
||||
|
||||
Agent_qualified ::= Agent_target ". " Agent_unqualified
|
||||
|
||||
Agent_unqualified ::= [[#Feature names|Feature_name]] [Agent_actuals]
|
||||
|
||||
Agent_target ::= Entity | Parenthesized | [[#Manifest constants|Manifest_type]]
|
||||
|
||||
Agent_actuals ::= "(" Agent_actual_list ")"
|
||||
|
||||
Agent_actual_list ::= {Agent_actual "," ...}+
|
||||
|
||||
Agent_actual ::= [[#Expressions|Expression]] | Placeholder
|
||||
|
||||
Placeholder ::= <nowiki>[</nowiki>[[#Manifest constants|Manifest_type]]<nowiki>]</nowiki> "?"
|
||||
|
||||
|
||||
===Expressions ===
|
||||
Expression ::= Basic_expression | Special_expression
|
||||
|
||||
Basic_expression ::= [[#Entities and variables|Read_only]] | [[#Entities and variables|Local]] | [[#Feature calls|Call]] | [[#Precursor|Precursor]] | [[#Equality expressions|Equality]] | Parenthesized | [[#"Old" postcondition expressions|Old]] |
|
||||
[[#Operator expressions|Operator_expression]] | [[#Bracket expressions|Bracket_expression]] | [[#Creation expression|Creation_expression]] | [[#Conditionals|Conditional_expression]]
|
||||
|
||||
Special_expression ::= [[#Manifest constants|Manifest_constant]] | [[#Manifest arrays|Manifest_array]] | [[#Manifest tuples|Manifest_tuple]] | [[#Agents|Agent]] | [[#Object test|Object_test]] | Once_string |
|
||||
Address
|
||||
|
||||
Parenthesized ::= "(" Expression ")"
|
||||
|
||||
Address ::= "$" [[#Entities and variables|Variable]]
|
||||
|
||||
Once_string ::= <code>once</code> [[#Manifest strings|Manifest_string]]
|
||||
|
||||
Boolean_expression ::= Basic_expression | [[#Manifest constants|Boolean_constant]] | [[#Object test|Object_test]]
|
||||
|
||||
|
||||
===Operator expressions ===
|
||||
Operator_expression ::= Unary_expression | Binary_expression
|
||||
|
||||
Unary_expression ::= Unary Expression
|
||||
|
||||
Binary_expression ::= [[#Expressions|Expression]] [[#Operators|Binary]] [[#Expressions|Expression]]
|
||||
|
||||
|
||||
===Bracket expressions ===
|
||||
Bracket_expression ::= Bracket_target "[" [[#Actual arguments|Actuals]] "]"
|
||||
|
||||
Bracket_target ::= [[#Feature calls|Target]] | [[#Expressions|Once_string]] | [[#Manifest constants|Manifest_constant]] | [[#Manifest tuples|Manifest_tuple]]
|
||||
|
||||
|
||||
===Constants ===
|
||||
Constant ::= [[#Manifest constants|Manifest_constant]] | Constant_attribute
|
||||
|
||||
Constant_attribute ::= [[#Feature names|Feature_name]]
|
||||
|
||||
|
||||
===Manifest constants ===
|
||||
Manifest_constant ::= [Manifest_type] Manifest_value
|
||||
|
||||
Manifest_type ::= "{" [[#Types|Type]] "}"
|
||||
|
||||
Manifest_value ::= Boolean_constant |
|
||||
Character_constant |
|
||||
Integer_constant |
|
||||
Real_constant |
|
||||
[[#Manifest strings|Manifest_string]] |
|
||||
Manifest_type
|
||||
|
||||
Sign ::= "+" | "-"
|
||||
|
||||
Integer_constant ::= <nowiki>[Sign]</nowiki> [[#Integers|Integer]]
|
||||
|
||||
Character_constant ::= " ' " [[#Characters|Character]] " ' "
|
||||
|
||||
Boolean_constant ::= <code>True</code> | <code>False</code>
|
||||
|
||||
Real_constant ::= <nowiki>[Sign]</nowiki> [[#Reals|Real]]
|
||||
|
||||
|
||||
===Manifest strings ===
|
||||
Manifest_string ::= Basic_manifest_string | Verbatim_string
|
||||
|
||||
Basic_manifest_string ::= ' " ' String_content ' " '
|
||||
|
||||
String_content ::= {[[#Simple strings|Simple_string]] [[#Line wrapping parts|Line_wrapping_part]] ...}+
|
||||
|
||||
Verbatim_string ::= Verbatim_string_opener Line_sequence Verbatim_string_closer
|
||||
|
||||
Verbatim_string_opener ::= ' " ' <nowiki>[</nowiki>[[#Simple strings|Simple_string]]<nowiki>]</nowiki> Open_bracket
|
||||
|
||||
Verbatim_string_closer ::= Close_bracket <nowiki>[</nowiki>[[#Simple strings|Simple_string]]<nowiki>]</nowiki> ' " '
|
||||
|
||||
Open_bracket ::= <nowiki>"[" | "{"</nowiki>
|
||||
|
||||
Close_bracket ::= "]" | "}"
|
||||
|
||||
Line_sequence ::= {[[#Simple strings|Simple_string]] [[#New line|New_line]] ...}+
|
||||
|
||||
{{Note|Exactly the same [[#Simple strings|Simple_string]] (including embedded white space, if any) should be used in ''Verbatim_string_opener'' and ''Verbatim_string_closer'' of the same verbatim string.}}
|
||||
|
||||
===External routines ===
|
||||
External ::= <code>external</code> External_language <nowiki>[External_name]</nowiki>
|
||||
|
||||
External_language ::= Unregistered_language | [[#Registered languages|Registered_language]]
|
||||
|
||||
Unregistered_language ::= [[#Manifest strings|Manifest_string]]
|
||||
|
||||
External_name ::= <code>alias</code> [[#Manifest strings|Manifest_string]]
|
||||
{{note|If the `inline` keyword is used in the Registered_language part, then External_name part is the inline code on the specified language.}}
|
||||
|
||||
|
||||
===Registered languages ===
|
||||
Registered_language ::= [[#C externals|C_external]] | [[#C++ externals|C++_external]] | [[#DLL externals|DLL_external]]
|
||||
|
||||
|
||||
===External signatures ===
|
||||
External_signature ::= <code>signature</code> <nowiki>[External_argument_types] [: External_type]</nowiki>
|
||||
|
||||
External_argument_types ::= "(" External_type_list ")"
|
||||
|
||||
External_type_list ::= {External_type "," ...}*
|
||||
|
||||
External_type ::= [[#Simple strings|Simple_string]]
|
||||
|
||||
|
||||
===External file use ===
|
||||
External_file_use ::= <code>use</code> External_file_list
|
||||
|
||||
External_file_list ::= {External_file "," <nowiki>... }+ </nowiki>
|
||||
|
||||
External_file ::= External_user_file | External_system_file
|
||||
|
||||
External_user_file ::= ' " ' [[#Simple strings|Simple_string]] ' " '
|
||||
|
||||
External_system_file ::= <nowiki>"<"</nowiki> [[#Simple strings|Simple_string]] <nowiki>">"</nowiki>
|
||||
|
||||
===C externals ===
|
||||
C_external ::= ' " ' <code>C</code> <nowiki>[</nowiki><code>inline</code>] <nowiki>[</nowiki> [[#External signatures |External_signature]] <nowiki>] [</nowiki> [[#External file use |External_file_use]] <nowiki>] ' " '</nowiki>
|
||||
|
||||
|
||||
===C++ externals ===
|
||||
C++_external ::= ' " ' <code>C++</code> <code>inline</code> <nowiki>[</nowiki> [[#External signatures |External_signature]] <nowiki>] [</nowiki> [[#External file use |External_file_use]] <nowiki>] ' " '</nowiki>
|
||||
|
||||
|
||||
===DLL externals ===
|
||||
DLL_external ::= ' " ' <code>dll</code> <nowiki>[</nowiki><code>windows</code><nowiki>] DLL_identifier [DLL_index] [[</nowiki> [[#External signatures |External_signature]] <nowiki>] [</nowiki> [[#External file use |External_file_use]] <nowiki>] ' " ' </nowiki>
|
||||
|
||||
DLL_identifier ::= [[#Simple strings|Simple_string]]
|
||||
|
||||
DLL_index ::= [[#Integers|Integer]]
|
||||
|
||||
|
||||
===Comments ===
|
||||
Comment ::= "- -" <nowiki>{</nowiki>[[#Simple strings|Simple_string]] Comment_break ...}*
|
||||
|
||||
Comment_break ::= New_line <nowiki>[Blanks_or_tabs] "- -"</nowiki>
|
||||
|
||||
===Integers ===
|
||||
Integer ::= <nowiki>[Integer_base]</nowiki> Digit_sequence
|
||||
|
||||
Integer_base ::= "0" Integer_base_letter
|
||||
|
||||
Integer_base_letter ::= "b" | "c" | "x" | "B" | "C" | "X"
|
||||
|
||||
Digit_sequence ::= Digit+
|
||||
|
||||
Digit ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" |
|
||||
"a" | "b" | "c" | "d" | "e" | "f" |
|
||||
"A" | "B" | "C" | "D" | "E" | "F" | "_"
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
[[Property:title|Quick reference to the Eiffel programming language]]
|
||||
[[Property:link_title|Quick Reference]]
|
||||
[[Property:weight|4]]
|
||||
[[Property:uuid|4f61365d-59f6-a394-678b-144bad8ec12f]]
|
||||
The Quick Reference to the Eiffel programming language provides an informal guide to the syntax and reserved words of the language. The Eiffel programming language is described in detail in the '''ISO/ECMA''' standard document, available [http://www.ecma-international.org/publications/standards/Ecma-367.htm online].
|
||||
|
||||
Sometimes there are differences between the language as defined by the standard and that which is implemented by Eiffel Software. These differences are documented in the online documentation.
|
||||
|
||||
So, the final authority on Eiffel as implemented by Eiffel Software is the content of the standard document, amended by those variances cited in the [[Differences between standard ECMA-367 and Eiffel Software implementation|"differences" chapter of the online documentation]].
|
||||
|
||||
This reference is based on the June 2006 ISO/ECMA standard document.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
[[Property:title|Void-safe changes to Eiffel libraries]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|dc993c0e-fbec-dc5a-82c8-fbfd9fa9bc3a]]
|
||||
==Overview==
|
||||
|
||||
During the adoption of void-safety, the software libraries provided by Eiffel Software have been converted to be void-safe. The bulk of the changes made to these libraries will have little or no adverse effect on your existing software as you go through the process of void-safe conversion. However, there are a few changes to the library that we consider "breaking" changes, that is, important changes that might cause problems in existing systems that use certain library classes.
|
||||
|
||||
|
||||
{{note|Many of these changes were in effect in the ''experimental'' mode of versions 6.4 and 6.5. With the release of version 6.6, the ''experimental'' mode of previous versions became the ''default'' mode and, consequently may have caused these changes to become more apparent to some users. A ''compatibility'' mode is available to ease transition. The ''compatibility'' mode is accessible using the <code>-compat</code> command line option or through the EiffelStudio choices provided through the Microsoft Windows ''Start'' button. }}
|
||||
|
||||
|
||||
==Important changes to library classes==
|
||||
|
||||
|
||||
===Class ARRAY===
|
||||
|
||||
====New preconditions====
|
||||
|
||||
Some additional preconditions are in force in <code>ARRAY</code> in void-safe mode.
|
||||
|
||||
In void-unsafe mode, the behavior is equivalent to that of previous versions.
|
||||
|
||||
====Feature make_from_special====
|
||||
|
||||
The signature of this routine has changed.
|
||||
|
||||
Current signature: <code>make_from_special (a: SPECIAL [G])</code>
|
||||
|
||||
Previous signature: <code>make_from_special (a: SPECIAL [G]; min_index, max_index: INTEGER)</code>
|
||||
|
||||
Using the current version will create an array with a range from 1 to the number of elements in the argument `a`.
|
||||
|
||||
====Feature auto_resize====
|
||||
|
||||
This implementation (private) feature has been removed.
|
||||
|
||||
|
||||
===Class ARRAYED_LIST===
|
||||
|
||||
====Relationship to ARRAY====
|
||||
|
||||
Previously <code>ARRAYED_LIST</code> conformed to <code>ARRAY</code>. This is no longer the case. The feature <code>{ARRAYED_LIST}.to_array</code> can be used to produce an instance of <code>ARRAY</code> from an instance of <code>ARRAYED_LIST</code>.
|
||||
|
||||
====Features count and area====
|
||||
|
||||
Previously these two queries, <code>count</code> and <code>area</code>, were attributes. They are now functions.
|
||||
|
||||
|
||||
===Class HASH_TABLE===
|
||||
|
||||
The internal implementation has changed in ways that cause the order of traversal to differ from previous versions.
|
||||
|
||||
|
||||
===Classes SPECIAL and TO_SPECIAL===
|
||||
|
||||
====Feature {SPECIAL}.make====
|
||||
|
||||
This void-unsafe feature has been removed.
|
||||
|
||||
In its place, the creation procedures <code>{SPECIAL}.make_filled</code> and <code>{SPECIAL}.make_empty</code> can be used.
|
||||
|
||||
<code>{SPECIAL}.make_filled</code> is available in both ''default'' and ''compatible'' modes. Use this creation procedure if you want code that is compatible with both modes.
|
||||
|
||||
<code>{SPECIAL}.make_empty</code> is available in ''default'' mode only.
|
||||
|
||||
====Feature {TO_SPECIAL}.make_area====
|
||||
|
||||
In order to reflect the above change to class <code>SPECIAL</code>, the <code>make_area</code> feature of <code>TO_SPECIAL</code> has been removed in favor of <code>{TO_SPECIAL}.make_filled_area</code> and <code>{TO_SPECIAL}.make_empty_area</code>.
|
||||
|
||||
The availability of <code>{TO_SPECIAL}.make_filled_area</code> and <code>{TO_SPECIAL}.make_empty_area</code> corresponds to that noted above for the creation features of <code>SPECIAL</code>:
|
||||
|
||||
<code>{TO_SPECIAL}.make_filled_area</code> is available in both ''default'' and ''compatible'' modes. Use <code>make_filled_area</code> for code that needs to compile in both modes.
|
||||
|
||||
<code>{TO_SPECIAL}.make_empty_area</code> is available only in ''default'' mode.
|
||||
|
||||
====Relationship of feature {SPECIAL}.count to {SPECIAL}.capacity====
|
||||
|
||||
In previous versions, for a particular instance of <code>SPECIAL</code> the queries <code>count</code> and <code>capacity</code> yielded the same value.
|
||||
|
||||
This is no longer always true. If an instance of <code>SPECIAL</code> is created with, for example, <code>make_empty (10)</code>, although the <code>capacity</code> will be 10, the <code>count</code> will be zero.
|
||||
|
||||
However creating a <code>SPECIAL</code> using <code>make_filled</code> will produce an instance in which <code>count</code> and <code>capacity</code> are equal upon creation. So the behavior is similar to that of previous versions. Also, <code>make_filled</code> is available in both ''default'' and ''compatible'' modes.
|
||||
|
||||
If your code depends upon <code>count</code> and <code>capacity</code> having the same value, then you can use <code>make_filled</code> for creation. And then if you need resizing, use the "_with_default" versions of the "resized" features, specifically <code>resized_area_with_default</code> and <code>aliased_resized_area_with_default</code>.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
[[Property:title|Converting existing software to void-safety]]
|
||||
[[Property:weight|6]]
|
||||
[[Property:uuid|eb901272-d405-2277-005d-e37275b9baa4]]
|
||||
If you have been using Eiffel for a while, you may be maintaining systems which were developed before Eiffel became void-safe. If that's the case, then you will probably want to make those systems void-safe.
|
||||
|
||||
In this section we will use the experience of converting a set of simple (but not too simple) legacy Eiffel classes to show the types of issues that you may encounter, and how to deal with them.
|
||||
|
||||
So in the discussion below, you will see references to these classes:
|
||||
|
||||
|
||||
{| border="1"
|
||||
|-
|
||||
! Class name
|
||||
! Description
|
||||
|-
|
||||
| APPLICATION
|
||||
| Simple root class containing declarations of types NVP and NVP_LIST
|
||||
|-
|
||||
| NVP
|
||||
| Class modeling name/value pairs of type STRING
|
||||
|-
|
||||
| NVP_LIST
|
||||
| Class modeling a list of NVP's with specialized behavior; heir of TWO_WAY_LIST [NVP]
|
||||
|}
|
||||
|
||||
|
||||
It's not important that you know much about the details of these classes. We will, however, look at certain parts of the classes in enough detail to resolve the conversion issues.
|
||||
|
||||
|
||||
=Conversion considerations=
|
||||
|
||||
==To redesign or not to redesign==
|
||||
|
||||
During the process of conversion of classes to void-safety, the compiler will point out problems which you will have to fix. Some of these will be straightforward, while others may be tricky. It is natural, or sometimes mandatory, at times to consider changing elements of the design of your software.
|
||||
|
||||
Also, as you sift through your existing software during the void-safe conversion, you may not get very far before you see things that you wish had been done differently. This occurs often during reviews of existing systems, not just because of the introduction of void-safety.
|
||||
|
||||
In the discussions that follow you will see these redesign opportunities arise, and the decisions that were made for these cases.
|
||||
|
||||
==Be aware of changes to Eiffel libraries==
|
||||
|
||||
The libraries distributed with EiffelStudio have been converted to support void-safety. Mostly the changes made will cause no problems for existing software. However a few changes have been identified as "breaking" changes. You may or may not encounter the effects of these changes, but you should be aware of how they could effect your software and what options you have for adapting to them. Breaking changes are described in the [[EiffelStudio release notes]] and in the page dedicated to [[Void-safe changes to Eiffel libraries]].
|
||||
|
||||
=Conversion process=
|
||||
|
||||
==Enable full class checking==
|
||||
|
||||
First make sure your project will compile correctly under the configuration of EiffelStudio that you intend to use to convert to void-safe.
|
||||
|
||||
Then set the project setting '''Full Class Checking''' to '''True'''. Do a ''[[Clean compile|clean compile]]'' of your system.
|
||||
|
||||
Full class checking will analyze your classes to make sure that in cases of inheritance, features of the parent classes are rechecked for validity in the heirs.
|
||||
|
||||
Here's an example of the kind of error you might expect when compiling with full class checking:
|
||||
|
||||
|
||||
[[Image:VGCC error]]
|
||||
|
||||
|
||||
The situation here is that the feature <code>split</code> has been inherited (from class <code>TWO_WAY_LIST [G]</code>) by our class <code>NVP_LIST</code>. Feature <code>split</code> includes code to create and attach feature <code>sublist</code> which is typed <code>attached like Current</code> which in this case means <code>attached NVP_LIST</code>. To do this creation, <code>split</code> uses a creation procedure <code>make_sublist</code>.
|
||||
|
||||
Now here's the rub: <code>NVP_LIST</code> has not named <code>make_sublist</code> as a creation procedure:
|
||||
<code>
|
||||
create
|
||||
make, make_from_string, make_from_file_named
|
||||
</code>
|
||||
If we go to the <code>create</code> part of <code>NVP_LIST</code> and add <code>make_sublist</code> to its list of creation procedures, this will fix the problem:
|
||||
<code>
|
||||
create
|
||||
make, make_from_string, make_from_file_named, make_sublist
|
||||
</code>
|
||||
|
||||
So, fix any problems that arise out of turning on full class checking.
|
||||
|
||||
==Enable other project settings==
|
||||
|
||||
The second step in conversion of existing software is to change the values of the other void-safe related project settings and use the void-safe configurations for any delivered libraries and precompilations.
|
||||
|
||||
In the project settings for the target in which you are working, set '''Void safety''' to '''Complete''', '''Transitional''' , '''Initialization''' or '''Conformance'''.
|
||||
|
||||
{{note|Remember that during a transitional period starting with v6.4, there will be multiple versions of the configuration files for Eiffel libraries and precompiles. For example, base.ecf (void-unsafe) and base-safe.ecf (void-safe). Starting with v16.11 there is only one configuration file for libraries (e.g., base.ecf) that works with both void-safe and void-unsafe client software, but if you are using a precompile, there could be different versions for void-safe and void-unsafe precompiles.}}
|
||||
|
||||
If necessary, remove Eiffel libraries and any precompiled library that your project uses and re-add them with their void-safe configuration files. Because you've set your target to void-safety, when you click '''Add Library''', you should see only void-safe configurations by default.
|
||||
You will see a check box on the dialog that you can uncheck if you want to see all available library configurations:
|
||||
|
||||
|
||||
[[Image:VoidSafeAddLibraryDialog]]
|
||||
|
||||
|
||||
Now do a [[Clean compile|clean compile]].
|
||||
|
||||
If you've replaced a precompiled library that you have not already built, EiffelStudio will offer to build it for you on the fly:
|
||||
|
||||
|
||||
[[Image:VoidSafePrecompileOffer]]
|
||||
|
||||
|
||||
Now you should see error messages representing any situation in your project in which the compiler determines that it cannot guarantee void-safety.
|
||||
|
||||
This is what our legacy system produced:
|
||||
|
||||
|
||||
[[Image:VoidSafeErrorList]]
|
||||
|
||||
|
||||
==Fix the issues==
|
||||
|
||||
Next you fix the problems that the compiler discovered. The compiler errors concerning void-safety typically will be of three varieties.
|
||||
|
||||
# VEVI: violations of the '''Variable initialization rule'''. An attached variable is not '''properly set'''.
|
||||
# VUTA: violations of the '''Target rule'''. The target of a feature call is not attached.
|
||||
# VJAR (and other related codes): violations of attached status considered in conformance. The attachment status of the source of an assignment (or an argument to a feature call) is not compatible with that of the target of the assignment (or the formal argument).
|
||||
|
||||
Let's look at some specific cases and how fixing them unfolds.
|
||||
|
||||
===Variables not properly set===
|
||||
|
||||
[[Image:VoidSafeVEVI1]]
|
||||
|
||||
|
||||
There are two VEVI errors like this in class <code>APPLICATION</code> of our legacy system. They are probably the most obvious and easiest cases to handle.
|
||||
|
||||
<code>
|
||||
feature {NONE} -- Initialization
|
||||
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
...
|
||||
end
|
||||
|
||||
feature -- Access
|
||||
|
||||
my_nvp: NVP
|
||||
-- NVP for testing
|
||||
|
||||
my_nvp_list: NVP_LIST
|
||||
-- NVP_LIST for testing
|
||||
</code>
|
||||
|
||||
Here attribute declarations for <code>my_nvp</code> and <code>my_nvp_list</code> are made. These are assumed to be attached because of the project setting. But the create routine <code>make</code> fails to create objects and attach them. So by adding those creations, as shown below, the compiler is satisfied.
|
||||
|
||||
<code>
|
||||
make
|
||||
-- Run application.
|
||||
do
|
||||
create my_nvp.make ("SomeName", "SomeValue")
|
||||
create my_nvp_list.make
|
||||
...
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
In a second case, there is also an Initialization rule violation (VEVI), this time on <code>Result</code>, in this routine:
|
||||
|
||||
<code>
|
||||
at_first (nm: STRING): NVP
|
||||
-- The first found NVP with name matching nm.
|
||||
-- Or Void if not found
|
||||
require
|
||||
nm_valid: nm /= Void and then not nm.is_empty
|
||||
local
|
||||
tc: CURSOR
|
||||
do
|
||||
tc := cursor
|
||||
start
|
||||
name_search (nm)
|
||||
if not exhausted then
|
||||
Result := item
|
||||
end
|
||||
go_to (tc)
|
||||
ensure
|
||||
index_unchanged: index = old index
|
||||
end
|
||||
</code>
|
||||
|
||||
Here we cannot just ensure that <code>Result</code> is always attached, because, as indicated by the header comment, <code>Result</code> is allowed to be void by design.
|
||||
|
||||
So the least impact to this routine will be to declare its type as <code>detachable</code>:
|
||||
|
||||
<code>
|
||||
at_first (nm: STRING): detachable NVP
|
||||
-- The first found NVP with name matching nm.
|
||||
-- Or Void if not found
|
||||
</code>
|
||||
|
||||
|
||||
The same change is made in other routines that can return void by design, particularly including a routine called <code>value_at_first</code>, which gets our attention next.
|
||||
|
||||
The case of <code>at_first</code> offered us an opportunity to redesign (or not). We might have been able to leave <code>at_first</code> attached. After all, in void-safe software, the fewer <code>detachable</code>s, the better. Maybe we could devise a way, possibly through preconditions and other queries, that would guarantee that <code>at_first</code> attempts to execute only when it can return a value.
|
||||
|
||||
But <code>at_first</code> is an exported query, so a consequence of such a change in the class design is that it would affect the class interface in such a way that existing clients would have to be modified to comply. In other words, it would be a "breaking" change.
|
||||
|
||||
|
||||
===Source of assignment does not conform to target===
|
||||
|
||||
The change to <code>at_first</code> satisfies the VEVI issue in <code>at_first</code>, but it introduces a previously unseen conformance issue (VJAR) in the routine <code>value_at_first</code>:
|
||||
|
||||
|
||||
[[Image:VoidSafeVJAR1]]
|
||||
|
||||
|
||||
<code>value_at_first</code> looks like this:
|
||||
|
||||
<code>
|
||||
value_at_first (nm: STRING): detachable STRING
|
||||
-- Value from first found NVP with name matching nm
|
||||
-- Or Void of not found
|
||||
require
|
||||
nm_valid: nm /= Void and then not nm.is_empty
|
||||
local
|
||||
tn: NVP
|
||||
do
|
||||
tn := at_first (nm)
|
||||
if tn /= Void then
|
||||
Result := tn.value
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
The problem is that the local variable <code>tn</code> is declared as <code>attached</code>, but we know that now the result of <code>at_first</code> is detachable, making this assignment invalid:
|
||||
<code>
|
||||
tn := at_first (nm)
|
||||
</code>
|
||||
|
||||
Here the '''attached syntax''' can fix the problem and streamline the routine:
|
||||
|
||||
<code>
|
||||
value_at_first (nm: STRING): detachable STRING
|
||||
-- Value from first found NVP with name matching nm
|
||||
-- Or Void of not found
|
||||
require
|
||||
nm_valid: nm /= Void and then not nm.is_empty
|
||||
do
|
||||
if attached at_first (nm) as tn then
|
||||
Result := tn.value
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
In this version <code>tn</code> need not be declared as a local variable. Remember that the attached syntax provides a fresh local variable, if the expression is not void.
|
||||
|
||||
===Both VEVI and VJAR errors===
|
||||
|
||||
A design issue in class <code>NVP_LIST</code> causes both conformance and initialization compiler errors. In the original design, an instance of the class NVP_LIST could traverse its contents NVP-by-NVP with inherited functionality. Additionally, <code>NVP_LIST</code> has immediate functionality allowing an instance to traverse its contents in two different ways returning "sublists" based on recurring patterns of the <code>name</code> attributes of a sequence of name/value pairs.
|
||||
|
||||
These two traversal methods are referred to as "sequencing" and "segmenting". It's not important that you understand the details of what these traversals do. But it is important to know that a valid instance of <code>NVP_LIST</code> can either be in the process of sequencing or in the process of segmenting, or neither. It is invalid to be both sequencing ''and'' segmenting.
|
||||
|
||||
Two class attributes are maintained to store the recurring patterns of values of <code>{NVP}.name</code> that guide traversal:
|
||||
|
||||
<code>
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
sequence_array: ARRAY [STRING]
|
||||
-- The current array of names being used for
|
||||
-- sequence traversal
|
||||
|
||||
segment_array: ARRAY [STRING]
|
||||
-- The current array of names being used to determine
|
||||
-- the termination of list segments
|
||||
</code>
|
||||
|
||||
In the original class design, each of these attributes would be void unless their corresponding traversal was active. So the class contains the following clauses in its invariant:
|
||||
|
||||
<code>
|
||||
not_sequencing_and_segmenting: not (segment_readable and sequence_readable)
|
||||
sequence_traversal_convention: (sequence_array = Void) = (not sequence_readable)
|
||||
segment_traversal_convention: (segment_array = Void) = (not segment_readable)
|
||||
</code>
|
||||
|
||||
Of course by default these attributes are considered to be attached. So, because they are not initialized during creation, we see initialization errors. Because elements of the class intentionally set them to <code>Void</code>, we see conformance errors.
|
||||
|
||||
Here we have another opportunity to redesign (or not). We could mark the two arrays as <code>detachable</code>, recompile and fix any problems this causes (in fact, it causes eight errors: six Target rule violations, and two conformance issues).
|
||||
|
||||
However, because these attributes are not exported, we may be able to leave them attached and make changes to the implementation design without making breaking changes to the interface.
|
||||
|
||||
Those exported features which take arguments of the type <code>ARRAY [STRING]</code> which will serve as sequencing or segmenting control also require that the array contain at least one element. For example, the contract for feature <code>segment_start</code> contains these preconditions:
|
||||
|
||||
<code>
|
||||
segment_start (nms: ARRAY [STRING_8])
|
||||
-- Place segment cursor on the first occurrence of a seqment of list which
|
||||
-- begins at the current cursor position and
|
||||
-- terminates in a sequence with names equivalent to and ordered the same as `nms'.
|
||||
-- If no such sequence exists, then ensure exhausted
|
||||
require
|
||||
nms_valid: nms /= Void and then (nms.count > 0)
|
||||
not_sequencing: not sequence_readable
|
||||
</code>
|
||||
|
||||
Because the restriction always exists that a valid <code>sequence_array</code> or <code>segment_array</code> must contain at least one element, it is possible to redesign the implementation of the class such that an empty <code>sequence_array</code> and <code>segment_array</code> could serve the same purpose as a <code>Void</code> one does in the original design.
|
||||
|
||||
So the invariant clauses that we saw above would now become:
|
||||
|
||||
<code>
|
||||
not_sequencing_and_segmenting: not (segment_readable and sequence_readable)
|
||||
sequence_traversal_convention: (sequence_array.is_empty) = (not sequence_readable)
|
||||
segment_traversal_convention: (segment_array.is_empty) = (not segment_readable)
|
||||
</code>
|
||||
|
||||
We already have compiler errors (VJAR's) that point us to those places in which we have code that sets either <code>sequence_array</code> or <code>segment_array</code> to <code>Void</code>. Like this:
|
||||
|
||||
<code>
|
||||
segment_array := Void
|
||||
</code>
|
||||
|
||||
These instances need to be changed to attach an empty array, maybe like this:
|
||||
|
||||
<code>
|
||||
create segment_array.make (1, 0)
|
||||
</code>
|
||||
|
||||
Additionally, some postconditions which reference the implementation features <code>sequence_array</code> and/or <code>segment_array</code> would have to be changed. Looking at the postcondition clauses for <code>segment_start</code> we see that <code>segment_array</code> is expected (or not) to be <code>Void</code>:
|
||||
|
||||
<code>
|
||||
ensure
|
||||
started: (not exhausted) implies (segment_readable and (segment_array /= Void) and (last_segment_element_index > 0))
|
||||
not_started: exhausted implies ((not segment_readable) and (segment_array = Void) and (last_segment_element_index = 0))
|
||||
</code>
|
||||
|
||||
To support the "empty array" design, <code>segment_start</code>'s postcondition clauses would be:
|
||||
|
||||
<code>
|
||||
ensure
|
||||
started: (not exhausted) implies (segment_readable and (not segment_array.is_empty) and (last_segment_element_index > 0))
|
||||
not_started: exhausted implies ((not segment_readable) and (segment_array.is_empty) and (last_segment_element_index = 0))
|
||||
</code>
|
||||
|
||||
|
||||
|
||||
{{SeeAlso|<br/>[[Converting EiffelVision 2 Systems to Void-Safety]]<br/>[[Void-safe changes to Eiffel libraries]]}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
[[Property:title|Mixing void-safe and void-unsafe software]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:uuid|3446f214-3c77-ef41-98eb-92942298630c]]
|
||||
{{underconstruction}}
|
||||
|
||||
|
||||
=Introduction=
|
||||
|
||||
Eiffel Software recommends that any new development efforts be implemented using Eiffel's void-safe approach, thus eliminating one more common type of runtime failure. It is also recommended that existing software be converted to void-safety at the earliest opportunity.
|
||||
|
||||
Under some circumstances it is possible and even helpful to mix void-safe and void-unsafe libraries. During conversion to void-safety, for example, it can be helpful to compile and test a void-unsafe system with void-safe versions of the libraries it depends upon.
|
||||
|
||||
=Rule for mixing void-safety modes=
|
||||
|
||||
The rule for using void-safe and void-unsafe software together is fairly simple.
|
||||
|
||||
|
||||
{{Rule|name=Mixing void-safe and void-unsafe software|text=<br/>
|
||||
1) A class that is void-unsafe may depend upon other classes (as suppliers or ancestors) which are either void-safe or void-unsafe.<br/>
|
||||
2) A class that is void-safe may depend only upon other classes that are void-safe.}}
|
||||
|
||||
|
||||
This means that if the root class of a system is void-safe, then every other class in the system must also be void-safe.
|
||||
|
||||
However, if you are converting a system to void-safety, it's likely that your root class and the classes in the closely related clusters will be void-unsafe. The rule allows you to mix the void-safe versions of the Eiffel Software library classes from the EiffelStudio distribution with your void-unsafe system during conversion.
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
[[Property:link_title|New void-safe project]]
|
||||
[[Property:title|Creating a new void-safe project]]
|
||||
[[Property:weight|2]]
|
||||
[[Property:uuid|92cea2e9-b094-6380-2c5d-1cd1eb3038b4]]
|
||||
|
||||
{{TOC|limit=2}}
|
||||
|
||||
Now that we've been introduced to the Eiffel void-safe facilities, let's look at what it takes to set up a new void-safe software project. Here we'll look at the void-safety related project settings and how the can be used. Then we'll look deeper into the use of some of the void-safe tools.
|
||||
|
||||
==Project settings for void-safe projects==
|
||||
|
||||
There are two project settings that are related to void-safety. These settings can be set with great granularity throughout your project to allow you maximum flexibility, particularly when including classes or libraries that are void-unsafe or that have been converted to void-safety, but must do double duty in the void-safe and void-unsafe worlds.
|
||||
|
||||
===The ''"Void-safe"'' setting===
|
||||
|
||||
The '''Void-safe''' setting determines whether and how the Eiffel compiler checks your project against the void-safe related validity rules.
|
||||
|
||||
This is the essential void-safe project setting. It can assume one of the following values:
|
||||
# '''No''': No checking against any of the void-safety validity rules. Attachment marks '''attached''' and '''detachable''' are simply ignored.
|
||||
# '''Conformance''': The attachment marks are not ignored for type conformance checks (with respect to VJAR/VBAR and related validity rules).
|
||||
# '''Initialization''': Validity rules are selectively checked. The initialization rule (VEVI) and the target rule (VUTA) are checked only for attached entities and attached call targets -- i.e., detachable cases are not checked.
|
||||
# '''Transitional''': It is an obsolete level which is for users who have already migrated their code to void-safety using an old version of the compiler which did not implement all the void-safety validity rules (especially with agent initialization).
|
||||
# '''Complete''': Complete checking against all void-safety validity rules.
|
||||
|
||||
So, for a new void-safe project, you would want to set this option first to '''Conformance''', then '''Initialization''' and finally to '''Complete'''. This will let you migrate your code progressively without much changes at each steps.
|
||||
|
||||
|
||||
===The ''"Full class checking"'' setting===
|
||||
|
||||
This setting instructs the compiler to recheck inherited features in descendant classes. This setting is True and cannot be changed for projects with some void-safety level enabled.
|
||||
|
||||
|
||||
==Void-safe libraries==
|
||||
|
||||
As of EiffelStudio version 13.11, all libraries distributed with EiffelStudio are void-safe except the EiffelCOM library.
|
||||
|
||||
{{note|During a period of transition, there are different Eiffel configuration files (.ecf's) for void-unsafe and void-safe projects (for example, base.ecf and base-safe.ecf). If you have set the '''Void-safe''' setting to check for void-safety, then when you add a library to your project in EiffelStudio, you will see only the void-safe configurations by default. Starting with version 16.11 there is only one version of each of the configuration files for each library. The single configuration files serve both void-unsafe and void-safe projects.}}
|
||||
|
||||
===Using generic classes===
|
||||
|
||||
Void-safety affects generic classes. Fortunately, from the viewpoint of those writing clients to the generic classes in the EiffelBase library, not much has changed. Still, you should understand the interplay between void-safety and [[ET: Genericity and Arrays|genericity]].
|
||||
|
||||
Consider a generic class like <code>LIST [G]</code>. The formal generic parameter <code>G</code> represents an arbitrary type. In a generic derivation of <code>LIST [G]</code>, say <code>LIST [STRING]</code>, the formal generic type is replaced by an actual generic type, in this case <code>STRING</code>.
|
||||
|
||||
Remember that unconstrained genericity, <code>LIST [G]</code>, for example, is really a case of [[ET: Inheritance#Constrained genericity|constrained genericity]] in which the generic parameter is constrained to <code>ANY</code>, that is, it could be written <code>LIST [G -> ANY]</code>.
|
||||
|
||||
With the advent of void-safe Eiffel, the unconstrained generic class name <code>LIST [G]</code> now equates to <code>LIST [G -> detachable ANY]</code>. Because any type, say <code>T</code>, (synonymous with <code>attached T</code> in void-safe Eiffel) conforms to <code>detachable T</code>, this change facilitates the production of generic classes, but has little effect on writers of clients to those classes.
|
||||
|
||||
This change works for all the generic classes in EiffelBase ... except for one: <code>ARRAY</code>. Arrays are a special case because we often create arrays with a pre-allocated number of elements. In the case of expanded types, there's not a problem. For example, in this code
|
||||
<code>
|
||||
my_array: ARRAY [INTEGER]
|
||||
...
|
||||
create my_array.make (1, 100)
|
||||
</code>
|
||||
we create <code>my_array</code> with one hundred <code>INTEGER</code> elements. <code>INTEGER</code> is an expanded type, and each element is initialized by applying the default initialization rule for <code>INTEGER</code>, i.e, the integer representation of zero.
|
||||
|
||||
However, if <code>my_array</code> had been declared of a type with reference semantics, say <code>STRING</code> (meaning, of course, <code>attached STRING</code>, the default rule would not work well, because the default initialization for references types is <code>Void</code> which would not be allowed in an array of elements of any attached type.
|
||||
|
||||
The solution to this challenge is fairly simple. For arrays of elements of detachable or expanded types, there is no different behavior. When dealing with arrays of elements of attached types, we must be careful.
|
||||
|
||||
Creating an array using <code>ARRAY</code>'s creation procedure <code>make</code> may still be safe in some cases. Specifically, <code>make</code> can be used with arrays of elements of attached types if the arguments have values such that an empty array will be created, that is, when
|
||||
<code>
|
||||
min_index = max_index + 1
|
||||
</code>
|
||||
|
||||
In all other situations involving arrays of elements of attached types, <code>make</code> may not be used to do the creation. Rather, you should use the creation procedure <code>make_filled</code> which takes three arguments. The first is an object of the type of the array, and the second and third are the minimum and maximum indexes, respectively. When the array is created, each of the elements will be initialized with a reference to the object of the first argument.
|
||||
|
||||
So, a call using <code>make_filled</code> would look like this:
|
||||
<code>
|
||||
my_array: ARRAY [STRING]
|
||||
...
|
||||
create my_array.make_filled (" ", 1, 100)
|
||||
</code>
|
||||
Upon creation, each element of the array will reference the same object; an object of type <code>STRING</code> composed of one space character.
|
||||
|
||||
|
||||
==Using the ''attribute'' keyword carefully==
|
||||
|
||||
The keyword <code>attribute</code> should be used with some care. You might be tempted to think that it would be convenient or add an extra element of safety to use [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attributes]] widely. And in a way, you would be correct. But you should also understand that there is a price to pay for using self-initializing attributes and stable attributes. It is that upon every access, an evaluation of the state of the attribute must be made. So, as a general rule, you should avoid using self-initializing attributes only for the purpose of lazy initialization.
|
||||
|
||||
|
||||
==More about the ''attached syntax''==
|
||||
|
||||
The complete attached syntax is:
|
||||
<code>
|
||||
attached {SOME_TYPE} exp as l_exp
|
||||
</code>
|
||||
In this section, we will see more ways in which to use this versatile language facility.
|
||||
|
||||
===As a CAP-like construct which yields a local variable===
|
||||
|
||||
In the introduction to the attached syntax, we used an example which showed how the attached syntax is directly relevant to void-safety. That is, the code:
|
||||
<code>
|
||||
if x /= Void then
|
||||
-- ... Any other instructions here that do not assign to x
|
||||
x.f (a)
|
||||
end
|
||||
</code>
|
||||
|
||||
is a CAP for <code>x</code> ... but that's only true if <code>x</code> is a local variable or a formal argument to the routine that contains the code.
|
||||
|
||||
So to access a detachable attribute safely, we could declare a local variable, make an assignment, and test for <code>Void</code> as above. Something like this:
|
||||
<code>
|
||||
my_detachable_attribute: detachable MY_TYPE
|
||||
|
||||
...
|
||||
some_routine
|
||||
local
|
||||
x: like my_detachable_attribute
|
||||
do
|
||||
x := my_detachable_attribute
|
||||
if x /= Void then
|
||||
-- ... Any other instructions here that do not assign to x
|
||||
x.f (a)
|
||||
end
|
||||
...
|
||||
</code>
|
||||
The attached syntax can both check the attached status of a detachable attribute and also provide a new local variable. So the routine becomes:
|
||||
<code>
|
||||
some_routine
|
||||
do
|
||||
if attached my_detachable_attribute as x then
|
||||
-- ... Any other instructions here that do not assign to x
|
||||
x.f (a)
|
||||
end
|
||||
...
|
||||
</code>
|
||||
|
||||
===As a test for attachment===
|
||||
|
||||
In its simplest form, the attached syntax can be used to test attached status only:
|
||||
<code>
|
||||
if attached x then
|
||||
do_something
|
||||
else
|
||||
do_something_different
|
||||
end
|
||||
</code>
|
||||
|
||||
So in this simple form, <code>attached x</code> can be used instead of <code>x /= Void</code>. The two are semantically equivalent, and which one you choose is a matter of personal preference.
|
||||
|
||||
|
||||
===As a tool for "once per object"===
|
||||
|
||||
There is a code pattern for functions that exists in some Eiffel software to effect "once-per-object / lazy evaluation".
|
||||
|
||||
{{note|As of EiffelStudio version 6.6, the use of this code pattern effecting "once per object" is no longer necessary. V6.6 includes explicit support for <code>once</code> routines which can be adjusted by a [[ET: Once routines and shared objects#Adjusting once semantics with "once keys"|once key]] to specify once per object.}}
|
||||
|
||||
This "once-per-object" code pattern employs a cached value for some object which is not exported. When it is applied, the "once-per-object" function checks the attachment status of the cached value. If the cached value is void, then it is created and assigned to <code>Result</code>. If the cached value was found already to exist, then it is just assigned to <code>Result</code>.
|
||||
|
||||
Here's an example of this pattern used to produce some descriptive text of an instance of its class:
|
||||
|
||||
<code>
|
||||
feature -- Access
|
||||
|
||||
descriptive_text: STRING
|
||||
local
|
||||
l_result: like descriptive_text_cache
|
||||
do
|
||||
l_result := descriptive_text_cache
|
||||
if l_result = Void then
|
||||
create Result.make_empty
|
||||
-- ... Build Result with appropriate
|
||||
-- descriptive text for Current.
|
||||
descriptive_text_cache := Result
|
||||
else
|
||||
Result := l_result
|
||||
end
|
||||
ensure
|
||||
result_attached: Result /= Void
|
||||
result_not_empty: not Result.is_empty
|
||||
result_consistent: Result = descriptive_text
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
descriptive_text_cache: like descriptive_text
|
||||
|
||||
</code>
|
||||
This example will not compile in a void-safe project (class types are attached by default). The problem is that the attribute <code>descriptive_text_cache</code> is of an attached type, therefore will be flagged by the compiler as not properly set (VEVI). Of course, it will be ... that's the whole idea here: not to initialize <code>descriptive_text_cache</code> until it's actually used. So it sounds like <code>descriptive_text_cache</code> should be declared detachable. That is:
|
||||
<code>
|
||||
descriptive_text_cache: detachable like descriptive_text
|
||||
</code>
|
||||
This change will make this routine compile in a void-safe project. But you should notice that there is a ripple-down effect due to the change. Within the routine, <code>l_result</code> is typed <code>like descriptive_text_cache</code>, so it also will be detachable. Therefore we might expect trouble, because later in the routine we have:
|
||||
<code>
|
||||
Result := l_result
|
||||
</code>
|
||||
Because we know Result is attached and l_result is detachable, we might expect a compiler error in which the source of an assignment does not conform to its target (VJAR).
|
||||
|
||||
But we don't get such an error. The reason is two-fold. First, <code>l_result</code> is a local variable whose use can be protected by a CAP. Second, the CAP in this case is the check to ensure that <code>l_result</code> is not void. We only make the assignment to <code>Result</code> if <code>l_result</code> is not void. So the compiler can prove that <code>l_result</code> cannot be void at the point at which the assignment occurs ... therefore, no error.
|
||||
|
||||
Because the '''attached syntax''' can test attached status and provide a local variable, it can be used to remove some unnecessary code from this routine. The version of the routine that follows shows the attached syntax being used to test the attached status of <code>descriptive_text_cache</code> and yield the local variable <code>l_result</code> in the case that <code>descriptive_text_cache</code> is indeed attached.
|
||||
<code>
|
||||
descriptive_text: STRING
|
||||
do
|
||||
if attached descriptive_text_cache as l_result then
|
||||
Result := l_result
|
||||
else
|
||||
create Result.make_empty
|
||||
-- ... Build Result with appropriate
|
||||
-- descriptive text for Current.
|
||||
descriptive_text_cache := Result
|
||||
end
|
||||
ensure
|
||||
result_attached: Result /= Void
|
||||
result_not_empty: not Result.is_empty
|
||||
result_consistent: Result = descriptive_text
|
||||
end
|
||||
|
||||
feature {NONE} -- Implementation
|
||||
|
||||
descriptive_text_cache: like descriptive_text
|
||||
|
||||
</code>
|
||||
|
||||
|
||||
===As a replacement for assignment attempt===
|
||||
|
||||
The assignment attempt ( <code>?=</code> ) has traditionally been used to deal with external objects (e.g., persistent objects from files and databases) and to narrow the type of an object in order to use more specific features. The latter is a process known by names such as "down casting" in some technological circles. A classic example is doing specific processing on some elements of a polymorphic data structure. Let's look at an example. Suppose we have a <code>LIST</code> of items of type <code>POLYGON</code>:
|
||||
<code>
|
||||
my_polygons: LIST [POLYGON]
|
||||
</code>
|
||||
<code>POLYGON</code>s could be of many specific types, and one of those could be <code>RECTANGLE</code>. Suppose too that we want to print the measurements of the diagonals of all the <code>RECTANGLE</code>s in the list. Class <code>RECTANGLE</code> might have a query <code>diagonal</code> returning such a measurement, but <code>POLYGON</code> would not, for the reason that the concept of diagonal is not meaningful for all <code>POLYGON</code>s, e.g., <code>TRIANGLE</code>s.
|
||||
|
||||
As we traverse the list we would use assignment attempt to try to attach each <code>POLYGON</code> to a variable typed as <code>RECTANGLE</code>. If successful, we can print the result of the application of <code>diagonal</code>.
|
||||
<code>
|
||||
l_my_rectangle: RECTANGLE
|
||||
|
||||
...
|
||||
from
|
||||
my_polygons.start
|
||||
until
|
||||
my_polygons.exhausted
|
||||
loop
|
||||
l_my_rectangle ?= my_polygons.item
|
||||
if l_my_rectangle /= Void then
|
||||
print (l_my_rectangle.diagonal)
|
||||
print ("%N")
|
||||
end
|
||||
my_polygons.forth
|
||||
end
|
||||
</code>
|
||||
The '''attached syntax''' allows us to check both attached status and type, and provides us with a fresh local variable when appropriate:
|
||||
<code>
|
||||
from
|
||||
my_polygons.start
|
||||
until
|
||||
my_polygons.exhausted
|
||||
loop
|
||||
if attached {RECTANGLE} my_polygons.item as l_my_rectangle then
|
||||
print (l_my_rectangle.diagonal)
|
||||
print ("%N")
|
||||
end
|
||||
my_polygons.forth
|
||||
end
|
||||
</code>
|
||||
As with the other examples of the '''attached syntax''', it is no longer necessary to make a declaration for the local variable, in this case <code>l_my_rectangle</code>.
|
||||
|
||||
|
||||
==More about CAPs==
|
||||
|
||||
===Use of <code>check</code> instructions===
|
||||
|
||||
In void-safe mode, the compiler will accept code that it can prove will only apply features to attached references at runtime ... and you help this process along by using the tools of void-safety, like attached types and CAPs. On the other hand, the compiler will reject code that it cannot guarantee is void-safe. Sometimes this may cause you a problem. There may be subtle situations in which you feel quite certain that a section of code will be free of void calls at runtime, but the compiler doesn't see it the same way, and rejects your code. In cases like this, you can usually satisfy the compiler by using <code>check</code> instructions.
|
||||
|
||||
Technically speaking, <code>check</code> instructions are not CAPs. But they are useful in cases in which an entity is always expected to be attached at a certain point in the code. In the following example, the attribute <code>my_detachable_any</code> is detachable. But at the particular point at which it is the source of the assignment to <code>l_result</code>, it is expected always to be attached. If it is not attached at the time of the assignment, and therefore <code>l_result</code> becomes void, then an exception should occur. The <code>check</code> instruction provides this behavior.
|
||||
|
||||
The following sample shows the <code>check</code> instruction at work. There are reasons why this is not the best use use of <code>check</code> in this case, and we will discuss that next.
|
||||
|
||||
<code>
|
||||
-- A not-so-good example of using check.
|
||||
|
||||
my_detachable_any: detachable ANY
|
||||
...
|
||||
my_attached_any: ANY
|
||||
local
|
||||
l_result: like my_detachable_any
|
||||
do
|
||||
l_result := my_detachable_any
|
||||
check
|
||||
attached l_result
|
||||
end
|
||||
Result := l_result
|
||||
end
|
||||
</code>
|
||||
|
||||
Here the assertion in the <code>check</code> guarantees that <code>l_result</code> is attached at the time of its assignment to <code>Result</code>. If <code>my_detachable_any</code> is ever not attached to an object, then an exception will be raised.
|
||||
|
||||
So what's wrong with the sample above? It would be fine in ''workbench'' code, but what happens if the code is in ''finalized'' mode, in which assertions are typically discarded?
|
||||
|
||||
The answer is that the <code>check</code> in the sample above would no longer be effective, and the resulting executable would no longer be void-safe.
|
||||
|
||||
The solution to this problem is found in a different form of the <code>check</code> instruction. Consider the same example, but this time using <code>check ... then ... end</code>:
|
||||
|
||||
<code>
|
||||
-- A better way of using check.
|
||||
|
||||
my_detachable_any: detachable ANY
|
||||
...
|
||||
my_attached_any: ANY
|
||||
do
|
||||
check attached my_detachable_any as l_result then
|
||||
Result := l_result
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
Here, in the improved version of the example, the <code>check ... then ... end</code> is used along with the <code>attached</code> syntax. This streamlines the code a bit by eliminating the need to declare a separate local entity, while achieving the same effect as the previous example. If <code>my_detachable_any</code> is attached at runtime, then the temporary variable <code>l_result</code> is created and attached to the same object. Then the body of the <code>check ... then ... end</code> is executed. If <code>my_detachable_any</code> is not attached, an exception occurs.
|
||||
|
||||
Another important benefit, one that solves the problem with the original example, comes from the way in which <code>check ... then ... end</code> is handled by the compiler. The <code>check ... then ... end</code> form '''is always monitored, even if assertion checking is turned off at all levels''', as is usually done in finalized code.
|
||||
|
||||
===Choosing CAPs versus the Attached Syntax===
|
||||
|
||||
The attached syntax is convenient because it can check attached status and deliver a new local variable at the same time. But there are cases in which you might choose instead to define a local variable and use a CAP. Suppose you had code acting on several similar and detachable expressions, and you use the attached syntax in each case:
|
||||
<code>
|
||||
foobar
|
||||
do
|
||||
if attached dictionary_entry ("abc") as l_abc then
|
||||
l_abc.do_something
|
||||
end
|
||||
if attached dictionary_entry ("def") as l_def then
|
||||
l_def.do_something
|
||||
end
|
||||
if attached dictionary_entry ("ghi") as l_ghi then
|
||||
l_ghi.do_something
|
||||
end
|
||||
end
|
||||
</code>
|
||||
This routine causes three local variables to be allocated for the duration of routine <code>foobar</code>, one each for <code>l_abc</code>, <code>l_def</code>, and <code>l_ghi</code>. And it is no better to do this:
|
||||
<code>
|
||||
foobar
|
||||
do
|
||||
if attached dictionary_entry ("abc") as l_entry then
|
||||
l_entry.do_something
|
||||
end
|
||||
if attached dictionary_entry ("def") as l_entry then
|
||||
l_entry.do_something
|
||||
end
|
||||
if attached dictionary_entry ("ghi") as l_entry then
|
||||
l_entry.do_something
|
||||
end
|
||||
end
|
||||
</code>
|
||||
Even though the names are the same, still three separate local variables are allocated for <code>foobar</code>.
|
||||
|
||||
In cases like this, you could effect a minor performance improvement by declaring one local variable and reusing it. In the following code, only one local variable is used and access to it is protected by the CAP <code>if l_entry /= Void then</code>.
|
||||
<code>
|
||||
foobar
|
||||
local
|
||||
l_entry: like dictionary_entry
|
||||
do
|
||||
l_entry := dictionary_entry ("abc")
|
||||
if l_entry /= Void then
|
||||
l_entry.do_something
|
||||
end
|
||||
l_entry := dictionary_entry ("def")
|
||||
if l_entry /= Void then
|
||||
l_entry.do_something
|
||||
end
|
||||
l_entry := dictionary_entry ("ghi")
|
||||
if l_entry /= Void then
|
||||
l_entry.do_something
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
==Stable attributes==
|
||||
|
||||
Remember that stable attributes are actually detachable attributes, with the difference that they can never be the target of an assignment in which the source is <code>Void</code> or anything that could have a value of <code>Void</code>.
|
||||
|
||||
Stable attributes are useful in situations in which there are valid object life scenarios in which some particular attribute will never need an object attached, or will only need an object attached late in the scenario. So in this case, the attribute is used only under certain runtime conditions. Declaring these attributes as stable eliminates the need to make attachments during object creation. Yet once needed, that is, once the attribute is attached, it will always be attached.
|
||||
|
||||
Also, you should remember that unlike other attributes, you can access stable attributes directly in a CAP:
|
||||
<code>
|
||||
my_stable_attribute: detachable SOME_TYPE
|
||||
note
|
||||
option: stable
|
||||
attribute
|
||||
end
|
||||
|
||||
...
|
||||
|
||||
if my_stable_attribute /= Void then
|
||||
my_stable_attribute.do_something
|
||||
end
|
||||
|
||||
...
|
||||
</code>
|
||||
|
||||
{{SeeAlso| [[Void-safety: Background, definition, and tools#Types as "attached" or "detachable"|Types as "attached" or "detachable"]].}}
|
||||
@@ -0,0 +1,23 @@
|
||||
[[Property:link_title|Void-safe programming]]
|
||||
[[Property:title|Void-safe programming in Eiffel]]
|
||||
[[Property:weight|10]]
|
||||
[[Property:uuid|a03568e8-eb79-70d7-04a3-6fd3ed7ac2b3]]
|
||||
=Void-safe software development using Eiffel: introduction=
|
||||
|
||||
When you develop software in Eiffel, you can be assured (at compile time) that your system will not attempt (at run time) to apply a feature to a void reference -- or, in the terminology of other languages such as C, "dereference a null pointer".
|
||||
|
||||
Throughout the history of Eiffel, new capabilities -- agents, the SCOOP concurrency mechanism and many others -- have added considerable expressive power to the languag,e while causing minimum impact on existing software. Void-safe Eiffel is such an innovation, which instead of adding new mechanisms ''removes'' a major source of instability in programs, present in all other major languages: null-pointer dereferencing. To say that Eiffel is void-safe means that such catastrophic yet common errors simply will not occur.
|
||||
|
||||
There is in fact no need to speak of "void-safe Eiffel". The language is just Eiffel... and it is void-safe, just as it is statically typed. We still occasionally refer to "Void-safe Eiffel" simply because until 2005 or so Eiffel was not void-safe (it had to start somewhere), and you may still encounter older documentation that talks about "calls on void targets" (null-pointer dereferences). But in today's Eiffel such an event is impossible.
|
||||
|
||||
The rest of this chapter explains void safety:
|
||||
|
||||
# How is void-safety defined?
|
||||
# What are the specific elements of the mechanism?
|
||||
# How do these relate to Eiffel before void-safety?
|
||||
# What do I need to know to produce standard Eiffel software?
|
||||
# What do I need to know to convert my existing systems to be standard?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
[[Property:link_title|Background and tools]]
|
||||
[[Property:title|Void-safety: Background, definition, and tools]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|689f62b2-5675-5ab6-cd47-d891cf3d484d]]
|
||||
=Background=
|
||||
|
||||
The primary focus of Eiffel is on software quality. Void-safety, like static typing, is another facility for improving software quality. Void-safe software is protected from run time errors caused by calls to void references, and therefore will be more reliable than software in which calls to void targets can occur. The analogy to static typing is a useful one. In fact, void-safe capability could be seen as an extension to the type system, or a step beyond static typing, because the mechanism for ensuring void-safety is integrated into the type system.
|
||||
|
||||
==Static typing==
|
||||
|
||||
You know that static typing eliminates a whole class of software failures. This is done by making an assurance at compile time about a feature call of the form:
|
||||
<code>
|
||||
x.f (a)
|
||||
</code>
|
||||
Such a feature call is judged acceptable at compile time only if the type of <code>x</code> has a feature <code>f</code> and that any arguments, represented here by <code>a</code>, number the same as the formal arguments of <code>f</code>, and are compatible with the types of those formal arguments.
|
||||
|
||||
|
||||
In statically typed languages like Eiffel, the compiler guarantees that you cannot, at run time, have a situation in which feature <code>f</code> is not applicable to the object attached to <code>x</code>. If you've ever been a Smalltalk programmer, you are certainly familiar with this most common of errors that manifests itself as "Message not understood." It happens because Smalltalk is not statically typed.
|
||||
|
||||
==Void-unsafe software==
|
||||
|
||||
Static typing will ensure that there is some feature <code>f</code> that can be applied at run time to <code>x</code> in the example above. But it does not assure us that, in the case in which <code>x</code> is a reference, that there will always be an object attached to <code>x</code> at any time <code>x.f (a)</code> is executed.
|
||||
|
||||
This problem is not unique to Eiffel. Other environments that allow or mandate reference semantics also allow the possibility of void-unsafe run time errors. If you've worked in Java or .NET you may have seen the NullReferenceException. Sometimes you might have experienced this rather poetic sounding message: "Object reference not set to an instance of an object". In Eiffel you would see "Feature call on void target". All these are the hallmarks of run time errors resulting from void-unsafe software.
|
||||
|
||||
{{note|If you need a review of difference between reference types and expanded types in Eiffel, see [[ET: The Dynamic Structure: Execution Model|the chapter of the Eiffel Tutorial dedicated to the Eiffel execution model]]. }}
|
||||
|
||||
Of course this is not an issue with instances of expanded types, because these instances are indeed "expanded" within their parent objects. But we could not imagine a world with expanded types only. References are important for performance reasons and for modeling purposes. For example, consider that a car has an engine and a manufacturer. When we model cars in software, it might be appropriate for engines to be expanded types, as each car has one engine. But certainly the same is not true for manufacturer. Many cars can share, through a reference, a single manufacturer.
|
||||
|
||||
So, references are necessary, but we want them to be trouble free.
|
||||
|
||||
==Void-safe software==
|
||||
|
||||
Void-safe software, then, is software in which the compiler can give assurance, through a static analysis of the code, that at run time whenever a feature is applied to a reference, that the reference in question will have an object attached. This means that the feature call
|
||||
<code>
|
||||
x.f (a)
|
||||
</code>
|
||||
is valid only if we are assured that <code>x</code> will be attached to an object when the call executes.
|
||||
|
||||
|
||||
{{info|This validity rule is called the '''Target rule''', validity code VUTA, and is the primary rule for void-safety. In the following discussion, you will see that other validity rules are involved, too. You can see the formal definition of all validity rules in the [http://www.ecma-international.org/publications/standards/Ecma-367.htm ISO/ECMA standard document] available online. }}
|
||||
|
||||
|
||||
Once we have committed ourselves to this validity rule, we must have a strategy for complying with the rule.
|
||||
|
||||
=Elements of the void-safe strategy=
|
||||
|
||||
Here are the tools of void-safe trade. They will each be addressed in more detail throughout the documentation that follows. As you look at these elements it helps to try to think about things from the compiler's viewpoint ... after all, it is the compiler that we expect to give us the guarantee that our code is indeed void-safe.
|
||||
|
||||
First let's look at a couple of approaches that won't work.
|
||||
|
||||
It might occur to us that we could enforce compliance with the target rule by simply eliminating the concept of void references. But this would not be practical. Void is a valuable abstraction that is useful in many situations, such as providing void links in structures. So, we must keep void ... but we want to keep it under control.
|
||||
|
||||
Another thought might be that we could just have the compiler do all the work for us. But would be impossibly time consuming for the compiler to investigate every conceivable execution path available to a system to make certain that every possible feature call was made on an attached reference.
|
||||
|
||||
So, all of this boils down to the fact that we have to take some actions that help the compiler along. That's what the following are about.
|
||||
|
||||
==Certified Attachment Patterns (CAPs)==
|
||||
|
||||
We know that in the context of certain code patterns, it is clear that it would be impossible for a reference to be void. These patterns are identified and we call them CAPs, short for Certified Attachment Patterns. Here is a very straightforward example expressed in a syntax that should be familiar to all Eiffel developers:
|
||||
<code>
|
||||
if x /= Void then
|
||||
-- ... Any other instructions here that do not assign to x
|
||||
x.f (a)
|
||||
end
|
||||
</code>
|
||||
Here a check is made to ensure <code>x</code> is not void. Then as long as no assignments to <code>x</code> are made in the interim, a feature <code>f</code> can be applied to <code>x</code> with the certainty that <code>x</code> will be attached at the time ... and importantly, this can be determined at compile time. So, we say that this code pattern is a CAP for <code>x</code>.
|
||||
|
||||
|
||||
It is important to understand that in this example (and with other CAPs), <code>x</code> is allowed to be a local variable or formal argument only. That is, <code>x</code> may not be an attribute or general expression (with one exception which we will see [[#Stable attributes|below]]). Direct access to class attribute references cannot be allowed via a CAP due to the fact that they could be set to void by a routine call in some execution path invoked by the intervening instructions or possibly even different process thread. In a later [[Void-safety: Background, definition, and tools#Types as "attached" or "detachable"|section]], we well see that this is not quite such a limitations as it may appear at this point.
|
||||
|
||||
|
||||
{{note|You will find more useful information about CAPs in [[Creating a new void-safe project#More about CAPs|More about CAPs]]. Learn how certain code patterns are determined to be CAPs in [[What makes a Certified Attachment Pattern]]. }}
|
||||
|
||||
|
||||
==The ''attached syntax'' (object test)==
|
||||
|
||||
For the purposes of void-safety, the '''attached syntax''' does double duty for us. It allows us to make certain that a reference is attached, and it provides us a safe way to access objects that are attached to class attributes.
|
||||
|
||||
We noted earlier that this code
|
||||
<code>
|
||||
if x /= Void then
|
||||
-- ... Any other instructions here that do not assign to x
|
||||
x.f (a)
|
||||
end
|
||||
</code>
|
||||
creates a CAP for feature calls on <code>x</code>, but only if <code>x</code> is a local variable or a formal argument.
|
||||
|
||||
By using the '''attached syntax''', we can perform an '''object test''' on a variable. That is, the attached syntax is a <code>BOOLEAN</code> expression which provides an answer to the question "Is <code>x</code> attached to an object?" At the same time, if indeed <code>x</code> is attached to an object, the attached syntax will deliver to us a fresh local variable, also attached to <code>x</code>'s object, on which we can make feature calls.
|
||||
<code>
|
||||
if attached x as l_x then
|
||||
l_x.f (a)
|
||||
end
|
||||
</code>
|
||||
In the example above, <code>x</code> is tested to make certain that it is attached. If so, the new local <code>l_x</code> becomes attached to the same object as <code>x</code>. And so the object can be used safely even if <code>x</code> is a class attribute. So, the attached syntax, is really another CAP, because it provides a clearly verifiable place for the application of features to targets that are guaranteed not to be void.
|
||||
|
||||
|
||||
{{note|The attached syntax has other syntax variations as well as other uses. These will be discussed [[Creating a new void-safe project#More about the attached syntax|later]]. }}
|
||||
|
||||
|
||||
One way to make sure we comply with the target rule would be always use a CAP or the attached syntax every time we want to apply a feature to a referenced object. That might work, but it falls among the impractical approaches to the problem ... it would break a very high percentage of existing Eiffel code, not to mention cluttering things up quite a bit.
|
||||
|
||||
==Types as "attached" or "detachable"==
|
||||
|
||||
Rather than trying to protect every feature call, Eiffel allows us to declare any variable as being of an '''attached type'''. This is an important extension to the Eiffel type system.
|
||||
|
||||
In Eiffel prior to the introduction of void-safe facilities, any reference variable could be set to <code>Void</code>. So, all variables were considered '"detachable"'.
|
||||
|
||||
The current standard Eiffel supports a mixture of '''attached''' and '''detachable''' types. When a variable is declared of an attached type, as in the following example, then the compiler will prevent it from being set to <code>Void</code> or set to anything that can be set to <code>Void</code>.
|
||||
|
||||
<code>
|
||||
my_attached_string: attached STRING
|
||||
</code>
|
||||
|
||||
It is easy to imagine that the more declarations are of attached types, the easier it will be to guarantee that a call to a void target cannot take place at run time. In fact, if every declaration was guaranteed to be of an attached type, then that would be all that was needed to satisfy the Target rule.
|
||||
|
||||
However, it wouldn't be workable to have only attached types, because sometimes it's important to allow references to have a value of <code>Void</code>.
|
||||
|
||||
When it is necessary to allow <code>Void</code> as a value, a declaration can use the ''detachable mark'' as in the following.
|
||||
<code>
|
||||
my_detachable_string: detachable STRING
|
||||
</code>
|
||||
|
||||
|
||||
This doesn't mean that on every declaration you must put either an ''attached mark'' or a ''detachable mark''. Declarations that are unmarked are allowed. If a declaration contains neither '''attached''' nor '''detachable''', then it is assumed to be '''attached'''.
|
||||
|
||||
In Eiffel then, all declarations will have types that are either '''attached''' or '''detachable'''. As a result, we need only use CAPs and the attached syntax with detachable types. So the important thing to remember is that ''direct access to class attributes of detachable types is never void-safe.''
|
||||
|
||||
===Attachment and conformance===
|
||||
|
||||
The distinction between attached and detachable types results in a small but important addition to the rules of conformance. Because variables declared as attached types can never be void, then it is important not to allow any assignment of a detachable source to an attached target. However, assigning an attached source to a detachable target is permissible. The following code shows both cases (as described earlier, class types are attached by default).
|
||||
<code>
|
||||
my_attached_string: STRING
|
||||
my_detachable_string: detachable STRING
|
||||
|
||||
...
|
||||
|
||||
my_attached_string := my_detachable_string -- Invalid
|
||||
my_detachable_string := my_attached_string -- Valid
|
||||
</code>
|
||||
|
||||
|
||||
==Initialization rule==
|
||||
|
||||
If we have attached types, then we can assume variables declared of these types, once attached, will always be attached. But how do they get attached in the first place? That's what the initialization rule is all about.
|
||||
|
||||
The rule says that at any place in which a variable is accessed, it must be '''properly set'''. A variable's being properly set has a precise, but not particularly simple definition in the Eiffel standard.
|
||||
|
||||
|
||||
{{info|You can find the formal definition of the '''Variable initialization rule''', validity code VEVI, and its related concepts such as '''properly set''' variables in the [http://www.ecma-international.org/publications/standards/Ecma-367.htm ISO/ECMA standard document]. }}
|
||||
|
||||
|
||||
Still, it's not too hard to understand the basics of initializing variables of attached types:
|
||||
|
||||
* For the initialization of attributes of a class, we can apply a rule similar to that of the initial evaluation of class invariants ... that is, everything must be in order upon completion of a creation procedure. If a class attribute is of an attached type, then each of the class's creation procedures is responsible for making sure that the attribute is attached to an object upon its completion.
|
||||
|
||||
* A local variable is considered properly set if it is initialized at some point '''preceding''' its use in any execution path in which it is used. So immediately after its <code>create</code> instruction, the local variable would be considered properly set. But if the <code>create</code> occurred in the <code>then</code> part of an <code>if</code> instruction, the local variable would not be properly set in the <code>else</code> part of that same <code>if</code> instruction:
|
||||
|
||||
<code>
|
||||
my_routine
|
||||
-- Illustrate properly set local variable
|
||||
local
|
||||
l_my_string: STRING
|
||||
do
|
||||
if my_condition then
|
||||
create l_my_string.make_empty
|
||||
-- ... l_my_string is properly set here
|
||||
else
|
||||
-- ... l_my_string is not properly set here
|
||||
end
|
||||
end
|
||||
</code>
|
||||
|
||||
* A variable is considered properly set if it is '''self-initializing'''. What it means to be self-initializing is explained below.
|
||||
|
||||
==Self-initializing attributes==
|
||||
|
||||
A self-initializing attribute is guaranteed to have a value when accessed at run time. Declarations of self-initializing attributes are characterized by the use of the code that follows the <code>attribute</code> keyword. The code is executed to initialize the attribute in the case that the attribute is accessed prior to being initialized in any other way.
|
||||
|
||||
So, self-initializing attributes are ordinary attributes, with the restriction that they are of both ''attached'' types and ''reference'' types (i.e., not expanded types or constants). Self-initializing attributes still can be, and typically will be initialized in the traditional ways. The difference is that the code in the attribute part serves as a kind of safety net guaranteeing that a self-initializing attribute will never be void, even if it is accessed prior to being initialized by one of the traditional means.
|
||||
|
||||
<code>
|
||||
value: STRING
|
||||
attribute
|
||||
create Result.make_empty
|
||||
end
|
||||
</code>
|
||||
|
||||
In the example above, the attribute <code>value</code> will be attached to an object of type <code>STRING</code>, in fact, the empty string, if no other initialization occurs before the first access of <code>value</code>.
|
||||
|
||||
==Rule for conformance==
|
||||
|
||||
You will remember that the Eiffel type system dictates that an assignment instruction:
|
||||
<code>
|
||||
x := y
|
||||
</code>
|
||||
is valid only if the type of <code>y</code> is '''compatible''' with the type of <code>x</code>. Compatibility, in turn, means either '''conversion''' or '''conformance'''.
|
||||
|
||||
The fact that all types are either '''attached''' or '''detachable''' adds another dimension to rule for conformance:
|
||||
*If x is of an attached type, then y must be of an attached type.
|
||||
This prevents us from circumventing attached status at run time. If <code>x</code> is of a detachable type, then <code>y</code> could be either a detachable or attached type.
|
||||
|
||||
The same goes for routine calls. In a call:
|
||||
<code>
|
||||
z.r (y)
|
||||
</code>
|
||||
where <code>x</code> is the formal argument for <code>r</code>, then if x is of an attached type, then y must be of an attached type.
|
||||
|
||||
==Stable attributes==
|
||||
|
||||
Stable attributes are really stable ''detachable'' attributes, as adding the concept of stability is meaningful only for detachable attributes. Declaring a detachable attribute as stable, means that it behaves like a detachable attribute except that its assignment rules mimic those of attached attributes. In other words, a stable attribute does not need to be attached during object creation the way that attributes declared as attached must. But like attached type attributes, stable attributes can never be the target of an assignment in which the source is <code>Void</code> or a detachable type.
|
||||
<code>
|
||||
my_test: detachable TEST
|
||||
note
|
||||
option: stable
|
||||
attribute
|
||||
end
|
||||
</code>
|
||||
|
||||
This means that even though stable attributes do not need to be initialized like attributes of attached types, once they are attached to an object, they can never be void again.
|
||||
|
||||
Stable attributes are also interesting in that they are the only exception to the rule given above in the [[Void-safety: Background, definition, and tools#Certified Attachment Patterns (CAPs)|CAPs section]] that stated that direct access to attributes cannot be protected by a CAP. A stable attribute can be used under the protection of a CAP. This is because once a stable attribute has an object attached, it can never again be set to <code>Void</code>. So there's no worry about having the attribute's state going unexpectedly from attached to non-attached because of the actions of other routines or threads.
|
||||
|
||||
==Rule for generic parameters==
|
||||
|
||||
Generic classes provide another question. A generic class like
|
||||
<code>
|
||||
class
|
||||
C [G]
|
||||
...
|
||||
</code>
|
||||
allows us to create a type by providing a specific actual generic parameter for the formal parameter <code>G</code>.
|
||||
|
||||
So, two valid derivations are:
|
||||
<code>
|
||||
my_integer_derivation: C [INTEGER]
|
||||
</code>
|
||||
and
|
||||
<code>
|
||||
my_employee_derivation: C [EMPLOYEE]
|
||||
</code>
|
||||
|
||||
If class C contains a declaration:
|
||||
<code>
|
||||
x: G
|
||||
</code>
|
||||
What do we know about the void-safety of <code>x</code> ?
|
||||
|
||||
In the case of the <code>INTEGER</code> derivation above, we know <code>x</code> is safe because <code>INTEGER</code> is an expanded type. But often types like <code>EMPLOYEE</code> will be reference types which could be void at run time.
|
||||
|
||||
'''For a class like <code>C [G]</code>, <code>G</code> is considered detachable'''. As a result, because of the [[Void-safety: Background, definition, and tools#Rule for conformance|rule for conformance]], any class will work for an actual generic parameter. That means that both of the following are valid generic derivations:
|
||||
|
||||
<code>
|
||||
my_detachable_string_derivation: C [detachable STRING]
|
||||
|
||||
my_attached_string_derivation: C [attached STRING]
|
||||
</code>
|
||||
|
||||
If <code>C</code> contains a declaration <code>x: G</code>, the application of features to <code>x</code> must include verification of attachment (CAPs, attached syntax, etc).
|
||||
|
||||
Constrained genericity can be used to create generic classes in which the generic parameter represents an attached type. If class <code>C</code> had been defined as:
|
||||
<code>
|
||||
class C [G -> attached ANY]
|
||||
...
|
||||
</code>
|
||||
then <code>x</code> in this class <code>G</code> represents an attached type. Consequently, the actual generic type in any derivation must be attached ... and feature calls on <code>x</code> are safe.
|
||||
|
||||
==Rule for ARRAYs==
|
||||
|
||||
The rule for generic parameters applies to all generic types ... except <code>ARRAYs</code>. In the typical creation of an <code>ARRAY</code>, we would provide a minimum and maximum index.
|
||||
<code>
|
||||
my_array: ARRAY [STRING]
|
||||
|
||||
...
|
||||
|
||||
create my_array.make (1, 100)
|
||||
</code>
|
||||
During creation, an area to store the appropriate number of entries is also created. And depending upon the actual generic parameter, these entries are either objects for expanded types or references for reference types.
|
||||
|
||||
In the case of an actual generic parameter of an attached reference type, all the elements must be attached to instances of type during the creation of the ARRAY. The <code>make</code> procedure would not do this. Creation of an <code>ARRAY</code> in which the actual generic parameter is attached must be done using the <code>make_filled</code> creation procedure.
|
||||
<code>
|
||||
create my_array.make_filled ("", 1, 100)
|
||||
</code>
|
||||
The first argument is an object of the actual generic type, in this case an empty <code>STRING</code>. Every entry in the newly created <code>ARRAY</code> will be initialized to reference this object.
|
||||
|
||||
|
||||
For more detail on void-safe use of arrays and other generic classes, see the section: [[Creating a new void-safe project#Using generic classes|Using generic classes]].
|
||||
@@ -0,0 +1,182 @@
|
||||
[[Property:title|What makes a Certified Attachment Pattern]]
|
||||
[[Property:weight|8]]
|
||||
[[Property:uuid|1a20197d-5a88-59c3-9a04-512399125661]]
|
||||
|
||||
==A little background on CAPs==
|
||||
|
||||
Certified Attachment Patterns (CAPs) were described in the section on [[Void-safety: Background, definition, and tools#Certified attachment patterns (CAPs)|void-safety tools]]. To review, a CAP is a code pattern for a certain expression, say <code>exp</code> of a detachable type that ensures that <code>exp</code> will never have a void run-time value within the covered scope.
|
||||
|
||||
A simple example is the familiar test for void reference:
|
||||
<code>
|
||||
if l_x /= Void then
|
||||
l_x.do_something -- Valid for formal arguments, local variables, and stable attributes
|
||||
end
|
||||
</code>
|
||||
We know that after the explicit check to make sure <code>l_x</code> is not <code>Void</code>, that the feature application <code>l_x.do_something</code> is void-safe.
|
||||
Of course, you should remember from previous discussions that <code>l_x</code> must be a local variable, a formal argument, or a [[Void-safety: Background, definition, and tools#Stable attributes|stable attribute]].
|
||||
|
||||
When void-safety was first envisioned for Eiffel, it was intended that individual CAPs would be proven or certified and documented. This would produce a "catalog" of CAPs.
|
||||
|
||||
What happened instead is that the members of the Eiffel standard committee have been able to produce and publish as part of the [http://www.ecma-international.org/publications/standards/Ecma-367.htm standard] a definition of the nature of a CAP from which a determination can be made as to whether a particular code pattern is or is not a CAP.
|
||||
|
||||
The definition in the standard document is not easily readable by most developers. So, in this documentation, you will see various examples of CAPs and the rationale behind them.
|
||||
|
||||
|
||||
==The standard CAP definition==
|
||||
|
||||
The Eiffel standard (2nd edition, June 2006) defines a CAP as follows:
|
||||
----
|
||||
'''''A Certified Attachment Pattern (or CAP) for an expression <code>exp</code> whose type is detachable is an occurrence of <code>exp</code> in one of the following contexts: '''''
|
||||
|
||||
|
||||
'''''1. <code>exp</code> is an Object-Test Local and the occurrence is in its scope. '''''
|
||||
|
||||
'''''2. <code>exp</code> is a read-only entity and the occurrence is in the scope of a void test involving <code>exp</code>.'''''
|
||||
----
|
||||
|
||||
The terminology used in the definition is precise. For example, terms like "read-only entity" and "scope of a void test" have specific meanings that are supported by their own definitions in the standard.
|
||||
|
||||
Still, the standard does contain informative text that gives us a guideline that a CAP is a scheme to ensure that a particular expression of a detachable type will never have void run-time value in the scope covered by the CAP.
|
||||
|
||||
The discussion here will follow that guideline, and, as such, will be less formal (and consequently less precise) than that in the standard, and is intended to be a practical guide. Of course, the [http://www.ecma-international.org/publications/standards/Ecma-367.htm standard document] is available for download if you wish to investigate the specifics.
|
||||
|
||||
|
||||
==CAP-able expressions==
|
||||
|
||||
In the first context in the definition above, the expression <code>exp</code> can be an '''Object-Test Local'''. An Object-Test Local is the identifier specified for a fresh local entity in an '''object test'''. Remember, object tests are coded using the [[Void-safety: Background, definition, and tools#The attached syntax (object test)|attached syntax]].
|
||||
<code>
|
||||
attached x as l_x
|
||||
</code>
|
||||
In the object test expression above, the identifier '''<code>l_x</code>''' is an Object-Test Local.
|
||||
|
||||
In the second context, the expression can be a '''read-only entity'''. Read-only entities are:
|
||||
# Constant attributes
|
||||
# Formal arguments
|
||||
# Object-Test Locals
|
||||
# <code>Current</code>
|
||||
|
||||
Additionally, the Eiffel Software compiler allows for [[Void-safety: Background, definition, and tools#Stable attributes|stable attributes]] and local variables to be protected by a CAP.
|
||||
|
||||
===Stable attributes===
|
||||
|
||||
Stable attributes are the only class attributes which are CAP-able. This is because stable attributes, once attached at run-time, can never have a void value again. So, you use stable attributes safely by using them under the protection of a CAP. Consider this stable attribute:
|
||||
<code>
|
||||
my_stable_string: detachable STRING
|
||||
note
|
||||
option: stable
|
||||
attribute
|
||||
end
|
||||
</code>
|
||||
The detachable attribute <code>my_stable_string</code>, because it is stable, is not required to be initialized during the creation of instances of the class in which it is a feature. That means that for each instance, <code>my_stable_string</code> can be initialized later during the instance's life-cycle or not at all. But because it is detachable, <code>my_stable_string</code> cannot be accessed in any context in which it cannot be determined that it is currently attached. For ordinary attributes, this means either using an object test and accessing the object through an object test local, or using using a local variable under the protection of a CAP.
|
||||
|
||||
Stable attributes however, can be used directly in a CAP, as shown below:
|
||||
|
||||
<code>
|
||||
if my_stable_string /= Void then
|
||||
my_stable_string.append ("abc") -- Valid
|
||||
...
|
||||
</code>
|
||||
|
||||
So using stable attributes can reduce the need to initialize rarely used attributes, and the need to code object tests.
|
||||
|
||||
===Local variables===
|
||||
|
||||
Local variables can be used in a CAP as long as they are not the target of an assignment whose source is <code>Void</code> or some expression which could possibly be void.
|
||||
|
||||
So, for a local variable <code>l_string</code>, the following is valid:
|
||||
<code>
|
||||
local
|
||||
l_string: detachable STRING
|
||||
do
|
||||
if l_string /= Void then
|
||||
l_string.append ("abc") -- Valid
|
||||
...
|
||||
</code>
|
||||
|
||||
But, if <code>l_string</code> had been a target of an assignment in which the source could possibly have been void, then it could no longer be guaranteed that <code>l_string</code> is not void. So, assuming that <code>my_detachable_string</code> is an attribute declared as type <code>detachable STRING</code>, the second application of <code>append</code> in this example would be invalid:
|
||||
|
||||
<code>
|
||||
local
|
||||
l_string: detachable STRING
|
||||
do
|
||||
if l_string /= Void then
|
||||
l_string.append ("abc") -- Valid
|
||||
l_string := my_detachable_string
|
||||
l_string.append ("xyz") -- Invalid: my_detachable_string might have been void
|
||||
...
|
||||
</code>
|
||||
|
||||
==Common CAPs==
|
||||
|
||||
We've already seen the simple test for void as a CAP:
|
||||
<code>
|
||||
local
|
||||
l_str: detachable STRING
|
||||
|
||||
...
|
||||
|
||||
if l_str /= Void then
|
||||
l_str.append ("xyz") -- Valid
|
||||
end
|
||||
</code>
|
||||
|
||||
Additionally, a creation instruction can serve as a CAP. After the execution of a creation instruction, the target of the creation instruction will be attached:
|
||||
<code>
|
||||
local
|
||||
l_str: detachable STRING
|
||||
do
|
||||
create l_str.make_empty
|
||||
l_str.append ("xyz") -- Valid
|
||||
...
|
||||
</code>
|
||||
|
||||
|
||||
==Less obvious cases==
|
||||
|
||||
There are some situations that constitute CAPs that we might not think of immediately.
|
||||
|
||||
For example, the case of the non-strict boolean operator <code>and then</code>:
|
||||
<code>
|
||||
if x /= Void and not x.is_empty then -- Invalid
|
||||
...
|
||||
|
||||
if x /= Void and then not x.is_empty then -- Valid
|
||||
...
|
||||
</code>
|
||||
Assuming that <code>x</code> is CAP-able, the first line of code is invalid because the expression <code>x.is_empty</code> could always be evaluated even in the case in which <code>x</code> is void.
|
||||
|
||||
In the second line of code, the non-strict boolean is used, guaranteeing that <code>x.is_empty</code> will not be evaluated in cases in which <code>x</code> is void. Therefore, <code>x.is_empty</code> falls within the scope of the void test on <code>x</code>.
|
||||
|
||||
In contracts, multiple assertion clauses are treated as if they were separated by <code>and then</code>. This allows preconditions like the one in the following example:
|
||||
<code>
|
||||
my_routine (l_str: detachable STRING)
|
||||
require
|
||||
l_str /= Void
|
||||
not l_str.is_empty -- Valid
|
||||
...
|
||||
</code>
|
||||
|
||||
Another not-so-obvious CAP is related to the use of the logical implication:
|
||||
<code>
|
||||
local
|
||||
l_str: detachable STRING
|
||||
do
|
||||
if l_str /= Void implies some_expression then
|
||||
...
|
||||
else
|
||||
l_str.append ("xyz") -- Valid
|
||||
end
|
||||
</code>
|
||||
|
||||
|
||||
==The bottom line on CAPs==
|
||||
|
||||
In summary, CAPs provide void-safe protection for certain types of detachable expressions.
|
||||
|
||||
Possibly the characteristic of CAPs which is most important to developers is whether or not a particular CAP is supported by the compiler. In other words, from the developers viewpoint, the only opinion that matters in the argument of whether a particular pattern constitutes a CAP is that of the compiler.
|
||||
|
||||
If the compiler can provide assurance that a certain code pattern guarantees void-safe protection, then the developer will have that pattern available as a CAP. Likewise, even if a pattern can be shown logically to be a CAP, but for some reason it is not supported by the compiler, then that pattern will not available as a CAP and the compiler will not allow its use.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
[[Property:modification_date|Tue, 09 Jul 2019 09:42:22 GMT]]
|
||||
[[Property:publication_date|Tue, 09 Jul 2019 09:42:22 GMT]]
|
||||
[[Property:title|Common myths and misconceptions about Eiffel]]
|
||||
[[Property:link_title|]]
|
||||
[[Property:weight|4]]
|
||||
[[Property:uuid|056c0ab0-8e44-571f-f126-0b1850980754]]
|
||||
Often, when we speak about Eiffel to prospective users, we hear them repeat misinformation about the method, the language, or the tools. Most of the time, the stories are familiar to us … and untrue. Here are a few of the myths that we hear most often, as recounted and debunked by the series entitled [http://eiffel.com/developers/presentations/ "Where Eiffel Fits"].
|
||||
|
||||
|
||||
==Eiffel is an "academic" language only: ''Whoa, wrong! Twice!''==
|
||||
|
||||
Recently, I was offered the opportunity to speak to a local technology group about Eiffel for Microsoft .Net. The leader of this group is part of a small commercially-oriented software development company. Concerning Eiffel, he said, “All I know about Eiffel is that it’s an academic language.”
|
||||
|
||||
We hear that one a lot … and it’s wrong … in two unrelated ways.
|
||||
|
||||
First, as you should know by now, Eiffel is a framework for software development. It has a full-lifecycle development method. The Eiffel method is supported by a notation we call the Eiffel programming language. The notation just happens to be designed such that when it contains sufficient detail, it can be compiled into a running software system. Additionally, the method and language are supported by a set of tools including an interactive development and compiler. So to refer to Eiffel only as a "language" is to do injustice to the complete framework of which the language is only one part.
|
||||
|
||||
Secondly, I’m not sure what “academic language” means exactly, but if it means only used in an academic setting, or not fit for practical work, then this could not be farther from the truth. It is true that Bertrand Meyer who developed the original Eiffel concepts has academic background and is well-respected in the academic community. It’s also true that many of those Eiffel ideas evolved from work that was done by other academic computer scientists and mathematicians. And it’s true that many colleges and universities use Eiffel to teach the best practices of software development.
|
||||
|
||||
But Eiffel is also used successfully in many commercial and government endeavors. If you have any doubts, pay a visit to [https://www.eiffel.com/company/customers/testimonials/ eiffel.com] and check out the success stories and customers testimonials.
|
||||
|
||||
|
||||
==Eiffel is not for doing "real" work: ''That's a joke, right?''==
|
||||
|
||||
Occasionally we’ve heard people say that Eiffel is only suitable for building “toy” systems.
|
||||
|
||||
This is similar to the "academic language" argument and is just as false.
|
||||
|
||||
In actuality, we see Eiffel being used often in situations in which other technologies fail. If anything it is the other commonly used technologies that tend to break down under stress.
|
||||
|
||||
We see Eiffel being used instead of other technologies for systems in which scalability and reliability are essential.
|
||||
|
||||
One of our customers is an organization that has developed a payroll system using Eiffel that every week pays over two hundred thousand employees in twenty thousand different institutions … the people in this organization would assure you that Eiffel is indeed industrial grade.
|
||||
|
||||
|
||||
==Not many people are using Eiffel: ''You wouldn't want to share an elevator with them all!''==
|
||||
|
||||
The answer to this one depends a bit upon your frame of reference. Some time ago Microsoft estimated that there were twenty million Visual Basic programmers world wide.
|
||||
|
||||
If this is true, then relatively speaking, we have to admit that Eiffel’s market share ''is'' considerably smaller than that of Visual Basic.
|
||||
|
||||
Despite that, it’s not correct to say that not many people use Eiffel. Eiffel licenses world wide number in the tens of thousands. If you use Eiffel, you are not alone. These license-holders have formed a lasting worldwide quorum. Many world-class organizations are committed now, and will continue to be committed to the Eiffel framework. There is support through your maintenance contract with Eiffel Software. Help and information are available online in the form of the [https://www.eiffel.com/company/customers/ Eiffel Software users’ list] and websites like [https://www.eiffel.org/ Eiffel.org].
|
||||
|
||||
Eiffel Software's dual licensing model gives developers the opportunity to learn Eiffel without a great initial financial commitment.
|
||||
|
||||
So, don’t worry about it, plenty of people use Eiffel … and those numbers are increasing constantly.
|
||||
|
||||
|
||||
==If we use Eiffel, we may not be able to find qualified programmers: ''Gimme a break.''==
|
||||
|
||||
Through the years some potential Eiffel users have expressed to us a concern that if they embrace Eiffel, that they may not be able to find a sufficient number of qualified developers.
|
||||
|
||||
This is of course incorrect.
|
||||
|
||||
First, almost all Eiffel people were proficient in some other technology before they became Eiffel people. It turns out that this really works to your advantage. You see, Eiffel people want to stay Eiffel people. So an Eiffel programmer on the job market will be searching for an Eiffel position first, and would probably rather have a root canal than to go back to working in his or her previous technology.
|
||||
|
||||
Additionally, it is important also to understand that Eiffel developers are easy to create. Because Eiffel is simple, clean, and elegant, it doesn’t take long to get people going with it. I teach a five-day course that contains fifteen programming exercises. Each time I’ve taught the course, almost every student has finished every exercise. Students leave with a good foundation for how to begin saving time and money for their organization by constructing quality software with Eiffel. These people can be fluent in Eiffel in as little as a couple of months. This can be contrasted with the other extreme ... a well-known Microsoft Windows expert told me a couple of years ago that he estimates it to take 5 to 7 years to become truly fluent in C++/COM programming on Windows. Programmers who are proficient in other technologies often experience Eiffel as a breath of fresh air.
|
||||
|
||||
|
||||
==Eiffel might not be around in five/eight/ten (choose one) years: ''Better recalibrate your crystal ball, Nostradamus!''==
|
||||
|
||||
I think the first time I heard this one, it was about 1989.
|
||||
|
||||
And of course, I’ve heard it many times in the years since.
|
||||
|
||||
And of course, it’s not true.
|
||||
|
||||
Eiffel is more complete and functionally superior in most ways to every other commercially viable software development technology … and there are enough people around who recognize this (that quorum of users I mentioned earlier) to ensure that Eiffel will be around for a long time to come.
|
||||
|
||||
It’s possible that twenty-five years from now, there will be a significantly better software engineering idea … but certainly, there hasn’t been anything that’s come close since Eiffel’s original design in 1985. In most areas, other technologies are playing “catch-up” to Eiffel.
|
||||
|
||||
Besides, Eiffel constantly implements refinements and new capabilities with minimal impact on existing software. [[Void-safe programming in Eiffel|Void-safe programming]] is an excellent example of this.
|
||||
|
||||
You can get a feel for this issue by watching [http://channel9.msdn.com/posts/Charles/Emmanuel-Stapf-Eiffel-and-Contract-Oriented-Programming/ this video on Microsoft Developers Network Channel9]. Here you'll see Emmanuel Stapf, an engineer at Eiffel Software, speak with Mads Torgersen, one of Microsoft's C# language designers. You'll hear how Eiffel stays fresh and continues to set a technological standard worthy of the aspirations of other technologies.
|
||||
|
||||
So, don’t worry about it. Eiffel will be here.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
[[Property:title|Two-Minute fact sheet]]
|
||||
[[Property:weight|0]]
|
||||
[[Property:uuid|f672bfb8-ddea-beb1-eaa6-e374a6a6bc92]]
|
||||
If you are both curious about Eiffel and in a hurry, take a couple of minutes to read these facts about Eiffel. If anything here seems too good to be true, please suspend your disbelief. Press on to the more detailed documentation for the rationale, and our success stories for the evidence behind these facts.
|
||||
|
||||
===Eiffel is the most comprehensive approach to the construction of successful object-oriented software.===
|
||||
|
||||
Software produced with Eiffel is typically:
|
||||
|
||||
*Cheaper -- You spend less on development, debugging, maintenance
|
||||
*Better -- You get the bugs before they get you
|
||||
*Shorter time-to-market -- You release quality products ahead of your competitors
|
||||
*Easier -- In every way: understanding, maintenance, reuse, and extension
|
||||
|
||||
===Systems developed using Eiffel can be made portable across major industry platforms.===
|
||||
|
||||
*Windows NT/2000/XP/Vista including CLS compliance on Microsoft .NET
|
||||
*Major Unix versions
|
||||
*Macintosh OS X
|
||||
*Linux
|
||||
*OpenVMS
|
||||
|
||||
===Eiffel is the only approach that covers analysis, design, implementation and maintenance in a single framework.===
|
||||
|
||||
Eiffel consists of:
|
||||
|
||||
====The Eiffel Method====
|
||||
|
||||
*Is Based on a small number of powerful ideas from computer science and software engineering
|
||||
**An example of these is Design by Contract
|
||||
***Defines a software system as a set of components interacting through precisely specified contracts
|
||||
***Contracts are active and enforceable throughout the life-cycle
|
||||
***Design by Contract promotes:
|
||||
****Precise software specification
|
||||
****Software reliability
|
||||
****Safe, effective software reuse
|
||||
*Uses a "single-product" model
|
||||
**All life-cycle phases are supported by a single notation
|
||||
***No need to switch, say, from "analysis language" to "design language"
|
||||
**Products of all phases are recorded in a single document with multiple views
|
||||
|
||||
====The Eiffel Programming Language====
|
||||
|
||||
*Exists to express the products of the Eiffel Method
|
||||
*Supports features not always available in competing technologies
|
||||
**Contracts and contract monitoring
|
||||
**Exception handling based on software specification (versus ad hoc try/catch)
|
||||
**Void-safety: calls on void (null) references are eliminated at compile time
|
||||
**Inheritance
|
||||
***Includes multiple and repeated inheritance
|
||||
***Safe and fully controllable
|
||||
**Genericity (generic classes), including constrained genericity
|
||||
**Platform independent concurrency ([[Concurrent programming with SCOOP|SCOOP]])
|
||||
*Widely recognized as simultaneously the simplest and most complete implementation of object-oriented concepts
|
||||
*Is clean, elegant, readable, easy to learn
|
||||
|
||||
|
||||
====EiffelStudio and the Eiffel Libraries====
|
||||
|
||||
*'''EiffelStudio'''
|
||||
**Runs on all major platforms (of course, it's built with Eiffel)
|
||||
**Features lightning-fast compilation (Melting Ice Technology)
|
||||
**Generates lightning-fast executables
|
||||
***Final compilation generates standard C (MSIL in the case of .NET)
|
||||
***Speed of executables rivals native C
|
||||
**Provides multiple views of your product
|
||||
***Views for different life-cycle phases and developer roles
|
||||
***Graphical views
|
||||
**Features automated generation of HTML and XML documentation
|
||||
|
||||
*'''The Eiffel Libraries'''
|
||||
**Contain rich, time-tested, multi-platform components
|
||||
**Include facilities for
|
||||
***GUI building and graphics
|
||||
***Web
|
||||
***Networking
|
||||
***Fundamental algorithms and data structures
|
||||
***Object persistence and database access
|
||||
***Multi-threading
|
||||
***Lexical analysis and parsing
|
||||
***Interfacing with other technologies
|
||||
|
||||
===Eiffel has a proven track record of successful projects===
|
||||
|
||||
*Some of the largest successful object-oriented projects ever built, including systems target to:
|
||||
**Finance and securities
|
||||
**Education
|
||||
**Trading
|
||||
**Manufacturing
|
||||
**Telecommunications
|
||||
**Government and national defense
|
||||
**Science
|
||||
|
||||
For a more detailed overview see [[Invitation to Eiffel (I2E)|An Invitation to Eiffel]] .
|
||||
|
||||
|
||||
|
||||
5
documentation/21.11/eiffel/Overview/index.wiki
Normal file
@@ -0,0 +1,5 @@
|
||||
[[Property:title|Eiffel Overview]]
|
||||
[[Property:link_title|Overview]]
|
||||
[[Property:weight|1]]
|
||||
[[Property:uuid|f65e67ed-0990-4638-b8f8-0fc85c28f0d8]]
|
||||
|
||||
59
documentation/21.11/eiffel/Overview/learning-eiffel.wiki
Normal file
@@ -0,0 +1,59 @@
|
||||
[[Property:modification_date|Thu, 19 Sep 2019 23:24:40 GMT]]
|
||||
[[Property:publication_date|Fri, 22 Mar 2019 14:53:52 GMT]]
|
||||
[[Property:title|Learning Eiffel]]
|
||||
[[Property:weight|3]]
|
||||
[[Property:uuid|a30e29fe-841d-4634-ded2-88ae1754e5fd]]
|
||||
If you are new to Eiffel and are interested in learning the technology, you might consider some of the following resources. Remember that Eiffel, unlike other programming languages, is not just a programming language. Instead, it is a full life-cycle framework for software development. As a consequence, learning Eiffel implies learning the Eiffel Method and the Eiffel programming Language. Additionally, the Eiffel development environment EiffelStudio is specifically designed to support the method and language. So having an understanding of the method and language helps you to appreciate the capabilities and behavior of EiffelStudio.
|
||||
|
||||
|
||||
=Online presentations=
|
||||
|
||||
Your first stop in getting acquainted with Eiffel might be the collection of [http://eiffel.com/developers/presentations/ online presentations] on the [http://eiffel.com eiffel.com] website. These presentations each usually take less than an hour to view, and give an introduction to Eiffel concepts including Design by Contract, the EiffelStudio development environment, and includes several presentations that describe selected Eiffel features in relation to those of other other development tools.
|
||||
|
||||
=Online documentation set=
|
||||
|
||||
The [http://eiffel.org/documentation|eiffel.org/documentation] section contains the online documentation for the Eiffel method, tools, and language. Within the documentation set are tutorials to help you learn about the Eiffel programming language and tools.
|
||||
|
||||
==The Eiffel Tutorial==
|
||||
|
||||
A [[An Eiffel Tutorial (ET)|tutorial]] that covers the Eiffel Method and much of the Eiffel programming language.
|
||||
|
||||
==The EiffelStudio Guided Tour==
|
||||
|
||||
This [[Introducing EiffelStudio]] page is good way to get a feel for what EiffelStudio can do.
|
||||
|
||||
=Academic materials available online=
|
||||
|
||||
Many colleges and universities use Eiffel to teach "best practices" in software engineering. Often the materials used in courses are available on the worldwide web. For example, the teaching materials for courses at the Swiss Federal Institute of Technology in Zurich are available at [http://se.inf.ethz.ch/courses/ this web address] (warning: old content).
|
||||
|
||||
If you search the web, you can find similar materials at other academic institutions.
|
||||
|
||||
<!--
|
||||
=Learning maps=
|
||||
|
||||
For certain specific areas of learning, the eiffel.com website includes conceptual [http://eiffel.com/developers/learning_maps/ learning maps]. These are graphical maps that link concepts with their relationships. Each concept can have multiple learning resources attached to it. One of the most prevalent types of resources is the "Learnlet", a short online presentation (less than 30 minutes) covering a specific concept.
|
||||
-->
|
||||
|
||||
=Books=
|
||||
|
||||
To find information about the most up-to-date books about Eiffel, look [[Books about the Eiffel Method and Language|here]].
|
||||
|
||||
=Examples and sample code=
|
||||
|
||||
Throughout the documentation site, there are many code snippets designed to illustrate certain language features or design principles. For example, the code snippet [[ET: Inheritance#Redefinition|here]] shows the mechanics of redefining an inherited feature.
|
||||
|
||||
In the EiffelStudio distribution you will find a subdirectory "<code>examples</code>" which contains many examples of using Eiffel, primarily with the Eiffel class libraries.
|
||||
|
||||
A third source of examples is the [[Examples]] book in the documentation pages.
|
||||
|
||||
=Eiffel Programming Language Syntax=
|
||||
|
||||
The documentation site includes a summary of the [[Quick reference to the Eiffel programming language|syntax of Eiffel]] the language. This summary is intended to reflect the state of the current official [[ECMA Standard 367|ISO/ECMA Eiffel standard document]].
|
||||
|
||||
However, usually you will find that there are differences in the syntax supported by EiffelStudio's compiler and that defined in the current standard. The differences between the standard and the EiffelStudio implementation are summarized in the [[EiffelStudio release notes]] and in a [[Differences between standard ECMA-367 and Eiffel Software implementation|documentation page]] that is specific to that purpose.
|
||||
|
||||
Another [[Differences_between_ETL_2nd_printing_and__Eiffel_Software__implementation|a documentation page]] summarizes changes to the pre-ECMA definition of Eiffel as described in [[Eiffel-_The_Language|ETL-2 "Eiffel: The Language"]].
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
[[Property:title|Your next project in Eiffel]]
|
||||
[[Property:weight|1]]
|
||||
[[Property:uuid|038CDA4A-9ACA-46F6-AC10-06942FAE4529]]
|
||||
(After an article in the special Eiffel issue of the ''Journal of Object-Oriented Programming'', May 1996.)
|
||||
|
||||
|
||||
Over its ten-year life Eiffel has evolved into one of the most usable software development environments available today. Other articles discuss its theoretical contributions. This one addresses a more mundane subject: how practical software projects can benefit, today, from the power of Eiffel. In so doing it will largely rely on published assessments from both Eiffel users and book authors. In fact a quotation from one of the best-known books in the object-oriented field -- ''Object-Oriented Modeling and Design'' by James Rumbaugh and his colleagues, the text that introduced the OMT O-O analysis method -- provides a good start:
|
||||
|
||||
<blockquote>
|
||||
''Eiffel is arguably the best commercial object-oriented language available today. [Jim Rumbaugh et al. in Object-Oriented Modeling and Design, Prentice Hall 1988]. ''
|
||||
</blockquote>
|
||||
|
||||
|
||||
==What is Eiffel?==
|
||||
|
||||
First we should define what the word "Eiffel" means. If you are thinking "a programming language" you are not wrong (and the preceding quotation shows that you are in good company). The programming language is indeed the most visible part, but it is only a reflection of something broader: a comprehensive approach to the production of quality software. As Richard Wiener wrote:
|
||||
|
||||
<blockquote>
|
||||
''Eiffel is more than a language; it is a framework for thinking about, designing and implementing object-oriented software. [Richard Wiener in Software Development using Eiffel: There is life other than C++, Prentice Hall, 1995.] ''
|
||||
</blockquote>
|
||||
|
||||
The Eiffel approach includes a method (a "methodology", as it is sometimes called) based on a number of pervasive ideas such as Design by Contract, seamlessness, reversibility, rigorous architectural rules, systematic use of single and multiple inheritance, static type checking and several others. Besides a method and a language Eiffel also means powerful graphical development environments, such as EiffelStudio, available across a wide number of industry-standard platforms and supporting analysis and design as well as implementation, maintenance and evolution.
|
||||
|
||||
The language itself, indeed (which Wiener calls an elegant and powerful language for object-oriented problem solving") is not just a programming language but extends to the phases of system construction that both precede and follow implementation. This is sometimes hard to accept if you have been raised in the view that software development must involve a sequence of separate steps; that one should initially use an analysis method and then at some point switch to a programming language, with perhaps a design method in-between. This view is detrimental to the software process and to the quality of the resulting product, as it does not support the inevitable back-and-forth hesitations that characterize real software development.
|
||||
|
||||
Wisdom sometimes blooms late in the season. However careful you may have been at the analysis stage, some great ideas will hit you - or your implementers - past the point at which you thought you had all the specifications right. Why renounce the benefit of such belated but valuable ideas? Eiffel and the associated Business Object Notation approach to analysis and design accommodate them naturally, by providing a single conceptual framework from the beginning to the end of the process.
|
||||
|
||||
Here Eiffel does not have much competition. The most bright-eyed Smalltalk or C++ enthusiast would not seriously claim that one can do design, let alone analysis, in his language of choice. And users of any of the popular O-O analysis notations know that at some stage they must stop working on their model and move on to the implementation in some programming language. Eiffel is unique in helping you for all of these tasks, without ever introducing the impedance mismatches that characterize other approaches.
|
||||
|
||||
As a reviewer wrote:
|
||||
|
||||
<blockquote>
|
||||
''As a design language, Eiffel continues to be a better model for object- oriented programming than Ada. It is even better than the new Ada 9X standard. [Richard Riehle in HP Professional, October 1994, A Tour of Eiffel.] ''
|
||||
</blockquote>
|
||||
|
||||
==The commercial and political context==
|
||||
|
||||
The next few sections give a glimpse of the technical contributions of Eiffel, or more precisely of what other people have written about them. But of course the best technology in the world requires infrastructure and support to succeed.
|
||||
|
||||
Eiffel has plenty of these. It has been around for more than a decade. Eiffel is available from several commercial and open-source providers. The number of licenses sold is in the tens of thousands. Reusable library classes are in the thousands.
|
||||
|
||||
The platforms covered range from Unix (all of Unix, the famous and the arcane) and Linux to OpenVMS, OS/2, Windows 3. 1, Windows NT, Windows 95/98.
|
||||
|
||||
Particularly impressive is the growth of Eiffel usage in education. Eiffel is quickly becoming the language of choice for teaching modern software technology, including, increasingly, introductory programming. A dozen of excellent textbooks are now available from Prentice Hall, Addison-Wesley, Macmillan and others, with about as many announced just for the coming months.
|
||||
|
||||
It is not just the professors who like the approach. Here is just one typical comment on student reaction, from an institution (Rochester Institute of Technology) having adopted Eiffel as its first-year introductory language on a massive scale:
|
||||
|
||||
<blockquote>
|
||||
''We were pleased to discover many of our more skeptical students turning around and admitting that Eiffel was a "fun" language in which to work. [Jim Heliotis in the Proceedings of OOPSLA 95, Experiences teaching objects: A new curriculum for computer science students.] ''
|
||||
</blockquote>
|
||||
|
||||
A Computer World article confirmed the need for Eiffel in training the high-powered software professionals of tomorrow. Quoting Amy Cody-Quinn from Management Recruiters International, the journalist writes
|
||||
|
||||
<blockquote>
|
||||
''There is a big problem with people who say they know C++ - but they don't really know how to do objects. If they have Eiffel on their resume, then we know they really have the proper understanding of what they are doing. [Leslie Goff in ComputerWorld, Object Edge, December 18, 1995.] ''
|
||||
</blockquote>
|
||||
|
||||
But it would be a mistake to think of Eiffel as an academic tool. A little-known fact is that some of the biggest object-oriented projects ever undertaken (at least the successful ones - other O-O languages have had their share of large-scale failures) are being done in Eiffel. The hot areas at the moment are banking and the financial industry (in particular some very large derivative trading and investment management systems), telecommunications, health care. These are all areas in which all that counts in the end is quality and time to market, so that projects need to select the best technology available. Quoting from an article by Philippe Stephan, the system architect of such a project (Rainbow, a major derivative trading system built with ISE Eiffel):
|
||||
|
||||
<blockquote>
|
||||
''We evaluated three major object-oriented languages for the project - Smalltalk, C++ and Eiffel - and chose Eiffel. [...] Rainbow currently comprises over 400,000 lines of code, for about 3000 classes. [Current figures are way over these mid-1995 counts. ] The developers feel very productive. This was confirmed when Rainbow's financial backers brought in object professionals to audit the project. The auditors evaluated the project during July 1994 and were impressed with the productivity of the Rainbow development group. [Philippe Stephan in Object Magazine, July-August 1995, Building financial software with object technology.] ''
|
||||
</blockquote>
|
||||
|
||||
The development group in question is remarkable for being made only for a third of software professionals. The others are professionals from other disciplines (such as trading and financial analysis), who, Stephan writes,
|
||||
|
||||
<blockquote>
|
||||
''can express business concepts in Eiffel because they can focus on design and implementation, rather than struggling with memory management problems and debugging. ''
|
||||
</blockquote>
|
||||
|
||||
The result has received lavish praise from such publications as ComputerWorld and analysts:
|
||||
|
||||
<blockquote>
|
||||
''Industry experts briefed on Rainbow said they were impressed with the results. CALFP is "progressive" in [...] committing the organization's mission-critical systems development efforts to this architecture, said Richard Crone, senior manager of financial services at KPMG Peat Marwick in Los Angeles. "What's unique here is that [CALFP is] delivering this system end-to-end using object-oriented technologies", said Henry Morris, a research analyst at International Data Corporation (IDC) in Framingham, Mass. [Thomas Hoffmann in ComputerWorld, May 8, 1995, Object- Oriented financial package tames transactions.]''
|
||||
</blockquote>
|
||||
|
||||
Along with these Eiffel mega-projects, you will also find myriad smaller endeavors. Many consultants, in particular, have found for themselves the key competitive advantage that they can gain from Eiffel's excellence. In ensuring this spread of Eiffel throughout the industry, the benefit of cheap yet complete environments such as EiffelStudio for Linux has been immeasurable.
|
||||
|
||||
Also crucial to the development of Eiffel has been the neutral status of its definition, now controlled by a consortium of vendors and users, NICE (the Nonprofit International Consortium for Eiffel). NICE has already produced a library standard and expects to produce soon the language standard that should shortly thereafter enjoy a smooth ride through ANSI and other international standards bodies.
|
||||
|
||||
The pace of Eiffel history has been accelerating in the past few months. This has been picked up by many journalists. As Dan Wilder wrote:
|
||||
|
||||
<blockquote>
|
||||
''With an open specification for both the language and the kernel libraries, and support from multiple vendors, Eiffel now stands poised to take off. [Dan Wilder in Linux Journal, June 1995, Introduction to Eiffel.] ''
|
||||
</blockquote>
|
||||
|
||||
|
||||
==The criteria==
|
||||
|
||||
Eiffel - the method, the language, the environment - is based on a small set of goals, addressing the crucial needs of software quality and productivity. Quoting from an article in ''Byte'' magazine:
|
||||
|
||||
<blockquote>
|
||||
''Developers who want an object-oriented language that adheres to the keystone principles of software engineering need look no further than Eiffel. [Peter Varhol in Byte Magazine, February 1996.] ''
|
||||
</blockquote>
|
||||
|
||||
or, as Steve Bilow wrote in a review of Eiffel Software's Melting Ice compiling technology (which he calls "an outstanding marriage between portability and development speed"):
|
||||
|
||||
<blockquote>
|
||||
''Eiffel was designed precisely for the purpose of enabling software developers to deliver high quality, reliable, efficient, reusable code. [Steve Bilow in The X Journal, The Eiffel alternative, July-August 1995.]''
|
||||
</blockquote>
|
||||
|
||||
==Reliability==
|
||||
|
||||
The first goal is reliability. No other approach available today has made the effort to give developers all the tools that they need to produce bug-free software - software that will run without bugs the first time around. Crucial in this effort is the presence of static typing ( ''real'' static typing, not "a little bit typed" as in those languages that still keep C-like type conversions); assertions and the whole mechanism of Design by Contract, on which more than one Eiffel developer has said "this has changed my life" by enabling him or her to specify precisely what the software should do, and to track at run time that it does it; disciplined exception handling; automatic garbage collection, which eliminates a source of horrendous bugs in C++-based environments (and a large part of the code, tedious and error-prone); a clean approach to inheritance; the use of dynamic binding as the default policy, meaning the guarantee that all calls will use the right version of each operation; and the simplicity of the language design, which enables Eiffel developers to know '''all''' of Eiffel and feel in control.
|
||||
|
||||
The role of assertions and Design by Contract is particularly important here. According to the ''Journal of Object-Oriented Programming'':
|
||||
|
||||
<blockquote>
|
||||
''The contribution of Eiffel is significant: it shows how invariants, preconditions, and postconditions can be incorporated into a practical developer's view of a class. Wider use of Eiffel [...] will encourage a greater use of simple but powerful mathematics during development. [Richard Mitchell et al. in Journal of Object-Oriented Programming, July-August 1995, As-a: a relationship to support code reuse.] ''
|
||||
</blockquote>
|
||||
|
||||
==Reusability==
|
||||
|
||||
The second goal is reusability. This has become a catchword, but Eiffel is the only approach that has taken this requirement and its consequences all the way to the end. Quoting Roland Racko:
|
||||
|
||||
<blockquote>
|
||||
''Everything about [Eiffel] is single-mindedly, unambiguously, gloriously focused on reusability - right down to the choice of reserved words and punctuation and right up to the compile time environment. [Roland Racko in Software Development, December 1994, In praise of Eiffel.] ''
|
||||
</blockquote>
|
||||
|
||||
Eiffel benefits here from being a simple ("but not simplistic", writes Racko) and consistent design, not a transposition from older, unrelated technology. Beyond the language and the environment facilities (such as precompilation), the crucial help to reusability is of course the presence of thousands of high-quality library ''classes'', such as, in EiffelBase (a "Linnaean approach to the reconstruction of software fundamentals"), EiffelNet for client-server communication, EiffelStore for relational and O-O database manipulations, EiffelLex and EiffelParse for lexical analysis and parsing, EiffelMath for object-oriented numerical computation, EiffelVision for portable graphics, WEL (the Windows Eiffel Library) for Windows-specific graphics, EiffelWeb to process forms from the Web, and many others. Not even mentioning quality, the result is probably the biggest repository of object-oriented components available elsewhere. The care that has been applied to the production of these libraries also has considerable pedagogical benefits: the way people learn Eiffel is by learning the libraries - first to use them, then to adapt them if necessary, then to write their own software.
|
||||
|
||||
Part of the single-mindedness mentioned by acko is the emphasis on abstraction. In contrast with, say, Smalltalk, you do not read the source code of a class when you want to use it. This may be fine for a couple dozen classes, but not for a large, powerful library. Eiffel introduces the notion of '''short form''': an abstract version of the class, keeping only the interface information including assertions. This is an ideal tool for documenting classes but also for discussing designs and presenting them to outsiders - managers or customers - who need to know what is going on without getting bogged down in the details.
|
||||
|
||||
Let me mention just one of the unique reusability-supporting features of Eiffel, without which it is, in my experience, impossible to have a long-term reuse effort. Racko again:
|
||||
|
||||
<blockquote>
|
||||
''The language's designer [...] recognized that no reusable library is ever perfect and, thus, that libraries are always in flux. So he built a kind of version-control system into the language. Specifically, there are language elements to demarcate obsolete code that is, however, still being supported. When these elements are referenced by someone unaware of such code's obsolescence, the compiler will issue a warning at compile time about the impending doom that awaits persons who continue the referencing. ''
|
||||
</blockquote>
|
||||
|
||||
It is this kind of detail that can make or break the success of reuse in a company.
|
||||
|
||||
==Extendibility==
|
||||
|
||||
Next comes extendibility. With Eiffel, modifying software is part of the normal process. As Philippe Stephan writes of the external audit of his project:
|
||||
|
||||
<blockquote>
|
||||
''The auditors rated the responsiveness of the development team as very high. ''
|
||||
</blockquote>
|
||||
|
||||
Chief among the method's support for extendibility is the careful design of the inheritance mechanism. Unlike Smalltalk, which is fatally limited by the absence of multiple inheritance, the Eiffel approach fundamentally relies on multiple inheritance to combine various abstractions into one. As Dan Wilder notes:
|
||||
|
||||
<blockquote>
|
||||
''Most object-oriented languages do not attempt multiple-inheritance. The literature is full of elaborate explanations why. This is sad. Eiffel demonstrates that multiple inheritance need not be difficult or complex, and it can also yield some quite practical results. ''
|
||||
</blockquote>
|
||||
|
||||
The approach also enforces a strict form of information hiding, which means that a module (a '''client''' in Eiffel Design by Contract terminology) that uses another's facilities (its '''supplier''') is protected against many of the changes that can be made later on to these facilities. This is essential in preserving the coherent evolution of a large system - and the sanity of its developers.
|
||||
|
||||
==Efficiency==
|
||||
|
||||
Performance is almost as much an obsession in Eiffel as reusability. The software field is still, and will remain for a long time, largely driven by performance considerations. (Do not believe anyone who says that speed does not matter. If we get faster computers, it is to do things faster and especially to do more things - not to use more CPU cycles to run the same old applications at the same old visible speed. )
|
||||
|
||||
There is no reason whatsoever to leave the mantle of efficiency to the proponents of machine-oriented languages such as C/C++, or to follow the path of Smalltalk which sacrifices performance to object orientation. With Eiffel you can have the best of both worlds. Thanks to a performance-obsessed language design and ten years of research and competition on compiling algorithms, the speed of Eiffel-generated code (in such modes as what is known as "finalization" in Eiffel Software's implementation) is as good as that of hand-produced C code, or better.
|
||||
|
||||
Software producers should stand up to their ideas. That is what we do at Eiffel Software: apart from the run-time engine (a few thousand lines of C), all of our software - thousands of classes, hundreds of thousands of lines - is written in Eiffel, and it runs fast. Typical of the situation is a recent incident with the EiffelLex library: it still had a few C elements, remnants of an earlier design. We rewrote them in Eiffel - for a 30% performance gain.
|
||||
|
||||
Why these gains? The answer is simple. The /C++ approach of doing everything by hand, under tight programmer control, works well for small programs. Similarly, a good secretary has no equivalent for keeping one person's records. But in the same way that no humans can match the performance of a computer for managing, say, the records of a bank or a city, no programmer can beat a sophisticated Eiffel compiler for optimizing a large program. Against the automatic application of inlining, static binding, memory management and other optimizations, the human does not stand a chance.
|
||||
|
||||
To have one's cake and eat it also means not to have to choose between run-time and compilation-time performance. For programmers used to the contrast between a Smalltalk-like style of rapid turnaround and the interminable edit-compile-link cycle of most compiled environment, the following comments by Dan Wilder (in a separate article) will be a shock:
|
||||
|
||||
<blockquote>
|
||||
''EiffelStudio uses "melting ice technology", which allows incremental changes to run in an interpreted mode. Only modified classes are recompiled. Changing one class and clicking the Melt button caused only a few seconds of compilation. [...] My test application took 20 seconds to compile from scratch in "melt" mode. [Dan Wilder in Linux Journal, September 1995, Two Eiffel implementations.] ''
|
||||
</blockquote>
|
||||
|
||||
Steve Bilow provides further explanations:
|
||||
|
||||
<blockquote>
|
||||
''Based on the observation that software development is an iterative process which is usually focused on constructing systems from code modifications, the folks at Eiffel Software have developed something that they call "Melting Ice Technology". Essentially, this means that when you make a [change] and you want to try it out, you simply "melt" it into the system. You don't need to regenerate a bunch of C code, so your changes are integrated into the system proportionally to the amount of code changed. Even in C and C++, `make` still has to relink. ''
|
||||
</blockquote>
|
||||
|
||||
What this also indicates in passing is the technology choice made by Eiffel Software's implementation and all current implementations: using C as the portable implementation vehicle. By going through C, the compilers gain efficiency and portability. This also makes Eiffel one of the most open environments around; in contrast to the self-centered view that predominates in Smalltalk, Eiffel software is born with a sociable attitude, ready to interface with all kinds of other software written in C or other languages. This, needless to say, is a key to the success of realistic applications.
|
||||
|
||||
==With us, everything is the face==
|
||||
|
||||
A good way to think about Eiffel - the seamlessness of it, the insistence on getting everything right, the conviction that software should be beautiful in and out, specification and implementation - is this little anecdote stolen from Roman Jakobson's Essays on ''General Linguistics'':
|
||||
|
||||
<blockquote>
|
||||
''In a far-away country, a missionary was scolding the natives. "You should not go around naked, showing your body like this!". One day a young girl spoke back, pointing at him: "But you, Father, you are also showing a part of your body!". "But of course", the missionary said in a dignified tone; "That is my face". The girl replied: "So you see, Father, it is really the same thing. Only, with us, everything is the face". ''
|
||||
</blockquote>
|
||||
|
||||
So it is with Eiffel too. Everything is the face.
|
||||
|
||||
Hundreds of thousands of people have now been exposed to Eiffel through books, through courses, through hearing about other people's successes, and most importantly (for the most fortunate among them) through using it to complete a project on time, within budget, and to the satisfaction of their customers. Shouldn't your next project use Eiffel too?
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
[[Property:modification_date|Wed, 18 Sep 2019 13:17:05 GMT]]
|
||||
[[Property:publication_date|Thu, 12 Sep 2019 15:07:05 GMT]]
|
||||
[[Property:uuid|BF3D5A25-A6C0-4645-956A-82807C41F073]]
|
||||
[[Property:weight|10]]
|
||||
[[Property:title|EiffelStudio: A Guided Tour - Eiffel Software Technical Report]]
|
||||
[[Property:link_title|EiffelStudio Guided Tour]]
|
||||
|
||||
==Eiffel Software Technical Report TR-EI-68/GT ==
|
||||
|
||||
First published 1993 as ''First Steps with EiffelBench'' (TR-EI-38/EB) and revised as a chapter of ''Eiffel: The Environment'' also available as [[#An_Object-Oriented_Environment|An Object-Oriented Environment]] (below).
|
||||
|
||||
Version 3.3.8, 1995.
|
||||
|
||||
Version 4.1, 1997
|
||||
|
||||
This version: July 2001. Corresponds to release 5.0 of the EiffelStudio environment.
|
||||
|
||||
Full reference at [[Manual_identification_and_copyright|Manual identification and copyright]]
|
||||
|
||||
==An Object-Oriented Environment ==
|
||||
|
||||
:<big>'''Bertrand Meyer'''</big>
|
||||
|
||||
:Prentice Hall, 1994
|
||||
|
||||
:ISBN 0-13-245-507-2
|
||||
|
||||
The principles of object technology change the way we envision, design and use software development environments.
|
||||
|
||||
This book explains what it means for an environment to be truly object-oriented, not just by having a modern user interface but by applying to its full extent the concept of data abstraction. It will provide precious material to anyone who is interested in finding out how an environment can support O-O development in its quest for software quality and productivity.
|
||||
|
||||
''Content highlights: ''
|
||||
|
||||
Introduces five design principles for object-oriented environments; presents a complete set of tools applying these principles, based on development object types rather than functional units; describes a novel approach to compilation: the Melting Ice Technology, which combines the fast development turnaround of interpreters with the safety of compiled approaches, and generates high-performance final code; discusses how to use C as a target language for efficiency and portable cross-development, without impairing the benefits of the O-O method; takes the reader through a detailed demonstration of the environment's object-oriented tools, showing their application to compiling, browsing and symbolic debugging; explains the principles and application of GUI (Graphical User Interface) Application Building, going from mere 'interface builders' to the interactive construction of entire applications - interface and semantics; and introduces the Context-Events-Command-State model of GUI application building and applies it to the interactive development of a complete mini-application.
|
||||
|
||||
==The Guided Tour==
|
||||
|
||||
{{Note|[[EiffelStudio_tutorials|The Guided Tour to EiffelStudio starts here]]}}
|
||||