mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-08 07:42:33 +01:00
Author:halw
Date:2008-10-17T21:31:06.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@88 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
@@ -406,37 +406,65 @@ For entities of reference types, the value of <code>x</code> will be a void refe
|
||||
|
||||
For entities of expanded types, the values are objects; the object attached to <code>x</code> will be overwritten with the contents of the object attached to <code>y</code>. In the case of atomic objects, as in <code>n := 3</code> with the declaration <code> n: INTEGER</code> , this has the expected effect of assigning to <code>n</code> the integer value <code>3</code>; in the case of composite objects, this overwrites the fields for <code>x</code>, one by one, with the corresponding <code>y</code> fields.
|
||||
|
||||
To copy an object, use <code>x.copy (y)</code> which assumes that both <code>x</code> and <code>y</code> are non-void, and copies the contents of <code>y</code>'s attached object onto those of <code>x</code>'s. For expanded entities the effect is the same as that the of the assignment <code>x := y</code>.
|
||||
To copy an object, use
|
||||
<code>
|
||||
x.copy (y)
|
||||
</code>
|
||||
which assumes that both <code>x</code> and <code>y</code> are non-void, and copies the contents of <code>y</code>'s attached object onto those of <code>x</code>'s. For expanded entities the effect is the same as that the of the assignment <code>x := y</code>.
|
||||
|
||||
An operation performing similar duty to the <code>copy</code> is <code>twin</code> . The assignment
|
||||
<code>
|
||||
x := y.twin
|
||||
</code>
|
||||
produces a newly created object (provided that <code>y</code> is non-void), initialized with a copy of the object attached to <code>y</code> and attaches the result to <code>x</code> . This means we may view <code> twin</code> as a function that performs the following two steps:
|
||||
produces a newly created object (provided that <code>y</code> is non-void), initialized with a copy of the object attached to <code>y</code> and attaches the result to <code>x</code> . This means we may view <code>twin</code> as a function that performs the following two steps:
|
||||
<code>
|
||||
create Result
|
||||
Result.copy (Current)
|
||||
</code>
|
||||
The new object is created, then its content is updated to match the content of <code>y</code> to which the <code>twin</code> call is targeted.
|
||||
|
||||
So, assuming both entities of reference types and <code>y</code> not void, the assignment above will attach <code>x</code> to a '''new object''' identical to <code>y</code>'s attached object, as opposed to the assignment <code> x := y </code> which attaches <code>x</code> to the '''same object''' as <code>y</code>.
|
||||
So, assuming both entities of reference types and <code>y</code> not void, the assignment above will attach <code>x</code> to a '''new object''' identical to <code>y</code>'s attached object, as opposed to the assignment <code>x := y</code> which attaches <code>x</code> to the '''same object''' as <code>y</code>.
|
||||
|
||||
|
||||
To determine whether two values are equal, use the expression <code> x = y </code>. For references, this comparison will yield true if the values are either both void or both attached to the same object; this is the case in the last figure in the state after the assignment, but not before. The symbol for not equal is <code> /= </code>, as in <code> x /= y </code>.
|
||||
To determine whether two values are equal, use the expression:
|
||||
|
||||
As with assignment, there is also a form that works on objects rather than references: <code>x.is_equal (y)</code> will return true when <code>x</code> and <code>y</code> are both non-void and attached to field-by-field identical objects. This can be true even when <code>x = y</code> is not, for example, in the figure, ''before'' the assignment, if the two objects shown are field-by-field equal.
|
||||
<code>
|
||||
x = y
|
||||
</code>
|
||||
For references, this comparison will yield true if the values are either both void or both attached to the same object; this is the case in the last figure in the state after the assignment, but not before. The symbol for not equal is <code> /= </code>, as in:
|
||||
<code>
|
||||
x /= y
|
||||
</code>
|
||||
|
||||
The expression <code>x.is_equal (y)</code> can also be expressed in a notation analogous to <code>x = y</code>. The expression <code>x ~ y</code> will be true only in cases in which <code>x.is_equal (y)</code> is true.
|
||||
As with assignment, there is also a form that works on objects rather than references:
|
||||
<code>
|
||||
x.is_equal (y)
|
||||
</code>
|
||||
will return true when <code>x</code> and <code>y</code> are both non-void and attached to field-by-field identical objects. This can be true even when <code>x = y</code> is not, for example, in the figure, ''before'' the assignment, if the two objects shown are field-by-field equal.
|
||||
|
||||
A more general variant of <code>is_equal</code> is used under the form <code>equal (x, y)</code> . This is always defined, even if <code>x</code> is void, returning true whenever <code>is_equal</code> would but also if <code>x</code> and <code>y</code> are both void. (In contrast, <code>x.is_equal (y)</code> is not defined for void <code>x</code> and would, if evaluated, yield an exception as explained in [[8 Design by Contract (tm), Assertions and Exceptions#Exception_handling|"Exception handling"]] below.)
|
||||
The expression <code>x.is_equal (y)</code> can be written alternatively in a notation similar in form to <code>x = y</code> . The expression:
|
||||
<code>
|
||||
x ~ y
|
||||
</code>
|
||||
will be true only in cases in which <code>x.is_equal (y)</code> is true.
|
||||
|
||||
<code>Void</code> denotes a void reference. So you can make <code>x</code> void through the assignment <code>x := Void</code>, and test whether it is void through:
|
||||
A more general variant of <code>is_equal</code> is used under the form:
|
||||
<code>
|
||||
equal (x, y)
|
||||
</code>
|
||||
This is always defined, even if <code>x</code> is void, returning true whenever <code>is_equal</code> would but also if <code>x</code> and <code>y</code> are both void. (In contrast, <code>x.is_equal (y)</code> is not defined for void <code>x</code> and would, if evaluated, yield an exception as explained in [[8 Design by Contract (tm), Assertions and Exceptions#Exception_handling|"Exception handling"]] below.)
|
||||
|
||||
<code>Void</code> denotes a void reference. So you can make <code>x</code> void through the assignment
|
||||
<code>
|
||||
x := Void
|
||||
</code>
|
||||
and test whether it is void through:
|
||||
<code>
|
||||
if x = Void then ...</code>
|
||||
|
||||
Where assignment, <code>:=</code> , and the equality operators, <code>=</code> and <code>/=</code> , were language constructions, <code>copy</code>, <code>twin</code>, <code>is_equal</code>, and <code>equal</code> are '''library features''' coming from class <code> ANY </code>.
|
||||
Note that the assignment, <code>:=</code> , and the equality operators, <code>=</code>, <code>~</code>, <code>/~</code>, and <code>/=</code> , are language constructions, whereas <code>copy</code>, <code>twin</code>, <code>is_equal</code>, and <code>equal</code> are '''library features''' coming from class <code>ANY</code> .
|
||||
|
||||
<code>Void</code> is a language keyword with built-in functionality, but it is not far out of bounds to think of <code>Void</code> as another feature declared in <code> ANY </code>, but with type of <code>NONE</code>, the "bottom" type.
|
||||
<code>Void</code> is a language keyword with built-in functionality, but it is not harmful to think of <code>Void</code> as another feature declared in <code> ANY </code>, but with type of <code>NONE</code>, the "bottom" type.
|
||||
|
||||
Using the redefinition mechanisms to be seen in the discussion of inheritance, a class can redefine <code>copy</code> and <code>is_equal</code> to cover specific notions of copy and equality. The assertions will ensure that the two remain compatible: after <code>x.copy (y)</code> , the property <code>x .is_equal (y)</code> must always be true. The effect of <code>twin</code> will automatically follow a redefinition of <code>copy</code>, and <code>equal</code> will follow <code>is_equal</code>.
|
||||
|
||||
@@ -558,7 +586,7 @@ Starting a system execution, as we have seen, consists in creating an instance o
|
||||
|
||||
From then on only two events can change the current object and current procedure: a qualified routine call; and the termination of a routine.
|
||||
|
||||
In a call of the form <code>target.routine (...)</code> , <code>target</code>denotes a certain object TC. (If not, that is to say, if the value of target is void, attempting to execute the call will trigger an exception, as studied below.) The generating class of TC must, as per the Feature Call rule, contain a routine of name <code>routine</code>. As the call starts, TC becomes the new current object and <code>routine</code> becomes the new current routine.
|
||||
In a call of the form <code>target.routine (...)</code> , <code>target</code> denotes a certain object TC. (If not, that is to say, if the value of target is void, attempting to execute the call will trigger an exception, as studied below.) The generating class of TC must, as per the Feature Call rule, contain a routine of name <code>routine</code>. As the call starts, TC becomes the new current object and <code>routine</code> becomes the new current routine.
|
||||
|
||||
When a routine execution terminates, the target object and routine of the most recent non-terminated call -- which, just before just before the terminated call, were the current object and the current routine -- assume again the role of current object and current routine.
|
||||
|
||||
|
||||
@@ -2,64 +2,66 @@
|
||||
[[Property:link_title|ET: Genericity and Arrays]]
|
||||
[[Property:weight|-9]]
|
||||
[[Property:uuid|7f3bd1d7-357e-031d-9faa-b00594aa9ae0]]
|
||||
Some of the classes that we will need, particularly in libraries, are '''container''' classes, describing data structures made of a number of objects of the same or similar types. Examples of containers include arrays, stacks and lists. The class <code> DEPOSIT_LIST </code> posited in earlier examples describes containers.
|
||||
Some of the classes that we will need, particularly in libraries, are '''container''' classes, describing data structures made of a number of objects of the same or similar types. Examples of containers include arrays, stacks and lists. The class <code>DEPOSIT_LIST</code> posited in earlier examples describes containers.
|
||||
|
||||
It is not hard, with the mechanisms seen so far, to write the class <code> DEPOSIT_LIST </code>, which would include such features as <code> count </code> (query returning the number of deposit objects in the list) and <code> put </code> (command to insert a new deposit object).
|
||||
It is not hard, with the mechanisms seen so far, to write the class <code>DEPOSIT_LIST</code>, which would include such features as <code>count</code> (query returning the number of deposit objects in the list) and <code>put</code> (command to insert a new deposit object).
|
||||
|
||||
Most of the operations, however, would be the same for lists of objects other than deposits. To avoid undue replication of efforts and promote reuse, we need a way to describe '''generic''' container classes, which we can use to describe containers containing elements of many different types.
|
||||
|
||||
==Making a class generic==
|
||||
|
||||
The notation
|
||||
<code>class C [G] ... The rest as for any other class declaration ...</code>
|
||||
|
||||
introduces a generic class. A name such as <code> G </code> appearing in brackets after the class name is known as a '''formal generic parameter'''; it represents an arbitrary type.
|
||||
|
||||
Within the class text, feature declarations can freely use <code> G </code> even though it is not known what type <code> G </code> stands for. Class <code> LIST </code> of EiffelBase, for example, includes features
|
||||
<code>
|
||||
first: G
|
||||
-- Value of first list item
|
||||
class C [G]
|
||||
... The rest as for any other class declaration ...</code>
|
||||
|
||||
extend (val: G) is
|
||||
-- Add a new item of value val at end of list
|
||||
...
|
||||
introduces a generic class. A name such as <code>G</code> appearing in brackets after the class name is known as a '''formal generic parameter'''; it represents an arbitrary type.
|
||||
|
||||
Within the class text, feature declarations can freely use <code>G</code> even though it is not known what type <code>G</code> stands for. Class <code>LIST</code> of EiffelBase, for example, includes features
|
||||
<code>
|
||||
first: G
|
||||
-- Value of first list item
|
||||
|
||||
extend (val: G) is
|
||||
-- Add a new item of value val at end of list
|
||||
...
|
||||
</code>
|
||||
|
||||
The operations available on an entity such as <code> first </code> and <code> val </code>, whose type is a formal generic parameter, are the operations available on all types: use as source <code> y </code> of an assignment <code> x := y </code>, use as target <code> x </code> of such an assignment (although not for <code> val </code>, which as a formal routine argument is not writable), use in equality comparisons <code> x = y </code> or <code> x /= y </code>, and application of universal features from <code> ANY </code> such as <code> clone </code>, <code> equal </code> and <code> copy </code>.
|
||||
The operations available on an entity such as <code>first</code> and <code>val</code>, whose type is a formal generic parameter, are the operations available on all types: use as source <code>y</code> of an assignment <code>x := y</code>, use as target <code>x</code> of such an assignment (although not for <code>val</code>, which as a formal routine argument is not writable), use in equality comparisons <code>x = y</code> or <code>x /= y</code>, and application of universal features from <code>ANY</code> such as <code>clone</code>, <code>equal</code> and <code>copy</code>.
|
||||
|
||||
To use a generic class such as list, a client will provide a type name as '''actual generic parameter'''. So instead of relying on a special purpose class <code> DEPOSIT_LIST </code>, the class <code> ACCOUNT </code> could include the declaration
|
||||
To use a generic class such as list, a client will provide a type name as '''actual generic parameter'''. So instead of relying on a special purpose class <code>DEPOSIT_LIST</code>, the class <code>ACCOUNT</code> could include the declaration
|
||||
<code>all_deposits: LIST [DEPOSIT]</code>
|
||||
|
||||
using <code> LIST </code> as a generic class and <code> DEPOSIT </code> as the actual generic parameter. Then all features declared in <code> LIST </code> as working on values of type <code> G </code> will work, when called on the target <code> all_deposits </code>, on values of type <code> DEPOSIT </code>. With the target
|
||||
using <code>LIST</code> as a generic class and <code>DEPOSIT</code> as the actual generic parameter. Then all features declared in <code>LIST</code> as working on values of type <code>G</code> will work, when called on the target <code>all_deposits</code>, on values of type <code>DEPOSIT</code>. With the target
|
||||
<code>all_accounts: LIST [ACCOUNT]</code>
|
||||
|
||||
these features would work on values of type <code> ACCOUNT </code>.
|
||||
these features would work on values of type <code>ACCOUNT</code>.
|
||||
|
||||
{{info|A note of terminology: to avoid confusion, Eiffel always uses the word '''argument''' for routine arguments, reserving '''parameter''' for the generic parameters of classes. }}
|
||||
|
||||
Genericity reconciles extendibility and reusability with the static type checking demanded by reliability. A typical error, such as confusing an account and a deposit, will be detected immediately at compile time, since the call <code> all_accounts </code>. <code> extend </code> <code> ( </code> <code> dep </code> <code> ) </code> is invalid for <code> dep </code> declared of type <code> DEPOSIT </code>. What is valid is something like <code> all_accounts </code>. <code> extend </code> <code> ( </code> <code> acc </code> <code> ) </code> for <code> acc </code> of type <code> ACCOUNT </code>. In other approaches, the same effect might require costly run-time checks (as in Java, C# or Smalltalk), with the risk of run-time errors.
|
||||
Genericity reconciles extendibility and reusability with the static type checking demanded by reliability. A typical error, such as confusing an account and a deposit, will be detected immediately at compile time, since the call <code>all_accounts</code>. <code>extend</code> <code>(</code> <code>dep</code> <code>)</code> is invalid for <code>dep</code> declared of type <code>DEPOSIT</code>. What is valid is something like <code>all_accounts</code>. <code>extend</code> <code>(</code> <code>acc</code> <code>)</code> for <code>acc</code> of type <code>ACCOUNT</code>. In other approaches, the same effect might require costly run-time checks (as in Java, C# or Smalltalk), with the risk of run-time errors.
|
||||
|
||||
{{info|This form of genericity is known as '''unconstrained''' because the formal generic parameter, <code> G </code> in the example, represents an arbitrary type. You may also want to use types that are guaranteed to have certain operations available. This is known as '''constrained''' genericity and will be studied with inheritance. }}
|
||||
{{info|This form of genericity is known as '''unconstrained''' because the formal generic parameter, <code>G</code> in the example, represents an arbitrary type. You may also want to use types that are guaranteed to have certain operations available. This is known as '''constrained''' genericity and will be studied with inheritance. }}
|
||||
|
||||
==Arrays==
|
||||
|
||||
An example of generic class from the Kernel Library is <code> ARRAY </code> <code> [ </code> <code> G </code> <code> ] </code>, which describes direct-access arrays. Features include:
|
||||
* <code> put </code> to replace an element's value, as in <code> my_array </code>. <code> put </code> <code> ( </code> <code> val </code>, <code> 25 </code> <code> ) </code> which replaces by <code> val </code> the value of the array entry at index 25.
|
||||
* <code> item </code> to access an entry, as in <code> my_array </code>. <code> item </code> <code> ( </code> <code> 25 </code> <code> ) </code> yielding the entry at index 25. A synonym is <code> infix </code> <code> "@" </code>, so that you may also write more tersely, for the same result, <code> my_array </code> <code> @ </code> <code> 25 </code>.
|
||||
* <code> lower </code>, <code> upper </code> and <code> count </code>: queries yielding the bounds and the number of entries.
|
||||
* The creation procedure <code> make </code>, as in <code> create </code> <code> my_array </code>. <code> make </code> <code> ( 1, 50 ) </code> which creates an array with the given index bounds. It is also possible to resize an array through <code> resize </code>, retaining the old elements. In general, the Eiffel method abhors built-in limits, favoring instead structures that resize themselves when needed, either from explicit client request or automatically.
|
||||
An example of generic class from the Kernel Library is <code>ARRAY</code> <code>[</code> <code>G</code> <code>]</code>, which describes direct-access arrays. Features include:
|
||||
* <code>put</code> to replace an element's value, as in <code>my_array</code>. <code>put</code> <code>(</code> <code>val</code>, <code>25</code> <code>)</code> which replaces by <code>val</code> the value of the array entry at index 25.
|
||||
* <code>item</code> to access an entry, as in <code>my_array</code>. <code>item</code> <code>(</code> <code>25</code> <code>)</code> yielding the entry at index 25. A synonym is <code>infix</code> <code>"@"</code>, so that you may also write more tersely, for the same result, <code>my_array</code> <code>@</code> <code>25</code>.
|
||||
* <code>lower</code>, <code>upper</code> and <code>count</code>: queries yielding the bounds and the number of entries.
|
||||
* The creation procedure <code>make</code>, as in <code>create</code> <code>my_array</code>. <code>make</code> <code>( 1, 50 )</code> which creates an array with the given index bounds. It is also possible to resize an array through <code>resize</code>, retaining the old elements. In general, the Eiffel method abhors built-in limits, favoring instead structures that resize themselves when needed, either from explicit client request or automatically.
|
||||
|
||||
The comment made about <code> INTEGER </code> and other basic classes applies to <code> ARRAY </code> too: Eiffel compilers know about this class, and will be able to process expressions of the form <code> my_array </code>. <code> put </code> <code> ( </code> <code> val </code>, <code> 25 </code> <code> ) </code> and <code> my_array </code> <code> @ </code> <code> 25 </code> in essentially the same way as a C or Fortran array access -- <code> my_array </code> <code> [ </code> <code> 25 </code> <code> ] </code> in C. But it is consistent and practical to let developers treat <code> ARRAY </code> as a class and arrays as objects; many library classes in EiffelBase, for example, inherit from <code> ARRAY </code>. Once again the idea is to get the best of both worlds: the convenience and uniformity of the object-oriented way of thinking; and the efficiency of traditional approaches.
|
||||
The comment made about <code>INTEGER</code> and other basic classes applies to <code>ARRAY</code> too: Eiffel compilers know about this class, and will be able to process expressions of the form <code>my_array</code>. <code>put</code> <code>(</code> <code>val</code>, <code>25</code> <code>)</code> and <code>my_array</code> <code>@</code> <code>25</code> in essentially the same way as a C or Fortran array access -- <code>my_array</code> <code>[</code> <code>25</code> <code>]</code> in C. But it is consistent and practical to let developers treat <code>ARRAY</code> as a class and arrays as objects; many library classes in EiffelBase, for example, inherit from <code>ARRAY</code>. Once again the idea is to get the best of both worlds: the convenience and uniformity of the object-oriented way of thinking; and the efficiency of traditional approaches.
|
||||
|
||||
A similar technique applies to another Kernel Library class, that one not generic: <code> STRING </code>, describing character strings with a rich set of string manipulation features.
|
||||
A similar technique applies to another Kernel Library class, that one not generic: <code>STRING</code>, describing character strings with a rich set of string manipulation features.
|
||||
|
||||
==Generic derivation==
|
||||
|
||||
The introduction of genericity brings up a small difference between classes and types. A generic class <code> C </code> is not directly a type since you cannot declare an entity as being of type <code> C </code>: you must use some actual generic parameter <code> T </code> -- itself a type. <code> C </code> <code> [ </code> <code> T </code> <code> ] </code> is indeed a type, but class <code> C </code> by itself is only a type template.
|
||||
The introduction of genericity brings up a small difference between classes and types. A generic class <code>C</code> is not directly a type since you cannot declare an entity as being of type <code>C</code>: you must use some actual generic parameter <code>T</code> -- itself a type. <code>C</code> <code>[</code> <code>T</code> <code>]</code> is indeed a type, but class <code>C</code> by itself is only a type template.
|
||||
|
||||
The process of obtaining a type <code> C </code> <code> [ </code> <code> T </code> <code> ] </code> from a general class <code> C </code> is known as a '''generic derivation'''; <code> C </code> <code> [ </code> <code> T </code> <code> ] </code> is a '''generically derived type'''. Type <code> T </code> itself is, recursively, either a non-generic class or again a generically derived type <code> D </code> <code> [ </code> <code> U </code> <code> ] </code> for some <code> D </code> and <code> U </code>, as in <code> LIST </code> <code> [ </code> <code> ARRAY </code> <code> [ </code> <code> INTEGER </code> <code> ]] </code>.)
|
||||
The process of obtaining a type <code>C</code> <code>[</code> <code>T</code> <code>]</code> from a general class <code>C</code> is known as a '''generic derivation'''; <code>C</code> <code>[</code> <code>T</code> <code>]</code> is a '''generically derived type'''. Type <code>T</code> itself is, recursively, either a non-generic class or again a generically derived type <code>D</code> <code>[</code> <code>U</code> <code>]</code> for some <code>D</code> and <code>U</code>, as in <code>LIST</code> <code>[</code> <code>ARRAY</code> <code>[</code> <code>INTEGER</code> <code>]]</code>.)
|
||||
|
||||
It remains true, however, that every type is based on a class. The base class of a generically derived type <code> C </code> <code> [ </code> <code> T </code> <code> ] </code> is <code> C </code>.
|
||||
It remains true, however, that every type is based on a class. The base class of a generically derived type <code>C</code> <code>[</code> <code>T</code> <code>]</code> is <code>C</code>.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[[Property:uuid|5b286f94-dd63-1169-a64e-74b5f8c5ef14]]
|
||||
When discovering any approach to software construction, however ambitious its goals, it is reassuring to see first a small example of the big picture -- a complete program to print the famous "Hello World" string. Here is how to perform this fascinating task in the Eiffel notation.
|
||||
|
||||
You write a class <code> HELLO </code> with a single procedure, say <code> make </code>, also serving as creation procedure. If you like short texts, here is a minimal version:
|
||||
You write a class <code>HELLO</code> with a single procedure, say <code>make</code>, also serving as creation procedure. If you like short texts, here is a minimal version:
|
||||
<code>
|
||||
class
|
||||
HELLO
|
||||
@@ -50,31 +50,31 @@ The two versions perform identically; the following comments will cover the more
|
||||
|
||||
Note the absence of semicolons and other syntactic clatter or clutter. You may in fact use semicolons to separate instructions and declarations. But the language's syntax is designed to make the semicolon optional (regardless of text layout) and it's best for readability to omit it, except in the special case of successive elements on a single line.
|
||||
|
||||
The <code> indexing </code> clause does not affect execution semantics; you may use it to associate documentation with the class, so that browsers and other indexing and retrieval tools can help users in search of reusable components satisfying certain properties. Here we see two indexing entries, labeled <code> description </code> and <code> author </code>.
|
||||
The <code>indexing</code> clause does not affect execution semantics; you may use it to associate documentation with the class, so that browsers and other indexing and retrieval tools can help users in search of reusable components satisfying certain properties. Here we see two indexing entries, labeled <code>description</code> and <code>author</code>.
|
||||
|
||||
The name of the class is <code> HELLO </code>. Any class may contain "features"; <code> HELLO </code>has just one, called <code> make </code>. The <code> create </code> clause indicates that <code> make </code> is a "creation procedure", that is to say an operation to be executed at class instantiation time. The class could have any number of creation procedures.
|
||||
The name of the class is <code>HELLO</code>. Any class may contain "features"; <code>HELLO </code>has just one, called <code>make</code>. The <code>create</code> clause indicates that <code>make</code> is a "creation procedure", that is to say an operation to be executed at class instantiation time. The class could have any number of creation procedures.
|
||||
|
||||
The definition of <code> make </code> appears in a <code> feature </code> clause. There may be any number of such clauses (to separate features into logical categories), and each may contain any number of feature declarations. Here we have only one.
|
||||
The definition of <code>make</code> appears in a <code>feature</code> clause. There may be any number of such clauses (to separate features into logical categories), and each may contain any number of feature declarations. Here we have only one.
|
||||
|
||||
The line starting with <code> -- </code> (two hyphen signs) is a comment; more precisely it is a "header comment", which style rules invite software developers to write for every such feature, just after the point at which the feature is named. As will be seen in [[8 Design by Contract (tm), Assertions and Exceptions#The_contract_form_of_a_class|"The contract form of a class"]], the tools of EiffelStudio know about this convention and use it to include the header comment in the automatically generated class documentation.
|
||||
The line starting with <code>--</code> (two hyphen signs) is a comment; more precisely it is a "header comment", which style rules invite software developers to write for every such feature, just after the point at which the feature is named. As will be seen in [[8 Design by Contract (tm), Assertions and Exceptions#The_contract_form_of_a_class|"The contract form of a class"]], the tools of EiffelStudio know about this convention and use it to include the header comment in the automatically generated class documentation.
|
||||
|
||||
The body of the feature is introduced by the <code> do </code> keyword and terminated by <code> end </code>. It consists of two output instructions. They both use <code> io </code>, a generally available reference to an object that provides access to standard input and output mechanisms; the notation<code> io.f</code>, for some feature<code> f</code> of the corresponding library class ( <code> STD_FILES </code>, in this case), means "apply<code> f</code> to<code> io</code>". Here we use two such features:
|
||||
* <code> put_string </code> outputs a string, passed as argument, here <code> "Hello World" </code>.
|
||||
* <code> put_new_line </code> terminates the line.
|
||||
The body of the feature is introduced by the <code>do</code> keyword and terminated by <code>end</code>. It consists of two output instructions. They both use <code>io</code>, a generally available reference to an object that provides access to standard input and output mechanisms; the notation <code>io.f</code>, for some feature <code>f</code> of the corresponding library class (<code>STD_FILES</code>, in this case), means "apply <code>f</code> to <code>io</code>". Here we use two such features:
|
||||
* <code>put_string</code> outputs a string, passed as argument, here <code>"Hello World"</code>.
|
||||
* <code>put_new_line</code> terminates the line.
|
||||
|
||||
Rather than using a call to <code> put_new_line </code>, the first version of the class simply includes a new-line character, denoted as<code> %N </code>, at the end of the string. Either technique is acceptable.
|
||||
Rather than using a call to <code>put_new_line</code>, the first version of the class simply includes a new-line character, denoted as <code>%N</code> , at the end of the string. Either technique is acceptable.
|
||||
|
||||
You may have noticed another difference between the two versions. The first version uses a call to <code>print</code> where the second uses <code>io.put_string</code> . Here too, the effect is identical and either technique is acceptable. In the next section, you will begin to see how things like <code>io</code> and <code>print</code> become available for use in a class like <code>HELLO</code>.
|
||||
|
||||
To build the system and execute it:
|
||||
* Start EiffelStudio
|
||||
* Create a new ''Basic application'' project
|
||||
* Specify <code> HELLO </code> as the "root class" and <code> make </code> as the "root procedure".
|
||||
* You can either use EiffelStudio to type in the above class text, or you may use any text editor and store the result into a file <code> hello.e </code> in the current directory.
|
||||
* Specify <code>HELLO</code> as the "root class" and <code>make</code> as the "root procedure".
|
||||
* You can either use EiffelStudio to type in the above class text, or you may use any text editor and store the result into a file <code>hello.e</code> in the current directory.
|
||||
* Click the "Compile" icon.
|
||||
* Click the "Run" icon.
|
||||
|
||||
Execution starts and outputs <code> Hello World </code> on the appropriate medium: under Windows, a Console; under Unix or OpenVMS, the windows from which you started EiffelStudio.
|
||||
Execution starts and outputs <code>Hello World</code> on the appropriate medium: under Windows, a Console; under Unix or OpenVMS, the windows from which you started EiffelStudio.
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ Complementing the preceding principles is the idea that, in the cluster lifecycl
|
||||
|
||||
The preceding goals benefit from the ability to check frequently that the current iteration is correct and robust. Eiffel supports efficient compilation mechanisms through such mechanisms as the '''Melting Ice Technology''' in EiffelStudio. The Melting Ice achieves immediate recompilation after a change, guaranteeing a recompilation time that's a function of the size of the changes, not of the system's overall size. Even for a system of several thousand classes and several hundred thousand lines, the time to get restarted after a change to a few classes is, on a typical modern computer, a few seconds.
|
||||
|
||||
Such a "melt" (recompilation) will immediately catch (along with any syntax errors) the type errors -- often the symptoms of conceptual errors that, if left undetected, could cause grave damage later in the process or even during operation. Once the type errors have been corrected, the developers should start testing the new functionalities, relying on the power of '''assertions''' -- explained in [[8 Design by Contract (tm), Assertions and Exceptions|"Design By Contract™ Assertions, Exceptions", page 38 ]] -- to kill the bugs while they are still larvae. Such extensive unit and system testing, constantly interleaved with development, plays an important part in making sure that the "current demo" is trustworthy and will eventually yield a correct and robust product.
|
||||
Such a "melt" (recompilation) will immediately catch (along with any syntax errors) the type errors -- often the symptoms of conceptual errors that, if left undetected, could cause grave damage later in the process or even during operation. Once the type errors have been corrected, the developers should start testing the new functionalities, relying on the power of '''assertions''' -- explained in [[8 Design by Contract (tm), Assertions and Exceptions|"Design By Contract™ Assertions, Exceptions"]] -- to kill the bugs while they are still larvae. Such extensive unit and system testing, constantly interleaved with development, plays an important part in making sure that the "current demo" is trustworthy and will eventually yield a correct and robust product.
|
||||
|
||||
==Quality and functionality==
|
||||
|
||||
|
||||
@@ -12,42 +12,42 @@ An Eiffel system is a collection of classes, one of which is designated as the r
|
||||
|
||||
To execute such a system is to create an instance of the root class (an object created according to the class description) and to execute the root procedure. In anything more significant than "Hello World" systems, this will create new objects and apply features to them, in turn triggering further creations and feature calls.
|
||||
|
||||
For the system to make sense, it must contains all the classes on which the root '''depends''' directly or indirectly. A class <code> B </code> depends on a class <code> A </code> if it is either a '''client''' of <code> A </code>, that is to say uses objects of type <code> A </code>, or an '''heir''' of <code> A </code>, that is to say extends or specializes <code> A </code>. (These two relations, client and inheritance, are covered below.)
|
||||
For the system to make sense, it must contains all the classes on which the root '''depends''' directly or indirectly. A class <code>B</code> depends on a class <code>A</code> if it is either a '''client''' of <code>A</code>, that is to say uses objects of type <code>A</code>, or an '''heir''' of <code>A</code>, that is to say extends or specializes <code>A</code>. (These two relations, client and inheritance, are covered below.)
|
||||
|
||||
==Classes==
|
||||
|
||||
The notion of class is central to the Eiffel approach. A class is the description of a type of run-time data structures (objects), characterized by common operations features) and properties. Examples of classes include:
|
||||
* In a banking system, a class <code> ACCOUNT </code> may have features such as <code> deposit </code>, adding a certain amount to an account, <code> all_deposits </code>, yielding the list of deposits since the account's opening, and <code> balance </code>, yielding the current balance, with properties stating that <code> deposit </code> must add an element to the <code> all_deposits </code> list and update <code> balance </code> by adding the sum deposited, and that the current value of <code> balance </code> must be consistent with the lists of deposits and withdrawals.
|
||||
* A class <code> COMMAND </code> in an interactive system of any kind may have features such as <code> execute </code> and <code> undo </code> , as well as a feature <code> undoable </code> which indicates whether a command can be undone, with the property that <code> undo </code> is only applicable if <code> undoable </code> yields the value true.
|
||||
* A class <code> LINKED_LIST </code> may have features such as <code> put </code>, which adds an element to a list, and <code> count </code>, yielding the number of elements in the list, with properties stating that <code> put </code> increases <code> count </code> by one and that <code> count </code> is always non-negative.
|
||||
* In a banking system, a class <code>ACCOUNT</code> may have features such as <code>deposit</code>, adding a certain amount to an account, <code>all_deposits</code>, yielding the list of deposits since the account's opening, and <code>balance</code>, yielding the current balance, with properties stating that <code>deposit</code> must add an element to the <code>all_deposits</code> list and update <code>balance</code> by adding the sum deposited, and that the current value of <code>balance</code> must be consistent with the lists of deposits and withdrawals.
|
||||
* A class <code>COMMAND</code> in an interactive system of any kind may have features such as <code>execute</code> and <code>undo</code> , as well as a feature <code>undoable</code> which indicates whether a command can be undone, with the property that <code>undo</code> is only applicable if <code>undoable</code> yields the value true.
|
||||
* A class <code>LINKED_LIST</code> may have features such as <code>put</code>, which adds an element to a list, and <code>count</code>, yielding the number of elements in the list, with properties stating that <code>put</code> increases <code>count</code> by one and that <code>count</code> is always non-negative.
|
||||
|
||||
We may characterize the first of these examples as an analysis class, directly modeling objects from the application domain; the second one as a design class, describing a high-level solution; and the third as an implementation class, reused whenever possible from a library such as EiffelBase. In Eiffel, however, there is no strict distinction between these categories; it is part of the approaches seamlessness that the same notion of class, and the associated concepts, may be used at all levels of the software development process.
|
||||
|
||||
==Class relations==
|
||||
|
||||
Two relations may exist between classes:
|
||||
* You can define a class <code> C </code> as a '''client''' of a class <code> A </code> to enable the features of <code> C </code> to rely on objects of type <code> A </code>.
|
||||
* You may define a class <code> B </code> as an '''heir''' of a class <code> A </code> to provide <code> B </code> with all the features and properties of <code> A </code>, letting <code> B </code> add its own features and properties and modify some of the inherited features if appropriate.
|
||||
* You can define a class <code>C</code> as a '''client''' of a class <code>A</code> to enable the features of <code>C</code> to rely on objects of type <code>A</code>.
|
||||
* You may define a class <code>B</code> as an '''heir''' of a class <code>A</code> to provide <code>B</code> with all the features and properties of <code>A</code>, letting <code>B</code> add its own features and properties and modify some of the inherited features if appropriate.
|
||||
|
||||
If <code> C </code> is a client of <code> A </code>, <code> A </code> is a '''supplier''' of <code> C </code>. If <code> B </code> is an heir of <code> A </code>, <code> A </code> is a '''parent''' of <code> B </code>. A '''descendant''' of <code> A </code> is either <code> A </code> itself or, recursively, a descendant of an heir of <code> A </code>; in more informal terms a descendant is a direct or indirect heir, or the class itself. To exclude <code> A </code> itself we talk of '''proper descendant'''. In the reverse direction the terms are '''ancestor''' and '''proper ancestor'''.
|
||||
If <code>C</code> is a client of <code>A</code>, <code>A</code> is a '''supplier''' of <code>C</code>. If <code>B</code> is an heir of <code>A</code>, <code>A</code> is a '''parent''' of <code>B</code>. A '''descendant''' of <code>A</code> is either <code>A</code> itself or, recursively, a descendant of an heir of <code>A</code>; in more informal terms a descendant is a direct or indirect heir, or the class itself. To exclude <code>A</code> itself we talk of '''proper descendant'''. In the reverse direction the terms are '''ancestor''' and '''proper ancestor'''.
|
||||
|
||||
The client relation can be cyclic; an example involving a cycle would be classes <code> PERSON </code> and <code> HOUSE </code>, modeling the corresponding informal everyday "object" types and expressing the properties that every person has a home and every home has an architect. The inheritance (heir) relation may not include any cycle.
|
||||
The client relation can be cyclic; an example involving a cycle would be classes <code>PERSON</code> and <code>HOUSE</code>, modeling the corresponding informal everyday "object" types and expressing the properties that every person has a home and every home has an architect. The inheritance (heir) relation may not include any cycle.
|
||||
|
||||
In modeling terms, client roughly represents the relation "has" and heir roughly represents "is". For example we may use Eiffel classes to model a certain system and express that every child <code> has </code> a birth date (client relation) and is a person (inheritance).
|
||||
In modeling terms, client roughly represents the relation "has" and heir roughly represents "is". For example we may use Eiffel classes to model a certain system and express that every child <code>has</code> a birth date (client relation) and is a person (inheritance).
|
||||
|
||||
Distinctive of Eiffel is the rule that lasses can only be connected through these two relations. This excludes the behind-the-scenes dependencies often found in other approaches, such as the use of global variables, which jeopardize the modularity of a system. Only through a strict policy of limited and explicit inter-class relations can we achieve the goals of reusability and extendibility.
|
||||
|
||||
==The global inheritance structure==
|
||||
|
||||
An Eiffel class that you write does not come into a vacuum but fits in a preordained structure, shown in the figure and involving two library classes: <code> ANY </code> and <code> NONE </code>.
|
||||
An Eiffel class that you write does not come into a vacuum but fits in a preordained structure, shown in the figure and involving two library classes: <code>ANY</code> and <code>NONE</code>.
|
||||
|
||||
|
||||
[[Image:tutorial-4]]
|
||||
|
||||
|
||||
Any class that does not explicitly inherit from another is considered to inherit from <code> ANY </code>, so that every class is a descendant, direct or indirect, of <code> ANY </code>. <code> ANY </code> introduces a number of general-purpose features useful everywhere, such as copying, cloning and equality testing operations (page [[6 The Dynamic Structure: Execution Model|28]] ) and default input-output. The procedure <code> print </code> used in the first version of our "Hello World" (page [[4 Hello World|11]] ) comes from <code> ANY </code>.
|
||||
Any class that does not explicitly inherit from another is considered to inherit from <code>ANY</code>, so that every class is a descendant, direct or indirect, of <code>ANY</code>. <code>ANY</code> introduces a number of general-purpose features useful everywhere, such as copying, cloning and equality testing operations (page [[6 The Dynamic Structure: Execution Model|28]] ) and default input-output. The procedure <code>print</code> used in the first version of our "Hello World" (page [[4 Hello World|11]] ) comes from <code>ANY</code>.
|
||||
|
||||
<code> NONE </code> inherits from any class that has no explicit heir. Since inheritance has no cycles, <code> NONE </code> cannot have proper descendants. This makes it useful, as we will see, to specify non-exported features, and to denote the type of void values. Unlike <code> ANY </code>, class <code> NONE </code> doesn't have an actual class text; instead, it's a convenient fiction.
|
||||
<code>NONE</code> inherits from any class that has no explicit heir. Since inheritance has no cycles, <code>NONE</code> cannot have proper descendants. This makes it useful, as we will see, to specify non-exported features, and to denote the type of void values. Unlike <code>ANY</code>, class <code>NONE</code> doesn't have an actual class text; instead, it's a convenient fiction.
|
||||
|
||||
==Clusters==
|
||||
|
||||
@@ -66,7 +66,7 @@ file_status (filedesc: INTEGER): INTEGER
|
||||
end
|
||||
</code>
|
||||
|
||||
to indicate that it is actually an encapsulation of a C function whose original name is <code> fstat _ </code>. The <code> alias </code> clause is optional, but here it is needed because the C name, starting with an underscore, is not valid as an Eiffel identifier.
|
||||
to indicate that it is actually an encapsulation of a C function whose original name is <code>fstat _</code>. The <code>alias</code> clause is optional, but here it is needed because the C name, starting with an underscore, is not valid as an Eiffel identifier.
|
||||
|
||||
Similar syntax exists to interface with C++ classes. EiffelStudio includes a tool called Legacy++ which will automatically produce, from a C++ class, an Eiffel class that encapsulates its facilities, making them available to the rest of the Eiffel software as bona fide Eiffel features.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user