Created Documentation branch for 25.02

git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@2485 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
eifops
2025-02-06 19:48:22 +00:00
parent de6e7aad63
commit 1a0353ee6c
2963 changed files with 63839 additions and 0 deletions

View File

@@ -0,0 +1,535 @@
[[Property:title|Adding Class Features]]
[[Property:weight|2]]
[[Property:uuid|04261c22-b28f-b045-a5d7-2c85efe992b9]]
The features of a class make it useful. They are the things that objects which are instances of the class have and can do.
It is during the process of adding class features that we relate a class we are producing to other classes via the client/supplier relationship.
It is when we add features to a class that we can build the executable code that makes things happen.
==Categorizing Features==
In Eiffel, we have several ways of thinking abstractly about features and categorizing them. As you saw in [[Eiffel Classes|Eiffel Classes]] the <code>feature</code> clause gives us a way to group features in the software text. We have ways to group features more generally, too. Here are some.
===Source===
You remember the example class from [[Eiffel Classes|Eiffel Classes]] :
<code>
note
description: Objects that model lists
revision: $Revision: 1.5 $
class
OLD_FASHIONED_LIST [G]
obsolete "This class is obsolete, use LINKED_LIST [G] instead"
inherit
DYNAMIC_LIST [G]
create
make
feature -- Initialization
make
-- Create an empty list.
do
before := True
ensure
is_before: before
end
feature -- Access
item: G
-- Current item
do
Result := active.item
end
first: like item
-- Item at first position
do
Result := first_element.item
end
... other features omitted ...
invariant
before_constraint: before implies (active = first_element)
after_constraint: after implies (active = last_element)
end
</code>
The example shows three of the features ( <code>make</code>, <code>item</code>, and <code>first</code>) coded directly in the class. These features (and the ones omitted from the example in the interest of brevity) may not be the only features of the class <code>OLD_FASHIONED_LIST</code>. In fact we can just about guarantee that there are other features of this class. Remember the inheritance part of the class:
<code>
inherit
DYNAMIC_LIST [G]
</code>
This means that every feature in <code>DYNAMIC_LIST</code> will be a feature of <code>OLD_FASHIONED_LIST</code>. So one way we can think of features is by their source.
* Immediate features are those that are introduced by a class itself.
* Inherited features are those that come to the class from its proper ancestors.
We will see more about this in [[Inheritance|Inheritance]] .
===Implementation Type===
Whenever we are building a class in Eiffel, we are potential reuse producers. As such, we can categorize the features of a class based on the three types of feature implementation:
* Attribute
* Function
* Procedure
Attributes are those features which occupy storage in an instance. When you code an attribute in a class that you are producing, that class becomes a client to the class of the attribute. This is the most common way to establish a client/supplier relationship between the classses. Client/supplier is one of the two relationships that can exist between classes.
Functions and procedures are the computation features, that is they are features that involve executable code. Functions and procedures together are themselves categorized as routines.
Also, from the producer standpoint we may view features as whether they work from memory or through computation:
* Memory
** Attribute
* Computation
** Function
** Procedure
This view can be valuable when a producer is considering performance issues. For example, if there is some class function called <code>count</code>, a producer might investigate whether it is better to leave <code>count</code> as a function, computing it each time the feature is applied, or to change it to an attribute and compute it less often.
===Usage===
A times we find it appropriate to categorize features by how we use them. Specifically, as:
* Query
** Attribute
** Function
* Command
** Procedure
Queries are features that, when applied to an instance, provide a value in response. Commands instruct an intance to take some action, but do not return a value. Seeing features as either queries or commands is of primary interest to reuse consumers. But as producers there are important reasons for ensuring that when we implement a feature, we implement it as a query or as a command, but not both. We will see more about this in [[Design by Contract and Assertions|Design by Contract and Assertions]] .
==General Syntax of Features==
===More Sample Features===
Here is another example class. Again this class contrived, so it does not do anyhing worthwhile except show you what different types of features look like. This class has an attribute and a constant attribute, and functions and procedures both with and without arguments.
<code>
class
SOME_CLASS
create
make,
make_with_arguments
feature -- Initialization
make
-- Creation procedure
do
an_attribute := 5
end
make_with_arguments (hour: INTEGER; minute: INTEGER; second: INTEGER)
-- Another creation procedure
do
an_attribute := second + (minute * 60) + (hour * 3600)
end
feature -- Access
an_attribute: INTEGER
-- An attribute of type INTEGER
another_attribute: INTEGER = 46
-- A constant attribute
a_function: STRING is
-- A function without arguments
do
Result := an_attribute.out
end
another_function (an_int: INTEGER): INTEGER
-- A function with arguments
do
Result := an_attribute + an_int
end
feature -- Basic Operations
a_procedure
-- A procedure with no arguments
do
an_attribute := an_attribute + 5
end
another_procedure (an_int: INTEGER; another_int: INTEGER)
-- A procedure with arguments
do
an_attribute := an_attribute + an_int + another_int
end
end -- Class SOME_CLASS
</code>
===Feature Declaration===
When you write a feature in a class, you typically will include some of the following:
* The feature's name
{{note|In Eiffel every feature of a class must have a name that is unique within that class. }}
* The feature's type (in the case of an attribute or a function)
* The feature's formal argument list (in the case of a function or procedure that has arguments)
* The actual value of the feature (in the case of a constant attribute)
* The implementation code (in the case of a function or procedure)
Let's dissect one feature and identify its parts:
<code>
another_function (an_int: INTEGER): INTEGER
-- A function with arguments
do
Result := an_attribute + an_int
end
</code>
In this feature:
* "another_function" is the feature's name.
* "(an_int: INTEGER)" is the argument list.
** "an_int" is the name of the first argument
** "INTEGER" is the type "an_int"
* "INTEGER" (after the argument list) is the feature's type.
* "do " introduces the implementation code.
* "Result := an_attribute + an_int" is an instruction.
{{note|This feature is a function. As a consequence the computation uses the keyword "<eiffel>Result</eiffel>' as an entity name for the value to be returned by the function }}
* "<eiffel>end</eiffel>" ends the feature declaration
==General Structure of Routines==
As you can imagine, the possibilities for coding routines are more complex than those for coding attributes. Routines always contain the keyword "is" after the first part of the feature declaration. The part after the "is" is called the routine part.
The routine part is made up of the following sections:
* [[#Header Comment|Header Comment]]
* [[#obsolete|Obsolete]]
* [[#Precondition|Precondition]]
* [[#Local Declarations|Local Declarations]]
* [[#Routine Body|Routine Body]]
* [[#Postcondition|Postcondition]]
* [[#Rescue|Rescue]]
All of the sections except the Routine Body are optional.
Here is another feature, a routine, which has all of these except obsolete and rescue.
<code>
insert_text_header_item (a_label: STRING;
a_width, a_format: INTEGER; insert_after_item_no: INTEGER)
-- Insert a text item to the header control
-- after the `insert_item_item_no' item.
require
exists: exists
label_not_void: a_label /= Void
insert_after_item_no_positive: insert_after_item_no >= 0
local
hd_item: WEL_HD_ITEM
do
create hd_item.make
hd_item.set_text (a_label)
hd_item.set_width (a_width)
hd_item.set_format (a_format)
insert_header_item (hd_item, insert_after_item_no)
ensure
item_count_increased: item_count = old item_count + 1
end
</code>
Using this example, let's identify and discuss the different sections.
===Header Comment===
<code>
-- Insert a text item to the header control
-- after the `insert_item_item_no' item.
</code>
Although the feature's header comment is optional, most Eiffel programmers and their technical managers feel that it should never be omitted. Header comments are included by some language processing tools in specialized views of classes. Header comments are almost always short, usually no more than a few lines. Header comments serve to provide a natural language description of what the feature will do (in the case of features that are commands) or what information it provides (in the case of queries).
===Obsolete===
The feature <code>insert_text_header_item</code> is not obsolete ... but if it were it would include an <code>obsolete</code> clause. This works much like the obsolete part for classes that we saw in [[Eiffel Classes|Eiffel Classes]] : the keyword "<code>obsolete</code>" followed by a manifest string which bears a message to potential reuse consumers:
===Precondition===
<code>
require
exists: exists
label_not_void: a_label /= Void
insert_after_item_no_positive: insert_after_item_no >= 0
</code>
The precondition part of a feature is introduced by the keyword "<code>require</code>". It contains a set of assertions which define the state necessary for the correct execution of a routine. We will see more about assertions in [[Design by Contract and Assertions|Design by Contract and Assertions]] .
===Local Declarations===
<code>
local
hd_item: WEL_HD_ITEM
</code>
This part contains the declarations for any "local entities" used by the feature. Sometimes the computation accomplished in a feature requires the use of entities which are only temporary. It would not be appropriate to make these attributes of the class. So, instead we can use local entities, which have scope only within the feature in which they are declared. In the example, <code>hd_item</code> is available as type <code>WEL_HD_ITEM</code> during the computation of feature <code>insert_text_header_item</code>.
{{note|A local entity name must not be the same as any feature of the class in which its feature occurs or the same as any argument name of the feature in which it occurs. }}
===Routine Body===
<code>
do
create hd_item.make
hd_item.set_text (a_label)
hd_item.set_width (a_width)
hd_item.set_format (a_format)
insert_header_item (hd_item, insert_after_item_no)
</code>
This is the routine body for a fairly typical effective, internal routine. It contains the instructions that get the job done for the feature. You may notice that experienced Eiffel programmers rarely write routine bodies that are more than a few lines long. The reason for this is more that just intuitive. This phenomenon will be explained in the section [[Design by Contract and Assertions|Design by Contract and Assertions]] .
There are other forms that a routine body can take. Here are some examples of some others:
====External Routines====
<code>
cwin_tooltips_class: POINTER
external
"C [macro ] : EIF_POINTER"
alias
"TOOLTIPS_CLASS"
end
</code>
The routine body above is for an "external" routine. External routines are used to represent within Eiffel classes, routines that are written in other languages.
{{tip|Because of the high degree of language interaction provided by Microsoft.NET, it is not necessary in Eiffel for.NET to use externals to use software components from.NET assemblies. Instead, these components are presented to the Eiffel programmer as if they were Eiffel classes. Read more about this in [[Conventions|Conventions]] . }}
====Once Routines====
<code>
once
Result := some_computation
</code>
This is the routine body of a "once" routine, specifically a "once function". A once routine is introduced by the keyword "<code>once</code>" rather than <code>do</code>. It contains an computational body that executes only the first time it is called. Upon subsequent calls it has no effect.
Once procedures are useful for doing things that for some reason should not be done multiple times.
If the once routine is a function (as the example above), it computes the resulting object on the first call, then on subsequent calls, it returns the object it originally created without executing the computation. Once functions facilitate shared objects which helps us in avoiding global entities. A class containing a once function can be inherited by many other classes. The first object to apply the once function causes the resulting object to be created and initialized. Subsequent applications by any other object accesses the originally created instance.
====Deferred Routines====
<code>
deferred
</code>
The body for a deferred routine is simply the keyword "<code>deferred</code>". Below is the deferred routine body in the context of an entire feature.
<code>
set_position (new_position: INTEGER)
-- Set `position' with `new_position'
require
exists: exists
valid_minimum: new_position >= minimum
valid_maximum: new_position <= maximum
deferred
ensure
position_set: position = new_position
end
</code>
As we learned in [[Eiffel Classes|Eiffel Classes]] a deferred routine has specification, but no implementation. We will investigate deferred classes and features further in [[Inheritance|Inheritance]] .
===Postcondition===
<code>
ensure
item_count_increased: item_count = old item_count + 1
</code>
The postcondition part of a routine is introduced by the keyword "<code>ensure</code>". The postcondition is a group of assertions which describe the state that must be satisfied upon the successful completion of the routine. We will see more about assertions in [[Design by Contract and Assertions|Design by Contract and Assertions]] .
===Rescue===
Our example feature does not have an explicitly coded rescue part. The rescue, introduced by the keyword "<code>rescue</code>", provides a routine with a chance to do additional processing in the case that it incurs an exeption during normal processing. We will learn about the rescue clause in the section [[Exception Mechanism|Exception Mechanism]] . Until then, you can see what a rescue part looks like in the feature below.
<code>
bind
-- Bind socket to local address in `address'.
require
socket_exists: exists
valid_local_address: address /= Void
local
ext: ANY
retried: BOOLEAN
do
if not retried then
ext := address.socket_address
c_bind (descriptor, $ext, address.count)
is_open_read := True
end
rescue
if not assertion_violation then
is_open_read := False
retried := True
retry
end
end
</code>
==Making Features Available to Clients==
Remember that when we build classes in Eiffel, we keep in mind the possibility that these classes may eventually become valued, reusable software components. As a result we have a responsibility to make sure that our classes allow clients to use them in a safe and productive fashion. We make available those features that it is appropriate for clients to use, and we hide the rest. In Eiffel we say that a feature that is available to clients is "exported".
Control of the export of features inherited from ancestors is done by using the "export" keyword. Export of inherited features will be discussed in Inheritance.
Control of the export of immediate features (those features introduced in the text of a class) is done with the "feature" clause. We have encountered the feature clause already:
<code>
feature -- Access
an_attribute: INTEGER
-- An attribute of type INTEGER
another_attribute: INTEGER = 46
-- A constant attribute
a_function: STRING
-- A function without arguments
do
Result := an_attribute.out
end
another_function (an_int: INTEGER): INTEGER
-- A function with arguments
do
Result := an_attribute + an_int
end
feature -- Basic Operations
a_procedure
-- A procedure with no arguments
do
an_attribute := an_attribute + 5
end
another_procedure (an_int: INTEGER; another_int: INTEGER)
-- A procedure with arguments
do
an_attribute := an_attribute + an_int + another_int
end
</code>
A feature clause like the ones in the example above means that all the features that follow, until the next feature clause are exported to clients based on any class. Technically, this
<code>
feature -- Basic Operations
</code>
is equivalent to
<code>
feature {ANY} -- Basic Operations
</code>
which means that the following features are available to clients which conform to class <code>ANY</code>. And in Eiffel, <code>ANY</code> is the class from which all other classes inherit. As a consequence all classes conform to <code>ANY</code>.
Inside the braces is a list of classes which are eligible as clients.
<code>
feature {STRING_HANDLER} -- Implementation
</code>
Features following this example from class <code>STRING</code> will be available to client class <code>STRING_HANDLER</code> and all its proper descendants.
As stated above, you can put a list of class names in the braces:
<code>
feature {CLASS_A, CLASS_B, CLASS_C} -- Semi-private features
</code>
Often features which are solely for implementation should not be seen or used by clients of any type. You can ensure this by exporting to class <code>NONE</code>, the class from which no other class can inherit:
<code>
feature {NONE} -- Implementation
</code>
==Eiffel Instructions and Control Structures==
When you begin to write routines in Eiffel, you will need to understand how to write instructions. Fortunately, the set of instruction types you can code is fairly small. Here we will look the most common of these. You will see some more in other topics.
===Creation===
<code>
create hd_item.make
</code>
We discussed creation procedures and the process of bringing new objects into being in [[Eiffel Classes|Eiffel Classes]] . A creation instruction starts with the keyword "<code>create</code>". It creates a new object, initialize its fields, may apply a creation procedure, and attaches the object to an entity.
===Procedure Call===
<code>
hd_item.set_text (a_label)
</code>
The application of a feature to an object constitutes an instruction if the feature is a procedure.
===Assignment===
In Eiffel, assignment syntax is simple. But depending upon the types involved, what actually happens may need some explanation. Assume here that <code>is_open_read</code> is an attribute declared as type <code>BOOLEAN</code>:
<code>
is_open_read := False
</code>
In this instruction, an attribute of type <code>BOOLEAN</code> named <code>is_open_read</code> is being assigned the value of the manifest boolean "<code>False</code>". The attribute <code>is_open_read</code> is based on an expanded class <code>BOOLEAN</code>, so that means that the value for <code>False</code> is held in the field for <code>is_open_read</code>. This is in contrast to what happens with reference types.
<code>
my_string := some_other_string
</code>
In this assignment, we will assume that both entities are type <code>STRING</code>. Because <code>STRING</code> is a reference type, the field for <code>my_string</code> will hold either a reference to an instance of <code>STRING</code>, or it will be <code>Void</code>. When the assignment above executes, then whatever was in the field for <code>my_string</code> is replaced with a reference to the same object that <code>some_other_string</code> refers to.
In summary, for objects based on expanded classes, assignment means assignment of value. For objects based on reference classes, assignment means assignment of reference.
====Conformance====
There is an important rule about assignment in Eiffel. The rule exists to ensure type safety. Consider the following assignment which we would read as "<code>x</code> receives <code>y</code>" or "<code>x</code> gets <code>y</code>".
<code>
x := y
</code>
then the rule says that this assignment is valid only if the type of <code>y</code> conforms to the type of <code>x</code>.
The rule is clear enough ... if you know what "conform" means. In the presence of mechanisms like expanded types, inheritance, and genericity, a precise definition of conformance is lengthy.
But we can get by for a while with much less. For now let us be satisfied with this:
Consider the classes in the declarations for <code>x</code> and <code>y</code>.
You might be tempted to say that to achieve "conformance", the classes would have to be the same. And for the case in which the declarations for <code>x</code> and <code>y</code> are expanded classes, you'd be correct. They conform only if they are the same class.
But for reference types, that constraint is unnecessarily restrictive. So, for reference types, the class of <code>y</code> conforms to that <code>x</code> if it is the same class or a proper descendant of that class. This facilitates a powerful idea known as polymorphic attachment that we will see more closely in the section on [[Inheritance|Inheritance]] .
===Conditional===
<code>
if l_c.is_digit then
l_state := 2
elseif l_c = '-' or l_c = '+' then
l_state := 1
else
l_state := 3
end
</code>
Conditionals in Eiffel use at a minimum the keywords "<code>if</code>", "<code>then</code>", and "<code>end</code>". Optionally, they may use the keywords "<code>elseif</code>" and "<code>else</code>".
===Loop===
<code>
from
i := lower
until
i > upper
loop
if item (i) /= Void and then v.is_equal (item (i)) then
Result := Result + 1
end
i := i + 1
end
</code>
There is only one structure for loops in Eiffel. In its typical form it uses the four keywords "<code>from</code>", "<code>until</code>", "<code>loop</code>", and "<code>end</code>". The instructions following the <code>from</code> keyword do any initialization necessary for the loop. After <code>until</code> is a boolean expression which is the exit condition. The loop body after <code>loop</code> is a list of instructions that are executed for every iteration. As you can imagine, something in the loop body should most likely cause the exit condition eventually to become true.

View File

@@ -0,0 +1,322 @@
[[Property:title|Design by Contract and Assertions]]
[[Property:weight|5]]
[[Property:uuid|41172f82-227a-96b1-2dad-624f04374ee0]]
==Motivation: Concerning Correctness==
When you produce an element of software, how do you know that what you produced is correct?
This is a difficult question for anyone to answer. Informally speaking, correct software is software that does what it is supposed to do. That is what makes answering the question so tricky. Before you can have any idea whether the software is correct, you must be able to express what it is supposed to do ... and that proves to be quite difficult itself.
In conventional software engineering, a document called a software specification is written in order to describe what it is that a piece of software is supposed to do. Writers of software specifications tend to pursue one of two approaches: the informal or the formal.
Informal specifications attempt to describe software behavior in the natural languages with which humans communicate on a daily basis. There are problems with this approach. Natural language is not precise. Informal specifications are subject to interpretation and affected by the ambiguities, noise, and contradiction inherent in natural language.
In order to avoid these problems, proponents of formal methods of specification turn to the most precise language they know: mathematics. It may be no exaggeration that the study of formal methods has produced more PhD's in Computer Science than it has well-specified software systems. Still the idea that the precision of mathematics can be brought to bear on the problem of specifying software is quite appealing. But, problems lurk here as well. Formal specifications are difficult and time-consuming to construct and verify against themselves, and most software engineers do not have a working knowledge of the mathematics required to work with formal specifications.
There is one more significant problem with both of these approaches. Even if you have a very precise specification, expressed in elegant text and graphics, and placed carefully in an expensive ring binder, how do you know that the software product actually reflects that specification and vice versa? If either is changed, the other must be as well. This is the document synchronization problem.
===Design by Contract to the Rescue===
Design by Contract (DbC) begins as an implementation of some of the ideas from formal methods and matures into a powerful way of thinking about software. And it does it in a way that is easy for programmers and managers to understand. DbC also puts the software specification into the software document itself which makes it checkable at runtime and eliminates the document synchronization problem.
==Model for Software Correctness==
Design by Contract is built around a model for software correctness that is really pretty simple.
Suppose there is software routine called <code>s</code>. If we were going to test <code>s</code>, we would probably devise some test inputs or test values to be in place when <code>s</code> starts and then observe what things look like after <code>s</code> completes. If they look the way we think they should then that leads us to believe that S is working correctly for those test inputs.
We can generalize and formalize that process a bit, taking it back from testing an into design. If indeed we know what it means for <code>s</code> to be correct, then we should be able to make a statement of any conditions that must be true prior to executing <code>s</code>. That is, we will state the conditions required for it to be possible for <code>s</code> to run correctly. We call this statement of preconditions for success <code>s</code>'s precondition.
Likewise we should be able to make a statement of the conditions that will be true always if <code>s</code> works correctly. This we call <code>s</code>'s postcondition.
As an example, suppose <code>s</code> accepted an argument of type <code>REAL</code> and returned another <code>REAL</code> which was the square root of the argument. The precondition for <code>s</code> would be that the argument could not be less that zero, as there is no real square root for negative numbers. <code>s</code>'s postcondition would be that the result multiplied by itself would yield the value of the original argument (give or take a little to allow for floating point error).
==Assertions in Eiffel==
Each Eiffel feature which is a routine, i.e. a function or procedure, can support one assertion for a precondition and one for a postcondition. We saw where precondition and postcondition fit into the structure of the routine in [[Adding Class Features|Adding Class Features]] . An assertion is expressed as one or more assertion clauses which are logically <code>and</code>-ed together to produce the assertion. Assertions clauses are boolean expressions that evaluate to true or false.
Let's look at another example. Assume you need to produce a class to model a time of day. Each instance of <code>TIME_OF_DAY</code> would hold some particular time of day accurate to the second between 00:00:00 and 23:59:59 inclusive.
As a producer, you would be faced with a decision concerning how to maintain the time internally in each instance. For the purpose of our example, let us consider two alternatives:
# Keep three instance of <code>INTEGER</code>. One each for hour, minute, and second.
# Keep one instance of <code>INTEGER</code> representing the time of day as the number of seconds since 00:00:00.
This would be an implementation issue for the producer, because it would not affect the services that <code>TIME_OF_DAY</code> could offer clients. If we have a query called <code>minute</code> the first alternative allows us simply to provide the value from storage. Whereas the second alternative will likely cause us to compute <code>minute</code> each time it is requested. But the service looks and works the same for the client in either alternative.
For now let us assume that we are using the first design alternative. In that case we would code class features for <code>hour</code>, <code>minute</code>, and <code>second</code>.
<code>
feature -- Access
hour: INTEGER
-- Hour expressed as 24-hour value
minute: INTEGER
-- Minutes past the hour
second: INTEGER
-- Seconds past the minute
</code>
Below is the code for a procedure <code>set_second</code> which receives an argument of type <code>INTEGER</code> and sets the value of the <code>second</code> feature to the argurment.
<code>
set_second (s: INTEGER)
-- Set the second from `s'.
do
second := s
end
</code>
The routine is simple enough, but there is a problem with it. Suppose a client calls <code>set_second</code> with an argument whose value is invalid, say 3574. Our routine would just stuff this value into <code>second</code> and we would end up with an instance of <code>TIME_OF_DAY</code> which is invalid. In the days before Design by Contract, as soon as we recognized that this problem exists, we would go into "defensive programming" mode and code some "<code>if</code>" statements inside the routine to validate the argument, before acting.
Consider though what we can do with Design by Contract. We will add a precondition assertion to <code>set_second</code> that expresses the need for valid arguments.
<code>
set_second (s: INTEGER)
-- Set the second from `s'.
require
valid_argument_for_second: 0 <= s and s <= 59
do
second := s
end
</code>
The precondition is introduced by the keyword "<code>require</code>". The text "<code>valid_argument_for_second</code>" is the label for the assertion clause. The boolean expression "<code>0 <= s and s <= 59</code>" says that a good value for <code>s</code> will be between 0 and 59 inclusive.
Remember that the precondition specifies those things that must be true if <code>set_second</code> has a chance of working correctly. As such, upon execution, the body of this routine will never be executed if an attempt is made to call it in a state that does not meet its precondition. Instead, the caller will incur a precondition violation exception. We will investigate more about what exceptions mean further in [[Exception Mechanism|Exception Mechanism]] .
So, what about a postcondition? We noted earlier that a postcondition should make a statement of what will be true in the case that the routine does its work correctly. For <code>set_second</code> this means that after it finishes, the query <code>second</code> should have the same value as the argument that was received from the caller. Below is the feature with the postcondition added.
<code>
set_second (s: INTEGER)
-- Set the second from `s'.
require
valid_argument_for_second: 0 <= s and s <= 59
do
second := s
ensure
second_set: second = s
end
</code>
The postcondition is introduced by the keyword "<code>ensure</code>". Here the expression "<code>second = s</code>" makes certain that the routine did actually do the necessary work to ensure that the value of <code>second</code> matches the value of the argument received.
As you look at the postcondition, you may be tempted to think that the one-line body of the routine is so simple as to make the postconditon unnecessary. To answer this concern we need to look again for a moment at software specification.
===Specification of a Routine===
If we remove the instructions from a routine and leave its signature, header comment and assertions, we have a specification for the routine.
<code>
set_second (s: INTEGER)
-- Set the second from `s'.
require
valid_argument_for_second: 0 <= s and s <= 59
ensure
second_set: second = s
end
</code>
This specification of <code>set_second</code> tells us what is required of reuse consumers if they wish to use <code>set_second</code> and what <code>set_second</code> promises to do for them. Importantly, it does that without revealing how it does it does what it does.
So, this specification view, officially called the contract view, is how consumers of class <code>TIME_OF_DAY</code> would view the feature.
If this is the specification, then haven't we put the cart before the horse? The answer is yes. We have done so to illustrate the problems that assertion-based specification can help solve.
Instead of starting with a routine and adding a specification, we really want to start in accepted software engineering fashion with specification first, and then add implementation. Therefore, the specification you see above would exist before the implementation.
Now back to the concern over whether the postcondition is redundant for this simple one-line routine. Obviously, if this specification exists first, then the postcondition must be there, and it would be silly to remove it later. But, more importantly, suppose that when the producer of the class decided on an implementation, he or she chose the second design alternative we mentioned above. This would mean that the internal state of an instance of <code>TIME_OF_DAY</code> would be only one <code>INTEGER</code> with the number of seconds since midnight. That would mean that the query <code>second</code> would probably be a function that computed seconds from that one <code>INTEGER</code> instead of an attribute.
What would change in the specification of <code>set_second</code>? Nothing. The implementation for the routine would be more complex, but what it does, setting the second in an instance of <code>TIME_OF_DAY</code>, would stay the same.
In summary, the precondition and postcondition ensure for use that the routine will only execute if called in a state in which the precondition is true, and then will either complete in a state in which the postcondition is true, or cause a postcondition violation exception.
===The Contract for a Routine===
Having assertions on its routines forms a contract between the <code>TIME_OF_DAY</code> class and all potential reuse consumers. The contract is much like a contract in business, with obligations and benefits for both parties.
* The client's benefits are outlined in the postcondition.
* The client's obligations come from the precondition.
* The supplier's obligations are in the postcondition.
* The supplier's benefits come from the precondition.
We can see the specifics of these by using <code>set_second</code> as an example.
* The client gets the desired value for seconds set in the instance.
* The client must provide an argument that is valid for seconds.
* The supplier must update the instance successfully.
* The supplier need not risk disaster attempting to process in an invalid state nor waste time validating the argument received from the client.
===Valid State for Instances===
Assertions on <code>TIME_OF_DAY</code>'s routines gives us specification for each routine and guarantees that if the specification of a routine gets violated at runtime we will be served immediately with an exception. This will go a long way toward preventing invalid instances from going unnoticed in a running system and fouling up lots of other stuff.
What will help even more is something called a class invariant. Using the class invariant we are able to state what it means for an instance of a class to be valid, or as it is sometimes put, in a stable state.
The class invariant is an assertion like precondition and postcondition, but there is only one per class. Check [[Eiffel Classes|Eiffel Classes]] to see how the class invariant fits into the class structure.
How would we code the class invariant for <code>TIME_OF_DAY</code>? An instance would be valid if its hour were between 0 and 23 inclusive, minute were between 0 and 59 inclusive, and its second were between 0 and 59 inclusive. We can code the invariant as shown below.
<code>
invariant
hour_valid: 0 <= hour and hour <= 23
minute_valid: 0 <= minute and minute <= 59
second_valid: 0 <= second and second <= 59
</code>
The name invariant implies that the assertion can never be false ... and that's true up to a point. It's really more like, "it must be true at times when it really counts".
At runtime the invariant must be true for an instance at anytime that the instance is available to clients. In general, this means that the invariant must be true before and after the execution of every exported routine.
As with the assertions on routines, if ever the invariant is not true when it should be, then a class invariant violation occurs.
Remember in the example above, that the features <code>hour</code>, <code>minute</code>, and <code>second</code> are queries, but they could be either attributes or functions.
==The Contract for a Class==
Earlier we saw the contract for a routine. Now we can define the contract for a class as the aggregation of the contracts for all its exported features, plus its class invariant.
In Design by Contract we design based on these contracts. They are the specifications for the modules in our system. We work in a reuse-oriented world. Whenever we produce a class, we produce it with a comprehensive contract which serves as its specification. We build each class with the thought that it may eventually become reusable.
When we are in our reuse consumer role, using existing classes, we tend not to look at the implementations for the classes we use. Instead we look at their contract views. It is there that we find the obligations and benefits of using each class.
==Contracts and Debugging==
We saw earlier that having contracts in the code tends to expose bugs at an early stage of development. It is possible selectively to turn off and on the runtime checking of assertions by changing project settings. Checking assertions does involve processing. More about turn off assertion checking in a moment.
Having contracts on a class gives another advantage when the contract gets broken. The contract tells us whose fault it is. Whenever there is a violation of a precondition, postcondition, or class invariant then the software is out of specification. This situation is called a defect, or bug.
Whose fault is it? If a precondition was violated, then a client class attempted to call a routine in a supplier, but made the call in a state that did not satisfy the supplier's precondition. Therefore the bug is in the client.
If a postcondition was violated, then a client made a call in a state that did satisfy the supplier's precondition, but the supplier was unable to complete the work as agreed. Therefore the fault lies with the supplier.
If a class invariant was violated, then the instance has been placed in an invalid state during the execution of a routine, and left that way when the processing completed. This caused the invariant violation. As with the postcondition violation, because the problem occurred while executing routines in the supplier, preconditions must have been met. The supplier then is to blame.
Based on this knowledge, we can say that it is most practical first to turn off runtime checking of postconditions and invariants as we gain confidence in a class. Meaning of course, that we feel confident that any calls that meet preconditions will be properly processed. Then our only worry is that some deranged client will, with total disregard for our carefully crafted preconditions, make calls to our routines from invalid states. So, maybe we will leave precondition checking turned on for a while.
==Contracts and Inheritance==
In the section titled [[Inheritance|Inheritance]] you saw that it was possible through inheritance to produce a new class that has all the features of an existing one. This is a very powerful notion, and could be dangerous. What would keep descendants from redefining inherited features with semantics that were totally different from those intended by the producer of the original class? Nothing if it were not for the contract.
Simply speaking assertions on a parent class, preconditions, postconditions, and class invariants, all are inherited by the class's proper descendants.
For class invariants, if any new invariants are coded in an heir, they will be added to those inherited from the parent, using a non-strict version of logical "and" (We will define non-strict booleans in Writing Assertions below).
That is simple enough. And the situation is also simple for effective routines inherited and left unchanged ... the contracts stand as written.
From our example above you may have gotten the idea that contracts are really useful only for effective routines. Such is not the case. In fact, specifying a contract on a deferred routine is really a powerful notion. It says not only that effective descendants must provide an implementation for this routine, but also that there is a contract that must be satisfied. Effecting or redefining a routine in a descendant class will not make the contract go away. Here is an feature from the Base Library deferred class <code>ACTIVE</code> which models data structures with a current item, and is an ancestor to many effective container type classes.
<code>
feature -- Element change
replace (v: G)
-- Replace current item by `v'.
require
writable: writable
deferred
ensure
item_replaced: item = v
end
</code>
Feature <code>replace</code> carries the semantics necessary for replacing an item in an <code>ACTIVE</code>. It does not, however provide an implementation. All implementers must produce versions of <code>replace</code> that satisfy the contract specified here.
It actually is possible to alter a feature assertion in an effected or redefined version(technically its a replacement of the original version):
* The precondition can only become weaker than in the inherited contract.
* The postcondition can only become stronger than in the inherited contract.
These rules are imposed as a consequence of the effect of effected or redefined routines on polymorphism and dynamic binding. But, you can understand them from an intuitive viewpoint, if you reconsider the business contract analogy. Suppose a contractor makes a deal with a client to do certain work (represented by the postcondition). Part of the deal might be that the client agrees to have a site ready by a certain date (represented by the precondition). The contractor represents the parent class in the analogy. Now suppose the contractor brings in a subcontractor (representing the heir class) to do a portion of the work. The subcontractor cannot force the client to change the date that the site is to be ready to an earlier date (no strengthing of the precondition). The deal with the client was made by the contractor and so no new or stronger requirements can be imposed by the subcontractor. Likewise the subcontractor must provide at least as much work as was bargained for by the contractor, but may promise to provide more if appropriate (strengthing of postcondition is allowed.)
In Writing Assertions below you will see the syntax for weaking preconditions and strengthening postconditions.
==Unfinished Business==
In the section [[Adding Class Features|Adding Class Features]] , we promised to explain two issues during this discussion of Design by Contract.
===Short Routines===
One of these is the tendency of mature Eiffel programmers to write routines that are quite short. It should be clear by now that we wish to build a contract on each routine. The contract describes the semantics of the routine in a declarative fashion. In other words, it tells what the routine does, without giving an indication of how it does it.
Try to imagine giving a declarative description of a routine that was 50 lines long. This could get ugly. So experienced Eiffel developers decompose complex computations into chunks small enough to be described through a clear, concise set of assertions.
===Command/Query Separation===
In [[Adding Class Features|Adding Class Features]] , we saw that we can categorize features as either queries or commands. A query will ask a question or make an observation about an instance. A command will tell the instance to take some action which may result in changing the instances internal state.
We said that when program routines, that those routines should either be commands or queries but not both. Importantly, asking a question about an instance should not change the instance. Likewise, taking an action that changes the state of an instance should not return a result.
Here's the rationale. In a routines postcondition we use boolean expressions to ensure that the routine has done its job properly. Likewise, class invariants, which define the valid state for instances, are written as boolean expressions. In both cases we may use the features of the class which are queries to ask about an instances current state.
If a query that we use in an assertion were to change the state of the instance, then the result we received would be invalid as soon as we received it.
Therein lies the primary reasoning behind command/query separation. You cannot reason about the integrity of an object if the act of asking a question changes the object.
==Writing Assertions==
You have seen fairly typical assertions written in the examples above. Study the classes in the libraries to see some excellent working examples. There are a couple of things that need to be covered.
===Non-Strict Booleans===
One is that, as you can probably imagine, it is not a good thing to cause an exception during the process of checking an assertion. One of the most common ways to cause such an exception is to apply a feature to a Void reference.
The way to avoid this is to use the non-strict booleans "<code>and then</code>" and "<code>or else</code>". These forms of "<code>and</code>" and "<code>or</code>" do not force the checking of all conditions. As soon as a determination can be made, they stop checking. It is typical to see "<code>and then</code>" used to avoid applying a feature to a void reference in preconditons. Below is a creation procedure that uses a non-strict boolean in its precondition.
<code>
make (a_nm: STRING; a_offset: INTEGER)
-- Initalize with name `a_nm' and utcoffset `a_offset'.
require
name_not_empty: a_nm /= Void and then not a_nm.is_empty
offset_valid: a_offset >= -12 and a_offset <= 12
do
name := a_nm.twin
utcoffset := a_offset
ensure
name_initialized: name.is_equal (a_nm)
utcoffset_initialized: utcoffset = a_offset
end
</code>
===Replacing Inherited Feature Assertions===
To replace a precondition on a feature you are effecting or redefining, you use the "<code>require else</code>" keywords to introduce new conditions. These conditions will be logically "<code>or</code>-ed" with the original precondition to form an new one.
Likewise use "<code>and then</code>" to add conditions to a postcondition. The added conditions will be "<code>and</code>-ed" to the original.
Below is an example of weakening a precondition. The first feature shown is from class <code>DYNAMIC_CHAIN</code> in the Base Library.
<code>
remove_left
-- Remove item to the left of cursor position.
-- Do not move cursor.
require
left_exists: index > 1
deferred
ensure
new_count: count = old count - 1
new_index: index = old index - 1
end
</code>
The next feature is from <code>DYNAMIC_LIST</code>, a proper descendant of <code>DYNAMIC_CHAIN</code>. <code>DYNAMIC_LIST</code> weakens the precondition it inherited from <code>DYNAMIC_CHAIN</code>. Originally in <code>DYNAMIC_CHAIN</code>, "<code>index > 1</code>" was required for <code>remove_left</code>. In <code>DYNAMIC_LIST</code> either "<code>index > 1</code>" or "<code>not before</code>" (or both) will suffice.
<code>
remove_left
-- Remove item to the left of cursor position.
-- Do not move cursor.
require else
not_before: not before
deferred
end
</code>
==Not Writing Assertions==
Let's close this discussion of Design by Contract with one more interesting and point to make about assertions. The precondition and postcondition parts of a routine are optional, as you may remember from [[Adding Class Features| Adding Class Features]] . Suppose you write a routine and do not code either precondition or postcondition. You might be tempted to think that you have simply written a routine that has no contract. But, that would not be the case.
The contract exists, even though you do not code it explicitly. If it were written out, it would look as follows.
<code>
my_routine
-- My descriptive header comment
require
True
ensure
True
end
</code>
What does this mean? It means that you have selected the weakest possible precondition and postcondition for your routine. Of course, this may be perfectly valid under some circumstances.
Just understand that if your routine could speak, it would be telling you, "I can always work successfully without any particular guarantees from you at all. On the other hand, I won't promise you any particular results when I get done."

View File

@@ -0,0 +1,223 @@
[[Property:title|Eiffel Classes]]
[[Property:weight|1]]
[[Property:uuid|f905426e-3109-b60b-adf0-c74b83c81b55]]
The unit of software reuse in Eiffel is the class.
The unit of modularity in Eiffel is the class.
The unit of type modeling in Eiffel is the class.
All Eiffel code must exist within the context of a class.
In Eiffel, application systems, or simply systems, are created by assembling a set of related classes. The classes in a system will be related only by one or both of the two allowable relationships in object-oriented design.
Having read the above, you should be convinced that the concept of class is important and far-reaching. The fact that we have precise rules about classes simplifies life a lot. The only kind of module in Eiffel is a class. Each class exists in one source file (which contains only that class), and contains the code necessary to provide a static definition of a data type. Every runtime entity, i.e. every object, must be an instance of a class. Because we can depend upon these things in Eiffel, we have consistency and predictabililty in the inherently complex world of software development.
Let's take a look at how classes are structured.
The code that makes up an Eiffel class is divided into the following parts:
==Structure of a Class==
All of the above, except Class header, are optional. So the simplest Eiffel class you could build would look like this:
<code>
class
SIMPLE
end
</code>
Okay, so class SIMPLE is only interesting in its simplicity. Let's look at an example that is more illustrative:
<code>
note
description: Objects that model lists
revision: $Revision: 1.4 $
class
OLD_FASHIONED_LIST [G]
obsolete "This class is obsolete, use LINKED_LIST [G] instead"
inherit
DYNAMIC_LIST [G]
create
make
feature -- Initialization
make
-- Create an empty list.
do
before := True
ensure
is_before: before
end
feature -- Access
item: G
-- Current item
do
Result := active.item
end
first: like item
-- Item at first position
do
Result := first_element.item
end
... other features omitted ...
invariant
before_constraint: before implies (active = first_element)
after_constraint: after implies (active = last_element)
</code>
Here is a class that, although completely contrived, utilizes all of the required and optional parts of the class. Let's look at each part individually.
===Note===
<code>
note
description: Objects that model lists
revision: $Revision: 1.4 $
</code>
The <code>note</code> part of a class is there to allow you as a producer to record information of your choice which will help you or other reuse consumers at some later time to locate understand the class. This important in Eiffel because we try to treat every class as if someday it will become reusable.
Information in <code>note</code> does not change the semantics of the class.
The <code>note</code> part in the class above is typical. It is introduced with the language keyword <code>note</code>, and contains two note clauses, each of which is comprised of an index and a single index value. You can code note clauses with indexes that you devise yourself, so there is nothing inherently special about "<code>description</code>" and "<code>revision</code>" as used above. But, these indexes could be special to tools which analyze libraries of classes use them. Although these clauses have only one index value each, it is permissible to put more, separated by commas.
===Class Header===
<code>
class
OLD_FASHIONED_LIST [G]
</code>
The class header is introduced by the keyword "class", which in turn can be preceded by one of three keywords which mark the class as <code>deferred</code>, <code>expanded</code>, or <code>frozen</code>. In our example, the class has none of these markings, so it is an effective class whose instances are access by reference.
The keyword class is followed by the class name, in this case "<code>OLD_FASHIONED_LIST</code>".
Of the three keywords for header marks, the one which you will encounter most often is <code>deferred</code>. A class is deferred if it contains one or more features that are deferred, that is, features which have been specified in the class but for which no implementation has been provided. Proper descendants of a deferred class will provide implementations for its deferred features.
===Formal Generics===
<code>
class
OLD_FASHIONED_LIST [G]
</code>
In this example the class name is followed by the specification of one formal generic parameter "<code>G</code>". The presence of one or more formal generic parameters will designate a class as a generic class. The formal generic parameter is a place holder for a class name which will be provided by reuse consumers. For example if we wrote a class which was a client to <code>OLD_FASHIONED_LIST</code> we would substitute the class name for the type of objects that we would want to build an <code>OLD_FASHIONED_LIST</code> of. We might make this declaration:
<code>
my_list_of_cats: OLD_FASHION_LIST [CAT]
</code>
The entity <code>my_list_of_cats</code> could then be attached at runtime to an <code>OLD_FASHIONED_LIST</code> of objects of type <code>CAT</code>. So the class <code>CAT</code> becomes an actual generic parameter and substitutes for <code>G</code> in the declaration.
Of course formal generic parameters cannot be the same name as a class name in the same universe. If multiple formal generic parameters are used, they are separated by commas.
You will learn more about generic classes in the section titled [[Genericity|Genericity]] .
===Obsolete===
<code>
obsolete "This class is obsolete, use LINKED_LIST [G] instead"
</code>
<code>OLD_FASHION_LIST</code>s are obsolete ... and the class is marked as such by include the line above. The manifest string contains an explanation, instructions, and/or recommended alternatives. Compilers and other language tools can deliver this message to potential reuse consumers. As with <code>note</code>, <code>obsolete</code> has no effect on the semantics of the class.
Obsolete is rarely used because of the nature of certain elements of the Eiffel methodology. For example, if implementations are well-hidden behind implementation-independent specifications, then those implementations may be changed to adapt the class to changing execution environments in such a way that clients are unaffected.
===Inheritance===
<code>
inherit
DYNAMIC_LIST [G]
</code>
One of the two possible relationships between classes, inheritance is also a powerful software reuse mechanism. In this example class <code>OLD_FASHIONED_LIST</code> declares itself to be a proper descendant of class <code>DYNAMIC_LIST</code>.
There will be more in the section called . For now though, be aware of two important implications of this declaration:
* Every feature of <code>DYNAMIC_LIST</code> is available to <code>OLD_FASHIONED_LIST</code> and potentially available to its clients.
* Whenever an instance of <code>DYNAMIC_LIST</code> is called for, then an instance of <code>OLD_FASHIONED_LIST</code> will suffice.
===Creators===
<code>
create
make
</code>
The creators part of a class declares a procedure as being a creation procedure. In this case the procedure in question is the one named <code>make</code>. By convention, creation procedure names begin with the word " <code>make</code>".
Let's take a quick look at object creation. Consider this declaration:
<code>
my_list_of_cats: OLD_FASHION_LIST [CAT]
</code>
Here the entity <code>my_list_of_cats</code> can be attached to an object of type <code>OLD_FASHION_LIST [CAT]</code> at runtime. The process of converting <code>my_list_of_cats</code> from holding a void reference to holding a reference to a object modeling a list of cats, starts when a creation instruction is executed. The creation instruction creates the instance and may apply a creation procedure to initialize the instance. A creation instruction for the declaration above would look like this:
<code>
create my_list_of_cats.make
</code>
The <code>create</code> keyword is used to introduce a creation instruction. This instruction causes the following four things to happen:
* A shell of a new instance of <code>OLD_FASHION_LIST [CAT]</code> is created in memory with a memory field for every attribute
* Each field is initialized with standard default values
** False for type <code>BOOLEAN</code>
** Null character for type <code>CHARACTER</code>
** The appropriate form of zero for number types
** <code>Void</code> for reference types
* Attach the new instance to the entity <code>my_list_of_cats</code>
* Apply the creation procedure <code>make</code>
Once these steps complete successfully, <code>my_list_of_cats</code> will be attached to a valid instance (i.e., an instance in which the class invariant is true) of <code>OLD_FASHIONED_LIST [CAT]</code>.
===Features===
<code>
feature -- Initialization
make
-- Create an empty list.
do
before := True
ensure
is_before: before
end
feature -- Access
item: G
-- Current item
do
Result := active.item
end
first: like item
-- Item at first position
do
Result := first_element.item
end
</code>
The features part of a class is the area in which we feel that most of the "programming" is done. It is here that we define those things that instances of a class have and can do. We will learn more about features in the next section [[Adding Class Features|Adding Class Features]] .
Until then let's just take a quick look at how features fit into a class. Notice that in our example the features part is introduced by the keyword "<code>feature</code>". In fact there are two occurrences of <code>feature</code> in this example, each followed by a comment.
You may declare multiple <code>feature</code> statements. This helps you group features in a manner that makes sense. Here we see the first group contains those features which are listed as creation procedures in the creators part of the class. The second group of features labeled "<code>Access</code>" contains a set of queries available to clients of the class.
Although the words "<code>Initialization</code>" and "<code>Access</code>" are actually in comments after the <code>feature</code> keyword, some language processing tools apply some significance to these, for example, ordering the groups in "pretty-printed" views of a class. Also, some tools allow you to build templates for creating new classes which have <code>feature</code> clauses already in place for predetermined groups.
{{tip|There is not a technical requirement governing the grouping or ordering of features in a class. It is the option of the producer of a class to group and order the features in a fashion that holds some meaning. Many years of Eiffel development experience are reflected in the classes in the EiffelBase Library. This is a good place to look for examples of well constructed classes. }}
===Invariant===
<code>
invariant
before_constraint: before implies (active = first_element)
after_constraint: after implies (active = last_element)
</code>
Here's the last word in a class definition ... both literally and figuratively. The invariant part, introduced not surprisingly by the keyword "<code>invariant</code>", is that portion of the class in which we can state what it means for an object to be a valid instance of this class.
We will learn more about class invariants in the section titled [[Design by Contract and Assertions|Design by Contract and Assertions]] .

View File

@@ -0,0 +1,26 @@
[[Property:title|Eiffel for .NET Compliance]]
[[Property:weight|9]]
[[Property:uuid|1e19c2f0-995e-02c1-0588-c134a11e0003]]
As of Eiffel for ASP.NET 5.6 and EiffelStudio 5.7; Eiffel for .NET introduces the notion of '''Eiffel-Compliance'''. .NET specifies a number of language interoperability rules in a [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconwhatiscommonlanguagespecification.asp Common Language Specification-Compliance] specification. Eiffel for .NET supports all CLS-Compliant type and features in .NET but now additionally supports a number of non-CLS-compliant types and features. This is the purpose of the Eiffel-Compliant notion.
The information contained within this page does not go into any depth on the Common Language Specification (CLS) or CLS-Compliance. For this information please see Microsoft's on-line documentation [http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconwhatiscommonlanguagespecification.asp What is the Common Language Specification?]
<span id="applicablity"></span>
==Applicability==
The CLS states a number of rules .NET tools have to abide by to be CLS-compliant. These rules relate to both a .NET producer, generally a compiler generating .NET code, and a consumer, which is generally a compiler that consumes .NET assemblies for reuse. Eiffel-Compliance relates only to consumption of .NET assemblies.
<span id="what_is_compliant"></span>
==What is Eiffel-Compliant?==
As already stated, anything CLS-compliant is Eiffel-compliant. Eiffel-Compliancy merely allows for exceptions so that non-CLS-compliant assemblies, types and members can be used in Eiffel for .NET.
The following list outlines the supported non-CLS-compliant types:
* All unsigned numerical basic types such as <eiffel>System.UInt32</eiffel> as <eiffel>System.UInt64</eiffel>, represented by <eiffel>NATURAL_xx</eiffel>.
* Native pointers (<eiffel>System.IntPtr</eiffel>), represented by <eiffel>POINTER</eiffel>
Typically assemblies, types or members are marked with the <eiffel>System.CLSCompliantAttribute</eiffel> attribute to explicitly indicate if they are CLS-compliant or not. The Eiffel for .NET compiler will now ignore this attribute and instead infer if they are Eiffel-Compliant. With such an inference engine at hand, Eiffel for .NET opens itself up to extended support for COM/Legacy interop as well support assemblies not adhering to CLS-compliant rules, for one reason or another.

View File

@@ -0,0 +1,203 @@
[[Property:title|Event Programming with Agents]]
[[Property:weight|7]]
[[Property:uuid|ea9d7b9d-daa1-a415-628a-e3a2f935c12a]]
In Eiffel there is a facility referred to as agents.
The implementation of agents is an advanced topic, but you do not have to understand the details of the implementation of agents to put agents to work for you. That is what you will learn in this section.
==Objects that Represent Operations==
Object technology is based on the idea that when we model systems based on objects, representing the "things" they manipulate. As to operations on these objects, they appear in the corresponding classes, as routines (functions and procedures). Operations are not objects.
Sometimes, on the other hand, the "things" we model with our objects could represent operations. For example, we might want to build a list of tasks to be performed later; each task is defined by a routine. Each of the objects in the list will represent the corresponding routine.
Such an object, representing an operation, is called an agent.
If we can have a run-time object that represents an operation, then we can place the object in the structure of another object, where at some later time, a client can cause the associated operation to execute.
This is a very desirable model for event driven processing, like graphical user interfaces. The operations that are executed when a user take some action like clicking on a button, could be represented by agents. When the user interface element is initialized, agents that represent the action routines are stored within the interface element. Then at the time that an event, say a button click, occurs, the agents for that event are retrieved and their associated operations are executed.
Another area in which agents are commonly used is in traversing data structures. Many of the data structure classes in the Base Library include routines which take agents as there arguments. For example, the feature <code>do_all</code> takes an agent which represents some procedure and will apply the procedure to every item in the structure.
==Classes to Model Operations==
We know that there are two types of routines in Eiffel, functions and procedures.
The implementation of agents correspondingly relies on three classes in the Base Library: class <code>ROUTINE</code> for the general notion, and its heirs <code>FUNCTION</code>, with and <code>PROCEDURE</code>. In addition, <code>PREDICATE</code>, an heir of <code>FUNCTION</code> , covers the particular case of a function returning a boolean result.
When you use an agent from a client routine, you will be building an instance of either <code>FUNCTION</code> or <code>ROUTINE</code>.
==Using Agents==
Below is an instruction which passes an agent as an argument to a procedure.
<code>
button.select_actions.extend (agent gauge.step_forward)
</code>
In this example, the producer wants to add the action of stepping the gauge forward in the event that a button is clicked. The keyword "<code>agent</code>" is used to indicate that at runtime an object of type <code>PROCEDURE</code> should be created which represents applying the feature <code>step_forward</code> to the object attached to <code>gauge</code>. It is the object of type <code>PROCEDURE</code> that is passed as the argument.
It is important to understand that <code>step_forward</code> does not get applied at the point that the instruction above is executed. Rather the procedure object that represents <code>step_forward</code> is given to the button to hold in reserve. Then at the point that the button click event takes place, the button will go through its list of <code>select_actions</code> executing their associated routines. Only then does <code>step_forward</code>get applied to <code>gauge</code>.
===Agents with Arguments===
In this example, the routine "<code>step_forward</code>" on which the agent is based takes no arguments. If you drilled down into the workings of this example you would find that class that implements the feature <code>extend</code> is class <code>EV_NOTIFY_ACTION_SEQUENCE</code>. You would also see that the signature for the feature <code>extend</code> is as essentially as follows.
<code>
extend (v: PROCEDURE [TUPLE])
</code>
We don't have to know too much about the workings of agents to see that "<code>extend</code>" takes an argument <code>v</code> which is of type <code>PROCEDURE</code>. The actual generic parameter <code>TUPLE</code> represents the set of "open" arguments. In this case, <code>extend</code> is expecting an agent with no open arguments.
===Open and Closed Arguments===
It is this business of open and closed arguments which really makes agents remarkable. To get a feel for it, let's simplify the example some. Instead of considering an agent passed as an argument let's look at it as a simple assignment within a class.
Suppose a class has a feature declared as shown below.
<code>
my_procedure: PROCEDURE [TUPLE]
</code>
Then what can be assigned to <code>my_procedure</code>?. An agent, of course. Say the class has procedures as follows.
<code>
no_argument_procedure
-- A procedure with no arguments
do
print ("No argument here!%N")
end
two_argument_procedure (an_int: INTEGER; another_int: INTEGER)
-- A procedure with two arguments
do
print ("My arguments are: " + an_int.out + " and " + another_int.out + "%N")
end
</code>
Then the following assignment is valid.
<code>
my_procedure := agent no_argument_procedure
</code>
What this means is that the agent created and associated with the procedure <code>no_argument_procedure</code> must conform to the type <code>PROCEDURE [TUPLE]</code>. The feature <code>my_procedure</code> (which is of type <code>PROCEDURE [TUPLE]</code>) can be attached at runtime to an agent representing a procedure with no open arguments, which indeed is what <code>no_argument_procedure</code> is.
Now let's turn our attention to the other procedure <code>two_argument_procedure</code>. You might think that because it takes two arguments, that you would not be able to build an agent from it which could be assigned to the attribute <code>my_procedure</code>. But you can do it by closing the two arguments at the time that the agent is created, as in the following.
<code>
my_procedure := agent two_argument_procedure (1, 2) -- Is Valid
</code>
What happens here is that values are fixed for those arguments at the time that the agent, an object of type <code>PROCEDURE [ TUPLE]</code> is created.
So this is the wonderful thing about agents. A routine which will be represented as an agent does not have to be an exact fit for the expected signature. By closing some arguments at agent creation, you have effectively produced a new and conforming routine.
The advantage of this is that you can sometimes avoid building specialized routines for the sole purpose of having a routine which conforms to the agent signature.
To leave an argument open, you hold its place with a question mark. If you intend for all arguments to be open, then you may make them all question marks, or leave off the arguments entirely.
<code>
my_procedure := agent two_argument_procedure (?, 2) -- Argument 1 left open
my_procedure := agent two_argument_procedure (?, ?) -- Both arguments left open
my_procedure := agent two_argument_procedure -- Both arguments left open
</code>
If an argument is open, then it means that a value is not provided for that argument at the time that the agent is created. The implication is that the value must be provided at some time prior to the time that the agent's associated routine gets executed. A precondition to executing a routine associated with an agent is that the agent has a valid set of arguments (called operands within the <code>ROUTINE</code> classes) for the call. If you were to leave one or both of the arguments to <code>two_argument_procedure</code> open as in the examples above, the assignment would still work due to the rules governing <code>TUPLE</code> conformance. But, at runtime unless the other arguments had been provided, the "<code>valid operands</code>" precondition would be violated.
Let's see an example in which we leave a target open. Suppose we have a class that has a feature coded as below
<code>
my_strings: LINKED_LIST [STRING]
</code>
and some code to put some strings in <code>my_strings</code>:
<code>
create my_things.make
my_strings.extend ("Hello")
my_strings.extend ("World!")
</code>
Our class also has a feature called <code>print_on_new_line</code> which we created to print a string preceded by a new line character.
<code>
print_on_new_line (s: STRING)
-- Print `s' preceded by a new line
do
print ("%N" + s)
end
</code>
Now suppose we want to print the values of all the strings in <code>my_strings</code> each on a separate line by invoking <code>print_on_new_line</code>. Traditionally, we would do it by traversing the <code>LINKED_LIST</code> and printing each item. Like this:
<code>
from
my_list.start
until
my_list.exhausted
loop
print_on_new_line (my_list.item)
my_list.forth
end
</code>
The availability of agents gives us new options. <code>LINKED_LIST</code> has a feature <code>do_all</code> which comes to it from its ancestor <code>LINEAR</code>. The <code>do_all</code> feature's signature looks like this:
<code>
do_all (action: PROCEDURE [TUPLE [G]])
</code>
As an argument <code>do_all</code> takes an agent based on a procedure with one open argument which is the same type as the list items (in this class, <code>G</code> is the formal generic parameter representing the type of the items being stored). Then it traverses the list executing the routine associated with that agent and uses the current list item to satisfy the open argument.
Instead of coding the loop shown above, we can code this instruction:
<code>
my_list.do_all (agent print_on_new_line (?))
</code>
we leave open the argument required by <code>print</code>, and <code>do_all</code> will provide it as a reference to the current list item as it traverses the list.
===Targets for Agents' Routines===
In Eiffel every routine must be applied against a target object. In our model for computation, <code>x.f (a, ...)</code>, the <code>x</code> is the target of the application of feature <code>f</code>. In the case of an agent, the agent must account for objects for each of the arguments and an object for the target of the routine.
Let's identify the targets in the examples shown. First:
<code>
button.select_actions.extend (agent gauge.step_forward)
</code>
Here the target is the object attached to the entity "gauge" which is (although you cannot determine it from this line taken out of context) an object of type <code>EV_GAUGE</code>.
How about this:
<code>
my_procedure := agent two_argument_procedure (1, 2)
</code>
Here, since there was no qualification, then the target is the current instance. Same with this:
<code>
my_list.do_all (agent print_on_new_line (?))
</code>
Again, consider the fact that the agent must account for objects for each of the arguments to a routine, and an object for the target. So, in the examples we've seen so far, the target is close, that is provided at the time of the creation of the agent.
But we can actually leave the target open as well. Now we cannot use the question mark notation to do that, because if we did, there would be no way to know of which class the routine is a feature. So instead, we mark an open target with the class name in braces.
Suppose in our list of strings example, we wanted to print the strings, then convert them to lower case, then print them again. Remember that "do_all" has one open argument, which will be provided as the current list item during the traversal.
<code>
my_list.do_all (agent print_on_new_line (?))
my_list.do_all (agent {STRING}.to_lower)
my_list.do_all (agent print_on_new_line (?))
</code>
In between printing the list two times, we provide <code>do_all</code> with an agent that representing the <code>STRING</code> class's feature <code>to_lower</code> which will convert each string in the list to lower case. Notice that <code>to_lower</code> does not take an argument of type <code>STRING</code> as <code>print_on_new_line</code> did. Rather it gets applied to an instance of <code>STRING</code>, so it is targeted to a string. So we leave its target open and <code>do_all</code> provides the current list item as the target.
Agents for Functions
So far all the agents that we have coded have created instances of <code>PROCEDURE</code>. But functions are routines and can be represented as agents as well. The difference is that functions have a return value.
Let's extend the string example by using an agent that represents a function. Suppose we wanted to print only those strings which contain a particular character, say the exclamation point.
Here again we'll use a feature of the <code>LINKED_LIST</code> class. There is a feature called <code>do_if</code> which takes two agents as arguments. One is an action procedure like the argument that <code>do_all</code> takes, and the other is a function which returns a boolean and used as a test. As each list item is current, the test is applied first. If the result is true, then the action is applied with the current item.
<code>
my_list.do_if (agent print_on_new_line(?), agent {STRING}.has('!'))
</code>
The agent for the action is the same as we used earlier. We've added an agent for the test. It represents applying the <code>has</code> feature of the <code>STRING</code> class. Here the target is left open, because we want each of the strings in the list to be the target of <code>has</code>.
Compatibility note
Versions of the Kernel Library classes ROUTINE, PROCEDURE, FUNCTION and PREDICATE prior to EiffelStudio 17-05 had an extra generic parameter at the initial position; the usual actual generic parameter was ANY. It has been removed. The compiler has been engineered so that in almost all cases it will still accept the old style.

View File

@@ -0,0 +1,66 @@
[[Property:title|Exception Mechanism]]
[[Property:weight|6]]
[[Property:uuid|84a159dd-4a19-af73-7b0b-0618a284142a]]
==Motivation: Concerning Robustness==
The notion of software correctness that we saw in [[Design by Contract and Assertions|Design by Contract and Assertions]] is half of the formula for software reliability. Correctness covers what the software is supposed to do, that is, its specification.
Of course,there is always a potential for things to go out of the bounds of the specification. This happens, for exampleif a client makes a call to a routine from a state in which the routine's precondition is not true.
How well software responds to situations which outside specification is called robustness. Together correctness and robustness define software reliability.
==Consequences of Contracts==
In the presence of Design by Contract, what happens to running software boils down to a simple rule:
A routine callcan complete in one of only two ways:
# The routine fulfills its contract.
# The routine fails to fulfill its contract.
As a follow-on, we can add that:
* Any routine that fails to fulfill its contract must cause an exception in its caller.
==Reacting to Exceptions==
Again, because of Design by Contract, we can state the following rule for dealing with exceptions:
A routine that incurs an exeception can react in one of only two ways:
# It can return the instance to a stable state and retry the entire routine with the same or a different strategy.
# It can fail, causing an exception in its caller.
There is an Eiffel mechanism called the rescue clause which facilitates the first alternative.
===The Rescue Clause===
The <code>rescue</code> clause is part of the routine structure we saw in [[Adding Class Features|Adding Class Features]] . The rescue clause is a sequence of instructions introduced by the keyword "<code>rescue</code>". At the point that an exception occurs, the processing of the normal instructions in the routine body will cease, and the instructions in the rescue clause will be executed instead.
If the instructions in the rescue clause can set things up so that it might prove fruitful to attempt to retry the routine, it can do so by issuing a <code>retry</code> instruction. When the <code>retry</code> instruction is executed, the routine is restarted from its beginning, although local entities are not re-initialized. You will see why in the example below.
If the rescue clause exits without issuing a <code>retry</code> instruction, then the routine fails.
It should be noted that rescue clauses and retry instructions are not something that are used commonly. Out of the approximately 2000 classes in the delivered Eiffel libraries, there are only 16 occurrences. Many of these are oriented toward network and database operations for which some reasonable recovery might be possible.
<code>
transmit: (p: PACKET)
-- Transmit packet `p'
require
packet_not_void: p /= Void
local
current_retries: INTEGER
r: RANDOM_NUMBER_GENERATOR
do
line.send (p)
rescue
if current_retries < max_retries then
r.next
wait_millisecs (r.value_between (20, 500))
current_retries := current_retries + 1
retry
end
end
</code>
In the example above, <code>rescue</code> is used to recover from a situation in which an exception occurs in trying to send a packet. When the exception occurs the rescue clause will, if the maximum number of retries has not been reached, wait for some random length of time. Then, after having updated the number of retries, it will issue the <code>retry</code> instruction. If the maximum number of retries is reached, the rescue clause will exit without executing the retry, constituting a failure.

View File

@@ -0,0 +1,144 @@
[[Property:title|Genericity]]
[[Property:weight|4]]
[[Property:uuid|3a0bfe10-78e7-00eb-d9a0-b977d1fa352a]]
We got a very short introduction to generic classes when we were looking at the formal generic part of class structure in [[Eiffel Classes|Eiffel Classes]] . That discussion left to the imagination the motivation and benefits for creating generic classes.
You will see that most of the generic classes model containers for multiple items and at least one of their formal generic parameters represents the type of items that are to be stored in the container. Some generic classes, like <code>LINKABLE</code>, care for only one instance of the type represented by their formal generic parameter.
==Motivation==
Imagine that a software producer is planning to build a class which would represent a list of things. Someone might ask "What kinds of things?" To which the producer would reply, "Just things. I want my list to be usable for all kinds of things."
Using the idea of polymorphic attachment that we learned in [[Inheritance|Inheritance]] , the producer could build such a class. It might have a query <code>item</code> which would return the thing from the list to which a cursor currently points. It might have a command <code>put</code> which would enter some new thing into the list.
What would be the type of <code>item</code>? And what would be the type of the argument to <code>put</code>?
If the producer wants the class to handle all kinds of things, then the answer must be class <code>ANY</code>, the class from which all others inherit.
<code>
class
LIST_OF_THINGS
...
feature -- Access
item: ANY
-- The thing currently pointed to by cursor
...
feature -- Element change
put (new_item: ANY)
-- Add `new_item' at the end of the list
...
</code>
This will work, but has some definite disadvantages. Suppose you choose to use this class to maintain a list of cats in one of your classes. You might make this declaration:
<code>
my_cats: LIST_OF_THINGS
-- A list of my cats
</code>
Then you could add individual instances to the list:
<code>
fluffy, twinkie: CAT
...
my_cats.put (fluffy)
my_cats.put (twinkie)
</code>
One problem with this type of list is that the type system will not help you keep from doing something pathological like:
<code>
fluffy, twinkie: CAT
thor: PSYCHOTIC_HYDROPHOBIC_CAT_HATING_DOG
-- A very nasty dog
...
my_cats.put (fluffy)
my_cats.put (twinkie)
my_cats.put (thor)
</code>
Another problem is that to do any <code>CAT</code> things with an item in the list, you must reattach it to a <code>CAT</code> entity. The following is invalid.
<code>
my_cats.item.purr -- Is invalid
</code>
This is because "item" is type <code>ANY</code> and although it may be currently attached to an instance of <code>CAT</code>, the static typing system cannot guarantee that. So you must use an object test as we saw in the polymorphism example in [[Inheritance|Inheritance]] .
<code>
...
if attached my_cats.item as some_cat then
some_cat.purr
end
</code>
You can see that this type of list has its drawbacks. Of course you could build a <code>LIST_OF_CATS</code> class in which <code>item</code> and the argument for <code>put</code> would be of type <code>CAT</code>. This would let you <code>purr</code> a cat without pulling it out of the list, and it would also prevent you from accidently letting old Thor in with the cats. But, every time you needed a list to hold a different type of object, you have to write a new class.
Indeed, this is how things are done in environments without facilities genericity.
What we would like to have is a way to produce the text of the list class once. Then only when we make declarations do we add the additional information about the particular types we want allowed in the list.
==Basic Genericity==
In Eiffel this is accomplished through generic classes. Generic classes are written relative not to a specific class but to a kind of phony class name called a formal generic parameter. With genericity, the <code>LIST_OF_THINGS</code> class might become a class called <code>LIST</code> which is a list of items of type <code>G</code>. In class <code>LIST</code> we would declare <code>item</code> as type G, as well as the argument to <code>put</code>.
<code>
class
LIST [G]
...
feature -- Access
item: G
-- The item currently pointed to by cursor
...
feature -- Element change
put (new_item: G)
-- Add `new_item' at the end of the list
...
</code>
We could declare feature <code>my_cats</code> as a <code>LIST</code> of items of type <code>CAT</code>. By doing so we are providing <code>CAT</code> as an "actual generic parameter" in the declaration. Then we are free to treat the features of <code>LIST</code> as if the class name <code>CAT</code> had been substituted for every occurrence of the formal generic parameter <code>G</code>.
<code>
my_cats: LIST [CAT]
-- A list of my cats
fluffy, twinkie: CAT
...
my_cats.put (fluffy)
my_cats.put (twinkie)
...
my_cats.item.purr -- Valid now
</code>
The following would no longer be valid:
<code>
my_cats: LIST [CAT]
-- A list of my cats
thor: PSYCHOTIC_HYDROPHOBIC_CAT_HATING_DOG
...
my_cats.put (thor) -- Is invalid
</code>
==Constrained Genericity==
The generic class <code>LIST</code> illustrated above is perfectly useful for making typed lists of any type of object. The features of the <code>LIST</code> will not attempt to use the objects in the list in any way. Sometimes though, it is important for a class to be guaranteed more about the nature of the types that can be substituted for its formal generic parameter.
Take for example the case of a class called <code>SORTED_LIST</code>. A <code>SORTED_LIST</code> is a list, of course, but it is special in that it acts upon the elements that it holds to keep them in order.
A <code>SORTED_LIST</code> needs to be able to order its elements. So, it must be able to apply queries to those elements to determine which should sort high than which. The elements themselves must respond to ordering operations.
If <code>SORTED_LIST</code> were defined like we did <code>LIST</code>
<code>
class
SORTED_LIST [G]
</code>
there would be no guarantee that ordering operations, like "<" and ">" could be applied to all types that could be listed. An Eiffel facility called "constrained genericity" will solve this problemfor us. In the case of <code>SORTED_LIST</code>, we would add to the formal generic part as follows.
<code>
class
SORTED_LIST [G -> COMPARABLE]
</code>
You may remember from [[Inheritance|Inheritance]] that if we make instances of a class comparable with each other, then we make the class inherit from <code>COMPARABLE</code> and effect the feature "<".
Here, constrained genericity does two things for us.
* First, it states that any candidate for substitution for <code>G</code> must conform to class <code>COMPARABLE</code>. Typically this means it must inherit from <code>COMPARABLE</code>.
* Second, it allows, within the features of <code>SORTED_LIST</code>, the features of <code>COMPARABLE</code> to be applied to any item which has a type of <code>G</code>.

View File

@@ -0,0 +1,19 @@
[[Property:title|Eiffel for .NET]]
[[Property:weight|2]]
[[Property:uuid|446038d8-abd6-0a0d-2b90-94124e1ac810]]
These pages contain documentation that describes the Eiffel programming language.
Eiffel is considered both a development methodology and a programming language.
Eiffel the methodology is a recipe for constructing quality software which is based on a small number of powerful concepts. Eiffel the programming language is a notation which is designed to support the methodology.
Eiffel for.NET is the Eiffel programming language made available in the .NET environment. Eiffel for.NET components can use and inherit from components in .NET assemblies that were produced using other.NET languages. And, programmers using other.NET languages can use and inherit from components in assemblies produced using Eiffel for.NET.
==Eiffel for.NET Conventions Documentation==
In Eiffel, as in other languages, certain conventions have evolved which constitute "the way things are done". Conventions provide consistency and therefore predictability and readability of software text.
When working in the.NET components, particularly when using components from .NET assemblies delivered from Microsoft or produced by other parties, the conventions of Eiffel are maintained in the view of these components. The first section, titled [[Conventions]], provides you with an understanding of Eiffel terminology, conventions , and how they work with .NET.
The remaining sections of this section are a reference for the Eiffel for .NET language. It is not a complete reference, though. Rather, it is intended to help you with the tasks that Eiffel programmers commonly encounter.

View File

@@ -0,0 +1,343 @@
[[Property:modification_date|Sat, 12 Jan 2019 18:39:06 GMT]]
[[Property:publication_date|Sat, 12 Jan 2019 18:34:23 GMT]]
[[Property:title|Inheritance]]
[[Property:weight|3]]
[[Property:uuid|7e4cb7ba-fda6-8eac-3e27-bbb8fafd8673]]
Inheritance, along with client/supplier, are the two relationships that can exist between classes.
Inheritance lets us mirror in software the types of abstractions that are common in many problem domains, i.e., the more general to the more specialized.
Inheritance also gives a way us to combine these abstractions.
Inheritance allows us to make extensions and adaptations to existing software, while at the same time, leaving the original software unaltered.
==The Eiffel Inheritance Model==
If class <code>B</code> inherits from class <code>A</code>, then:
* Every feature of <code>A</code> is also a feature of <code>B</code>
* In any case in which an instance of <code>A</code> is called for, then an instance of <code>B</code> will suffice.
Flexibility and adaptability are key qualities of the Eiffel inheritance model. On an informal level, this means that, except as prevented by certain constraints, a class can inherit from a set of classes containing just about any other classes.
Eiffel classes can be effective or deferred. If a class is effective, then it is completely implemented. As a result, it is possible to create and use direct instances of an effective class at runtime.
If a class is deferred, then it is not completely implemented. A class is deferred if it contains at least one deferred feature. So, it is possible for you to mark a feature (and by consequence also its class) as deferred when you code it. This means that the specification for this class dictates that such a feature exists, but there is no implementation for the feature included in the class. As a result, there can be no direct instances of deferred classes at runtime. However, a class that inherits from a deferred class can implement, or effect, the deferred features. This results in an effective descendant to the deferred class. And it is possible to create direct instances of this effective descendant. Such instances would also be instances (albeit not direct instances) of the original deferred class.
What this means to us as software producers, is that in any development effort, we have available a great number of classes which can serve as potential starting points. That is, classes that we could make parents to the classes we produce. And, those classes do not have to chosen from a strict dichotomy of classes which are either completely abstract or completely implemented. Inheritance from classes that are deferred but have some implemented features is both possible and encouraged. It reuses existing software and it reduces the opportunity for error.
Consider the deferred class <code>COMPARABLE</code> from the Eiffel Base Library. A portion of <code>COMPARABLE</code> is shown below:
<code>
deferred class
COMPARABLE
feature -- Comparison
is_less alias "<" (other: like Current): BOOLEAN
-- Is current object less than `other'?
deferred
end
is_less_equal alias "<=" (other: like Current): BOOLEAN
-- Is current object less than or equal to `other'?
do
Result := not (other < Current)
end
is_greater alias ">" (other: like Current): BOOLEAN
-- Is current object greater than `other'?
do
Result := other < Current
end
is_greater_equal alias ">=" (other: like Current): BOOLEAN
-- Is current object greater than or equal to `other'?
do
Result := not (Current < other)
end
is_equal (other: like Current): BOOLEAN
-- Is `other' attached to an object of the same type
-- as current object and identical to it?
do
Result := (not (Current < other) and not (other < Current))
end
</code>
If you are producing a class that you wish to support basic comparison operators, like "<" and ">", you can have that class inherit from <code>COMPARABLE</code>, which has features which correspond to those operators. The text for <code>COMPARABLE</code> contains eight features. Seven of these are effective and one is deferred.
So through inheritance from <code>COMPARABLE</code>, your class, let's call it <code>WHATZIT</code>, would now have these features available. But how would the features of <code>COMPARABLE</code> know what it means to compare <code>WHATZIT</code>s?
Of course, it would have no way of knowing, so you must show it. And you do that by writing the implementation for "<", the one deferred feature that <code>WHATZIT</code> inherits from the <code>COMPARABLE</code> class.
When you look closely at the effective features of <code>COMPARABLE</code>, you see that their implementations are ultimately based on "<". If we were not able to inherit from multiple partially implemented classes, then we would be forced to implement many more features, a process which invites error, or, in the case of comparison, to move to a less appealing model.
==The Inheritance Part of Classes in Eiffel==
Because the inheritance model has such flexibility, it must also have adaptability. A consequence of inheriting from multiple classes is that it would be possible to inherit multiple features with the same name ... and you remember from [[Adding Class Features|Adding Class Features]] that a class is not allowed to have more than one feature with the same name. A process called feature adaptation allows us to resolve these issues in an heir. Feature adaptation is also done for reasons other than resolving name clashes as well.
Feature adaptation is an enabling capability, but it is also one that takes some study to understand fully.
We will look at the types of feature adaptation that will serve most useful to you as you begin to produce Eiffel software.
In [[Eiffel Classes|Eiffel Classes]] you saw where the inheritance part fits into the class structure. Shown below is a portion of class <code>LINKED_QUEUE</code> from the Eiffel libraries. <code>LINKED_QUEUE</code> is an effective class which implements the abstract notion of a <code>QUEUE</code> (a deferred class) with an implementation based on the services provided by <code>LINKED_LIST</code> (an effective class).
<code>
class
LINKED_QUEUE [G]
inherit
QUEUE [G]
undefine
is_empty,
copy,
is_equal
redefine
linear_representation,
prune_all,
extend
select
item,
put
end
LINKED_LIST [G]
rename
item as ll_item,
remove as ll_remove,
make as ll_make,
remove_left as remove,
put as ll_put
export
{NONE}
all
{ANY}
writable,
extendible,
wipe_out,
readable
undefine
fill,
append,
prune,
readable,
writable,
prune_all,
extend,
force,
is_inserted
redefine
duplicate,
linear_representation
select
remove
end
</code>
Okay ... now calm down ... please. This is an example from a very highly-evolved and sophisticated library which is replete with software reuse. <code>LINKED_QUEUE</code> has two parents and uses considerable feature adaptation. In fact, it uses every feature adaptation option available. The benefit is obvious, though. <code>LINKED_QUEUE</code> class has only seven features actually coded. In total there are only 26 lines of instructions!
In practice you can use inheritance, even multiple inheritance, to do some quite productive programming in Eiffel without having to write anything that looks like the inheritance part of <code>LINKED_QUEUE</code> above.
Regardless, let's break <code>LINKED_QUEUE</code>'s inheritance part into chunks and take a look at some of them.
===Rename===
<code>
rename
item as ll_item,
remove as ll_remove,
make as ll_make,
remove_left as remove,
put as ll_put
</code>
As you might have already guessed, the rename part, introduced oddly enough by the keyword "<code>rename</code>", is used to rename features.
Specifically, it is used when an heir wants to use a feature from a parent, but wants to use it under a different name than that by which the parent knows it. So in the example, the feature known as <code>item</code> in <code>LINKED_LIST</code> is perfectly usable in <code>LINKED_QUEUE</code>, but must be applied as <code>ll_item</code>.
This is common when your class inherits two different features with the same name from two different parents and you want to be able to use them both. Because you can only have one feature with a given name, then rename one of the features.
===New Exports===
<code>
export
{NONE}
all
{ANY}
writable,
extendible,
wipe_out,
readable
</code>
The new exports part is introduced by the keyword "<code>export</code>". This section allows you to change the export status of inherited features. Remember from [[Adding Class Features|Adding Class Features]] that features become available (or not) to clients by their export status. Export status of immediate features is controlled in the feature clause. But here we are dealing with inherited features, so we control their status in the export part of the class's inheritance section. Any feature not mentioned will have the same export status as it did in the parent class.
In this example, the keyword "<code>all</code>" is used first to say that all features inherited form <code>LINKED_LIST</code> are unavailable to any clients (export to class <code>NONE</code>). This is typical for a class like <code>LINKED_QUEUE</code> in which the features important to the client come from the deferred parent, in this case <code>QUEUE</code>, and the class <code>LINKED_LIST</code> is used only for implementation. But, it seems that also in this case, the producer felt differently about the features <code>writable</code>, <code>extendible</code>, <code>wipe_out</code>, and <code>readable</code>, and decided the allow clients of <code>ANY</code> type to utilize these features inherited from <code>LINKED_LIST</code>.
===Undefine===
<code>
undefine
is_empty,
copy,
is_equal
</code>
Next, undefine ... it's probably not what you think. You might assume that undefine is a way to banish forever any inherited features that you just do not want to deal with. But what happens to features whose names are listed in an undefine clause is that they become deferred features in the heir.
Undefine is useful if you inherit two different features of the same name from different parents, a situation you cannot live with. If you like one and you don't like the other, then you can undefine the one you don't like. The the only version you get is the one you like.
Another way you might use undefine is in the case in which you actually want a feature to be deferred in an heir that was effective in a parent.
===Redefine===
<code>
redefine
linear_representation,
prune_all,
extend
</code>
The redefine part lists the names of effective features for which the producer of the heir class would like to provide implementations that replace the inherited implementations.
So, in this example the implementation for <code>linear_representation</code>, for example, that <code>LINKED_QUEUE</code> would have inherited from <code>QUEUE</code> will not be used. Instead <code>LINKED_QUEUE</code> implements its own version of <code>linear_representation</code>.
{{note|When a class implements a version of an inherited feature which was deferred in its parent, this is known as "effecting" the feature. Because features being effected are getting their first implementation, it is not necessary to list their names in the redefine part, or anywhere else in the inheritance part of the heir. }}
===Select===
<code>
select
remove
</code>
The select part is used only under special circumstances. The case in which select is required involves a situation called "repeated" inheritance. Repeated inheritance occurs when an heir inherits more than once from the same ancestor. Usually this means it has two or more parents who have a common proper ancestor (but it can occur directly). The features from the common ancestor are inherited by each of the parents and passed on to the heir. The rules and effects of repeated inheritance occupy an entire chapter in the official Eiffel programming language reference and will not be reproduced here. Just understand at this point that it is sometimes necessary to use <code>select</code> to provide the dynamic binding system with an unambiguous choice of features in the presence of polymorphic attachment.
You should note also that repeated inheritance can and does occur often without causing any problem at all. In fact it happens in every case of multiple inheritance, due to the fact that all classes inherit from class ANY and receive its features as a result. The reason it is not a problem is that in the case that any feature makes it from the original common ancestor along multiple paths to the heir with its name and implementation still intact, it will arrive as only one feature heir. This is called sharing and nothing special needs to be done to make it happen.
==Polymorphism==
It is time now to see another way in which inheritance helps build more extendible software.
Assume that we have to build classes that model different types of polygons. We would do this by building a class for polygon which would model a garden-variety polygon, a multi-sided closed figure. But when we consider that there are specialized types of polygons, like triangles and rectangles, we realize that to support these specializations, we need classes for them as well. And this is an obvious opportunity for inheritance. All triangles and rectangles are polygons. So, we start with class <code>POLYGON</code> and its proper descendants <code>TRIANGLE</code> and <code>RECTANGLE</code>.
So we can make declarations like:
<code>
my_polygon: POLYGON
your_polygon: POLYGON
my_triangle: TRIANGLE
my_rectangle: RECTANGLE
another_rectangle: RECTANGLE
</code>
Assume these declarations are in force for all the examples this section on polymorphism.
We saw in [[Adding Class Features|Adding Class Features]] that we can say that one class conforms to another if it is the same class or one of its proper descendants. Therefore POLYGON conforms to <code>POLYGON</code>. Also, <code>TRIANGLE</code> and <code>RECTANGLE</code> conform to <code>POLYGON</code>. But, importantly, <code>POLYGON</code> does not conform to <code>TRIANGLE</code> or <code>RECTANGLE</code>. This makes sense intuitively, because we know all rectangles and triangles are polygons ... and we also know that not all polygons are rectangles.
===Polymorphic Attachment===
These facts affect how assignments can work. Using the declarations above:
<code>
my_polygon := your_polygon -- Is valid
your_polygon :=my_polygon -- Is valid
my_polygon :=my_rectangle -- Is valid
my_polygon := my_triangle -- Is valid
</code>
but
<code>
my_rectangle := my_polygon -- Is not valid
my_triangle := my_polygon -- Is not valid
</code>
and of course
<code>
my_rectangle := my_triangle -- Is not valid
</code>
Consider now the assignment below which is valid.
<code>
my_polygon := my_rectangle
</code>
After an assignment like this executes the entity <code>my_polygon</code> will be holding at runtime a reference to an instance of a type which is not a direct instance of its declared type <code>POLYGON</code>. But conformance ensures us that, although it may not be a direct instance, it will indeed by an instance. (all rectangles are polygons).
Depending upon how many different types of polygons get modeled in classes, the entity "<code>my_polygon</code>" could be attached objects of may different types ... it could take on many forms. This in fact is the basis for the term "polymorphism"; having many forms. So we speak of "polymorphic attachment" as the process by which at runtime entities can hold references to objects which are not of the entity's declared type ... but they are of conforming types.
Now let's see how we get some value from this.
===Dynamic Binding===
Suppose that one of the features of <code>POLYGON</code> is a query <code>perimeter</code> which returns an instance's perimeter. The producer of <code>POLYGON</code> may have implemented <code>perimeter</code> as a function that computes the perimeter by adding up the lengths of all the sides. This approach is guaranteed to work for all polygons, and we can apply the <code>perimeter</code> feature to any polygon. Let's print some perimeters:
<code>
print (my_polygon.perimeter)
print (my_triangle.perimeter)
print (my_rectangle.perimeter)
</code>
<code>TRIANGLE</code> and <code>RECTANGLE</code> might have properties, expressed as queries, which as a part of their specialization, distinguish them from run-of-the-mill polygons. Two features of rectangles are <code>width</code> and <code>height</code> the lengths of the sides.
Armed with these <code>RECTANGLE</code>-specific features, the producer of <code>RECTANGLE</code> may say, "Now I no longer have to depend upon that crude implementation of <code>perimeter</code> that is inherited from <code>POLYGON</code>. I can build an efficient <code>RECTANGLE</code>-specific implementation of <code>perimeter</code>, based on the knowledge that for all <code>RECTANGLE</code>s perimeter = 2*(width+height)"
To implement this specialized version of <code>perimeter</code>, the producer of <code>RECTANGLE</code> must add the feature to the class, but also must list its name in the "<code>redefine</code>" part of the <code>RECTANGLE</code>'s inheritance clause.
<code>
class
RECTANGLE
inherit
POLYGON
redefine
perimeter
end
.
.
feature
perimeter: REAL
-- Sum of lengths of all sides
do
Result := 2 * (width + height)
end
</code>
You would expect then, that this version of perimeter would be executed in the following context:
<code>
print (my_rectangle.perimeter)
</code>
But what makes this interesting is that even in the context below
<code>
my_polygon := my_rectangle
print (my_polygon.perimeter)
</code>
in which <code>perimeter</code> is being applied to a entity declared as <code>POLYGON</code>, the specialized version of <code>perimeter</code> from <code>RECTANGLE</code> is being used. It would be impossible to ensure at compile time which version of <code>perimeter</code> is most appropriate. So it must be done at runtime. This ability to choose the best version of a feature to apply, just at the moment it needs to be applied, is called "dynamic binding".
Static typing tells us at compile time that it is safe to apply <code>perimeter</code> to <code>my_polygon</code> No matter which of the types of polygons is attached to <code>my_polygon</code>, there will be a <code>perimeter</code> feature that will work.
Dynamic binding tells us that when we apply <code>perimeter</code>, we know that the most appropriate version of the feature will get applied at runtime.
===Object Test===
Now let's add another situation. Consider the code below:
<code>
my_polygon := my_rectangle
print (my_polygon.perimeter)
print (my_polygon.width) -- Is invalid
</code>
We could apply <code>perimeter</code> to <code>my_polygon</code> and everything is fine ... we even get <code>RECTANGLE</code>'s specialized version of the feature. But it is invalid for us to try to apply <code>width</code> to <code>my_polygon</code> even though we feel (with rather strong conviction) that at this point in execution, <code>my_polygon</code> will be attached to an object of type <code>RECTANGLE</code>, and we know that <code>width</code> is a valid query on <code>RECTANGLE</code>s.
The reason follows. When we declared <code>my_polygon</code> as type <code>POLYGON</code>, we made a deal that says that the only features that can be applied to <code>my_polygon</code> are the features of <code>POLYGON</code>. Remember that static typing guarantees us at compile time that at runtime there will be at least one version of the feature available that can be applied.
<code>
print (my_polygon.width) -- Is invalid
</code>
But in the case above, the guarantee cannot be made. <code>my_polygon</code> is declared with class <code>POLYGON</code> which has no <code>width</code> feature, despite the fact that some of its proper descendants might.
Does this mean that we can never do <code>RECTANGLE</code> things with this instance again, once we have attached it to <code>my_polygon</code>?
No. There is a language facility called the '''object test''' which will come to our rescue. The object test will allow us safely to attach our instance back to an entity typed as <code>RECTANGLE</code>. After doing so, we are free use <code>RECTANGLE</code> features.
<code>
my_polygon := my_rectangle
print (my_polygon.perimeter)
if attached {RECTANGLE} my_polygon as l_rect then
print (l_rect.width)
end
</code>
In this code, the entity <code>l_rect</code> is a fresh local entity produced during the object test. So, the code can be read: if at this point, <code>my_polygon</code> is attached to an instance of type <code>RECTANGLE</code>, then attach that instance to a fresh local entity named <code>l_rect</code>, then apply <code>width</code> to <code>l_rect</code> and print the result.
:'''Note:''' The object test replaces the functionality of an obsolete mechanism called assignment attempt. Assignment attempt used the syntax '''<code>?=</code>''' in the context of assignment versus the '''<code>:=</code>''' of normal assignment.

View File

@@ -0,0 +1,49 @@
[[Property:title|Referenced Assembly Type and Feature Name Conversion]]
[[Property:weight|10]]
[[Property:uuid|5d575090-35d9-f983-7308-172b1641173f]]
The [[The Eiffel for .NET language|Eiffel for .NET language]] is Eiffel. It is not a variant of Eiffel that spawned a new language, as is '''C#''', or a dramatic evolution of Eiffel, such as '''Visual Basic .NET''' is to '''VB6'''. As Eiffel stands today, and will probably remain, Eiffel's conventions for class names and features names match neither that of the OO Pascal variants nor the "Camel-casing" conventions recommended by Microsoft. Eiffel also does not support the notion of full quantified type names. The period (''''.'''') between namespace and type names is not valid Eiffel syntax. These naming convention rules pose a problem for maintaining the Eiffel programming language. To address this issue, when referencing .NET assemblies, all referenced assembly type names and feature names are converted into "Eiffel-case" when using Eiffel.
<span id="eiffel_case"></span>
==What is Eiffel-Case?==
Eiffel-casing is almost the same for both class and class feature names, all words are separated using underscores (''''_''''). The differences between them are class names are always in uppercase and feature names always in lowercase.
<eiffel>MY_CLASS</eiffel> is an example of an Eiffel-cased class name. <br/>
<eiffel>my_feature</eiffel> is an example of an Eiffel-cased feature name.
There are somewhat complex rules to ensure that the automatic formatting of .NET name, type, method, property and otherwise are formatted to the most readable name possible, given their casing convention. One absolute is that the Eiffel compilation process will remove the namespace from the fully qualified type name and format just the type name.
For example <eiffel>System.Windows.Forms.Border3DStyle</eiffel> would yield <eiffel>BORDER_3D_STYLE</eiffel>.
Stripping the namespace from the name is essential to keep type names short and usable, who wants to use <eiffel>SYSTEM_WINDOWS_FORMS_BORDER_3D_STYLE</eiffel>? Dropping the namespace does present a potential problem; assemblies may have two type that are of the same name but are located in different namespaces. A resolution to this comes in the form of assembly prefixes. For every assembly a class name prefix can be specified. Eiffel Software have reserved a set of assembly prefix pairs which should not be change as they are used by the Eiffel class libraries. For example, ''System.Windows.Forms.dll'' contains a commonly used type called <eiffel>System.Windows.Forms.Form</eiffel>. During the compilation process ''System.Windows.Forms.dll'' will be evaluated and <eiffel>System.Windows.Forms.Form</eiffel> will yield the <eiffel>FORM</eiffel> Eiffel class name. ''System.Windows.Forms.dll'' has been assigned the '<eiffel>WINFORMS_</eiffel>' prefix, so <eiffel>FORM</eiffel> would actually be <eiffel>WINFORMS_FORM</eiffel> instead.
<span id="prefixes"></span>
==Reserved Prefixes==
The following table displays the fixed assembly class name prefixes, assigned by Eiffel Software, for the Microsoft Foundation Class Libraries:
{|
|-
| mscorlib.dll
| No Prefix
|-
| System.dll
| <eiffel>SYSTEM_DLL_</eiffel>
|-
| System.XML.dll
| <eiffel>XML_</eiffel>
|-
| System.Data.dll
| <eiffel>DATA_</eiffel>
|-
| System.Web.dll
| <eiffel>WEB_</eiffel>
|-
| System.EnterpriseServices.dll
| <eiffel>ENTERPRISE_</eiffel>
|-
| System.Windows.Forms.dll
| <eiffel>WINFORMS_</eiffel>
|}

View File

@@ -0,0 +1,16 @@
[[Property:title|Using Referenced Assemblies]]
[[Property:weight|8]]
[[Property:uuid|acbe0407-b95e-6268-fc20-238f91df595e]]
Eiffel for.NET is a first class citizen in the Microsoft.NET programming world. This means that if you are programming in Eiffel for.NET, you have full access to the thousands of software components in the .NET type libraries. But, that's not all. You also have full access to the thousands of components in the traditional Eiffel class libraries. And even that's not all. You have the ability to build software components which comply with.NET standards, so that they can be used by programmers using any other .NET language. Still not all. When you use Eiffel, you can choose to build software that will run under Microsoft.NET, but will be portable to other popular operating systems as well.
Being an Eiffel for.NET programmer obviously put you in a very powerful position. How do you take advantage of it?
To use.NET software components from Eiffel for.NET requires you to have some understanding of both.NET and Eiffel and how their respective object models differ. If you have read the rest of the help topics in [[Eiffel for .NET|this section]] then you have a pretty good idea of what the Eiffel method and language are all about.
When you begin to build software in Eiffel for.NET, you will likely find a need to reuse types from the.NET libraries. These libraries are called assemblies. When you reference a assembly using Eiffel for.NET, the types in the assembly become available to you in a form that makes them look like so many Eiffel classes. The names for types and members will conform to Eiffel conventions. The same thing happens when you are programming against assemblies in Visual Basic.NET or Visual C#.NET.
The section called [[Conventions]] covers the details the Eiffel conventions and how the.NET types are made available to Eiffel for.NET programmers.