Difference between revisions of "Expanded or reference"

From Liberty Eiffel Wiki
Jump to navigation Jump to search
 
m
 
(26 intermediate revisions by 4 users not shown)
Line 1: Line 1:
[[Category:Book]]
 
 
*** Translation in progress: Oliver Elphick 6/11/2005 ***
 
 
 
In our opinion, it is essential to have a good understanding of how objects are represented in memory while an application is running.
 
In our opinion, it is essential to have a good understanding of how objects are represented in memory while an application is running.
 
The aim is not to make every one of us an expert in the subject, but
 
The aim is not to make every one of us an expert in the subject, but
 
more simply to have sufficient knowledge to be able to make design choices.
 
more simply to have sufficient knowledge to be able to make design choices.
Besides, it is often essential to be able to design(?) objects in memory so as to be able to explain or think about the design of a new class.
+
Besides, it is often essential to be able to draw how objects appear in memory so as to be able to explain or think about the design of a new class.
 
The section which explains
 
The section which explains
 
[[#ExpandedBasics|the two categories of objects]] which exist during execution is essential.
 
[[#ExpandedBasics|the two categories of objects]] which exist during execution is essential.
Line 18: Line 14:
 
This too needs to be understood.
 
This too needs to be understood.
   
The last section is only of interest to those rare users who wish to define their
+
The last section is only of interest to those few users who wish to define their
 
[[#AvoidExpandedPitfall|own <tt>expanded</tt> class]].
 
[[#AvoidExpandedPitfall|own <tt>expanded</tt> class]].
 
This section can be skipped by most beginners.
 
This section can be skipped by most beginners.
Line 25: Line 21:
 
==<tt>Expanded</tt> or reference objects, the choice==
 
==<tt>Expanded</tt> or reference objects, the choice==
 
</div>
 
</div>
The objects that one manipulates during the execution of an Eiffel
+
The objects that are handled during the execution of an Eiffel
program are manipulated either with an intermediate reference or without one.
+
program are handled either with or without an intermediate reference.
 
Furthermore, when an object is handled through a reference, it can be handled only through a reference.
 
Furthermore, when an object is handled through a reference, it can be handled only through a reference.
 
In the same way, when an object is handled without a reference, it can only be handled in that way, that is to say without any intermediate reference.
 
In the same way, when an object is handled without a reference, it can only be handled in that way, that is to say without any intermediate reference.
Line 35: Line 31:
 
In this case, the class in question begins with the keyword
 
In this case, the class in question begins with the keyword
 
[[Syntax diagrams#ClassDeclaration|<tt>expanded</tt>]].
 
[[Syntax diagrams#ClassDeclaration|<tt>expanded</tt>]].
In Eiffel jargon, when we speak of an<tt>expanded</tt> class,
+
In Eiffel jargon, when we speak of an <tt>expanded</tt> class,
we are talking about a class whose objects are handled without an intermediate pointer, objects that are directly written, or ''expanded'', onto the memory area that they use.
+
we are talking about a class whose objects are handled without an intermediate pointer, objects that are directly written, or ''expanded'', onto the memory area that they use I. e. they are passed by value.
 
In contrast, if we talk of a ''reference class'' or of a ''reference type'', it is to emphasise that the objects in question are not <tt>expanded</tt>.
 
In contrast, if we talk of a ''reference class'' or of a ''reference type'', it is to emphasise that the objects in question are not <tt>expanded</tt>.
   
  +
The chief point of this dichotomy is to make it possible to integrate the most basic entities into the object model.
L'intérêt principal de cette dichotomie est de pouvoir intégrer les entités les plus
 
  +
For example, a boolean value of the
élémentaires dans le modèle objet.
 
  +
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]] class corresponds to an <tt>expanded</tt> object.
Par exemple, une valeur booléenne de la classe
 
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]] correspond à un objet <tt>expanded</tt>.
+
Similarly, the classes [[library_class:INTEGER|<tt>INTEGER</tt>]]
De même, les classes [[library_class:INTEGER|<tt>INTEGER</tt>]]
+
and [[library_class:REAL|<tt>REAL</tt>]] are also <tt>expanded</tt>.
  +
The following diagram shows what happens in memory; the classes
et [[library_class:REAL|<tt>REAL</tt>]] sont également <tt>expanded</tt>.
 
  +
<tt>POINT</tt> and <tt>TRIANGLE</tt> are ordinary classes, that is to say classes defined without the keyword <tt>expanded</tt>:
La figure suivante montre se qui se passe en mémoire sachant que les classes
 
<tt>POINT</tt> et <tt>TRIANGLE</tt> sont des classes ordinaires, c'est à dire
 
des classes définies sans le mot clef <tt>expanded</tt>&nbsp;:
 
   
[[Image:ExpandedVsReferenceBoolean.png|Schéma mémoire expanded vs référence]]
+
[[Image:ExpandedVsReferenceBoolean.png|Expanded vs reference memory structure]]
   
Pour la figure qui précède, la variable nommée <tt>a_boolean</tt> est
+
In the figure above, the variable called <tt>a_boolean</tt> is declared as type [[library_class:BOOLEAN|<tt>BOOLEAN</tt>]].
déclarée de type [[library_class:BOOLEAN|<tt>BOOLEAN</tt>]].
+
Since the [[library_class:BOOLEAN|<tt>BOOLEAN</tt>]] class is <tt>expanded</tt>,
  +
the corresponding object is directly assigned to the memory area associated with the variable <tt>a_boolean</tt>.
Comme la classe [[library_class:BOOLEAN|<tt>BOOLEAN</tt>]] est <tt>expanded</tt>,
 
  +
As the diagram shows, the <tt>a_boolean</tt> variable currently contains an object <tt>True</tt> which corresponds to the boolean value true.
l'objet correspondant est directement rangé dans l'espace mémoire
 
  +
In the same way, the memory area associated with the variable <tt>a_integer</tt> of type [[library_class:INTEGER|<tt>INTEGER</tt>]] directly contains the object corresponding to the value <tt>1</tt> since the [[library_class:INTEGER|<tt>INTEGER</tt>]] class is also <tt>expanded</tt>.
associé à la variable <tt>a_boolean</tt>.
 
  +
Finally, the variable <tt>a_real</tt> declared in the example as type [[library_class:REAL|<tt>REAL</tt>]] also directly contains the value <tt>1.0</tt>.
Comme le montre le schéma, la variable <tt>a_boolean</tt> contient actuellement
 
un objet <tt>True</tt> qui correspond à la valeur booléenne vrai.
 
De même, l'espace mémoire associé à la variable <tt>a_integer</tt>
 
de type [[library_class:INTEGER|<tt>INTEGER</tt>]] contient
 
directement l'objet correspondant à la valeur <tt>1</tt> car la classe
 
[[library_class:INTEGER|<tt>INTEGER</tt>]] est également <tt>expanded</tt>.
 
Enfin, la variable <tt>a_real</tt> déclaré dans l'exemple
 
de type [[library_class:REAL|<tt>REAL</tt>]] contient elle aussi directement
 
la valeur <tt>1.0</tt>.
 
   
Toujours dans la figure qui précède, la variable <tt>point</tt> est déclarée
+
In the diagram above, the variable <tt>point</tt> is declared as type <tt>POINT</tt>.
  +
Since we are not dealing with an <tt>expanded</tt> class, the memory area associated with the variable <tt>point</tt> does not directly contain the <tt>POINT</tt> object, but a pointer to that object.
de type <tt>POINT</tt>.
 
  +
Thus the <tt>point</tt> variable does not directly contain an object of the <tt>POINT</tt> class; the <tt>point</tt> variable ''references'' a <tt>POINT</tt> object.
Comme il ne s'agit pas d'une classe <tt>expanded</tt>, l'espace mémoire associé
 
  +
Note that the diagram also shows us that each object of class <tt>POINT</tt> is itself made up of two [[Glossary#Attribute|attributes]] <tt>x</tt> and <tt>y</tt> whose type is [[library_class:REAL|<tt>REAL</tt>]].
à la variable <tt>point</tt> ne contient pas directement l'objet de la classe
 
  +
As in the case of the <tt>point</tt> variable, the variable <tt>triangle</tt> is a reference to an object of the class <tt>TRIANGLE</tt> since the <tt>TRIANGLE</tt> class is an ordinary class, not <tt>expanded</tt>.
<tt>POINT</tt>, mais un pointeur vers cet objet.
 
  +
Since the [[Glossary#Attribute|attributes]] <tt>p1</tt>, <tt>p2</tt> and <tt>p3</tt> are of the <tt>POINT</tt> type, in this case there are also pointers to the corresponding objects.
Ainsi, la variable <tt>point</tt> ne contient pas directement un objet de la classe
 
<tt>POINT</tt>; la variable <tt>point</tt> ''référence'' un objet de la classe
 
<tt>POINT</tt>.
 
Notons que la figure nous montre également que chaque objet de la classe <tt>POINT</tt>
 
est lui-même composé de deux [[Glossary#Attribute|attributs]]
 
<tt>x</tt> et <tt>y</tt> dont le type est
 
[[library_class:REAL|<tt>REAL</tt>]].
 
Comme dans le cas de la variable <tt>point</tt>, la variable <tt>triangle</tt>
 
est une référence vers un objet de la classe <tt>TRIANGLE</tt> car la classe
 
<tt>TRIANGLE</tt> est une classe ordinaire, non <tt>expanded</tt>.
 
Comme les [[Glossary#Attribute|attributs]] <tt>p1</tt>, <tt>p2</tt> et <tt>p3</tt> sont de
 
type <tt>POINT</tt>, il y a aussi dans ce cas des pointeurs vers les objets correspondants.
 
   
  +
Whether or not an object is <tt>expanded</tt>, the syntax used to declare it is the same. The fact that a class is <tt>expanded</tt> or not depends only on the [[Syntax diagrams#ClassDeclaration|class definition]] itself.
Qu'un objet soit <tt>expanded</tt> ou pas, la syntaxe utilisée pour la déclaration est la
 
  +
For example, the declaration of the variables <tt>a_boolean</tt>, <tt>a_integer</tt>, <tt>a_real</tt>,
même.
 
  +
<tt>point</tt> and <tt>triangle</tt> corresponds to the following Eiffel code:
Le fait qu'une classe soit <tt>expanded</tt> ou pas dépend uniquement de la
 
[[Syntax diagrams#ClassDeclaration|définition de la classe]] elle même.
 
Par exemple, la déclaration des variables <tt>a_boolean</tt>, <tt>a_integer</tt>, <tt>a_real</tt>,
 
<tt>point</tt> et <tt>triangle</tt> correspond au code Eiffel suivant&nbsp;:
 
   
 
a_boolean: BOOLEAN; a_integer: INTEGER; a_real: REAL; point: POINT; triangle: TRIANGLE
 
a_boolean: BOOLEAN; a_integer: INTEGER; a_real: REAL; point: POINT; triangle: TRIANGLE
   
Que l'on manipule un objet <tt>expanded</tt> ou pas, la notation est également
+
Whether or not one is dealing with an <tt>expanded</tt> object, the notation is just the same.
  +
For example, the following [[Glossary#Instruction|instruction]] copies into the variable <tt>a_real</tt> the value of the attribute <tt>y</tt> of the <tt>POINT</tt> object referenced by the variable <tt>point</tt>:
la même.
 
Par exemple, [[Glossary#Instruction|l'instruction]] suivante permet de recopier dans
 
la variable <tt>a_real</tt> ce qui se trouve dans l'attribut <tt>x</tt> du <tt>POINT</tt> qui
 
est actuellement référencé par la variable <tt>point</tt>&nbsp;:
 
   
 
a_real := point.y
 
a_real := point.y
   
  +
The following [[Glossary#Instruction|instruction]] copies the pointer which points to the same <tt>POINT</tt> as the one referenced by the <tt>p1</tt> attribute of the <tt>TRIANGLE</tt> which is itself referenced by the variable <tt>triangle</tt>:
[[Glossary#Instruction|L'instruction]] suivante permet de recopier le pointeur qui désigne le
 
même <tt>POINT</tt> que celui qui est référencé par l'attribut <tt>p1</tt> du
 
<tt>TRIANGLE</tt> qui est lui même référencé par la variable
 
<tt>triangle</tt>&nbsp;:
 
   
 
point := triangle.p1
 
point := triangle.p1
   
  +
Without going into [[Assignment|all the details of assignments]], the effect of those two instructions in relation to the memory diagram above is to produce this memory configuration:
Sans vouloir présenter ici
 
[[Assignment|tous les détails concernant l'affectation]], l'effet des deux
 
instructions précédentes conduit, par rapport au schéma mémoire précédent, à la configuration
 
mémoire que voici&nbsp;:
 
   
[[Image:ExpandedVsReferenceBooleanBis.png|Schéma mémoire expanded vs référence]]
+
[[Image:ExpandedVsReferenceBooleanBis.png|Expanded vs reference memory structure]]
   
  +
Applying a method to an <tt>expanded</tt> object uses the same syntax as for an ordinary (not <tt>expanded</tt>) object.
L'application d'une méthode sur un objet <tt>expanded</tt> utilise la même syntaxe que
 
  +
For example the following [[Glossary#Instruction|instruction]] applies the <tt>sqrt</tt> [[Glossary#Function|function]] to the [[library_class:INTEGER|<tt>INTEGER</tt>]] class object which is stored directly in the memory area associated with the variable <tt>a_integer</tt>.
pour un objet ordinaire (non <tt>expanded</tt>).
 
  +
The result of calling the <tt>sqrt</tt> function is a <tt>REAL</tt> which overwrites the old object which was formerly stored directly in the variable <tt>a_real</tt>:
Par exemple, [[Glossary#Instruction|l'instruction]] suivante permet d'appliquer la
 
[[Glossary#Function|fonction]] <tt>sqrt</tt> sur l'objet de la classe
 
[[library_class:INTEGER|<tt>INTEGER</tt>]] qui est directement mémorisé dans l'espace
 
associé à la variable <tt>a_integer</tt>.
 
Le résultat de l'appel de la fonction <tt>sqrt</tt> est un <tt>REAL</tt> qui vient écraser
 
l'ancien objet préalablement mémorisé directement dans la variable <tt>a_real</tt>&nbsp;:
 
 
 
 
a_real := a_integer.sqrt
 
a_real := a_integer.sqrt
   
  +
Having identical notation for handling ordinary (referenced) and <tt>expanded</tt> (not referenced) objects simplifies programming and provides consistency.
Le fait d'avoir une notation identique pour manipuler objets ordinaires (avec référence) et
 
les objets <tt>expanded</tt> (sans référence) permet de simplifier et d'uniformiser l'écriture
 
des programmes.
 
   
  +
Being able to describe basic objects by a proper class is an important aid to consistency.
Pouvoir décrire les objets élementaires à l'aide d'une véritable classe constitue
 
  +
A simple object, such as a 32 bit signed integer, is described by a proper class, the [[library_class:INTEGER|<tt>INTEGER</tt>]] class.
un avantage important qui va également dans le sens de l'uniformisation.
 
  +
As with any class, it is possible to change or adapt the methods in the
Un objet simple comme un entier signé sur 32 bits est décrit par une véritable classe,
 
la classe [[library_class:INTEGER|<tt>INTEGER</tt>]].
+
[[library_class:INTEGER|<tt>INTEGER</tt>]] class.
  +
Of course, nearly all users only consult the list of available methods.
Comme dans n'importe quelle classe il est possible de changer ou d'ajouter des méthodes dans la
 
classe [[library_class:INTEGER|<tt>INTEGER</tt>]].
+
Since the [[library_class:INTEGER|<tt>INTEGER</tt>]] class is used by almost every program, altering it is more and more an uncommon event, and must be done with care.
  +
Nevertheless, having a proper class lets users look up the list of available methods for [[library_class:INTEGER|<tt>INTEGER</tt>]] in the same way as they can for all other classes.
Bien entendu, la très grande majorité des utilisateurs ne fait que consulter la liste des méthodes
 
disponibles.
 
La classe [[library_class:INTEGER|<tt>INTEGER</tt>]] étant utilisée par la quasi-totalité des
 
programmes, il faut, ce qui arrive de plus en plus rarement, la modifier avec précaution.
 
Ceci étant, le fait d'avoir une véritable classe permet aux utilisateurs de consulter la liste
 
des méthodes disponibles pour les [[library_class:INTEGER|<tt>INTEGER</tt>]] de la même
 
fa&ccedil;on qu'on le fait pour toutes les autres classes.
 
   
  +
Among the predefined <tt>expanded</tt> classes corresponding to basic objects that must be familiar to all users are:
Parmi les classes <tt>expanded</tt> prédéfinies correspondant à des objets élémentaires,
 
  +
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]],
devant être connues de tous les utilisateurs, citons&nbsp;:
 
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]]
+
[[library_class:INTEGER|<tt>INTEGER</tt>]],
[[library_class:INTEGER|<tt>INTEGER</tt>]]
 
 
[[library_class:REAL|<tt>REAL</tt>]]
 
[[library_class:REAL|<tt>REAL</tt>]]
  +
and
et
 
 
[[library_class:CHARACTER|<tt>CHARACTER</tt>]].
 
[[library_class:CHARACTER|<tt>CHARACTER</tt>]].
Un utilisateur averti devra aussi avoir connaissance des classes <tt>expanded</tt>
+
A well-informed user should also be familiar with the following <tt>expanded</tt> classes:
suivantes&nbsp;:
 
 
[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
 
[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
 
[[library_class:INTEGER_16|<tt>INTEGER_16</tt>]],
 
[[library_class:INTEGER_16|<tt>INTEGER_16</tt>]],
Line 162: Line 110:
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
 
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]]
 
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]]
et enfin, pour les plus curieux les classes [[library_class:POINTER|<tt>POINTER</tt>]]
+
and finally, for the most curious, there are the classes [[library_class:POINTER|<tt>POINTER</tt>]]
et [[library_class:NATIVE_ARRAY|<tt>NATIVE_ARRAY</tt>]].
+
and [[library_class:NATIVE_ARRAY|<tt>NATIVE_ARRAY</tt>]].
   
 
<div id="ExpandedProperties">
 
<div id="ExpandedProperties">
   
==Principales caractéristiques des expressions de type <tt>expanded</tt>==
+
==Principal characteristics of <tt>expanded</tt> type expressions==
 
</div>
 
</div>
Une [[Glossary#Expression|expression]] dont le type est expanded présente des
+
An expanded type [[Glossary#Expression|expression]] has
  +
properties which one needs to know about.
propriétés qu'il est bon de connaître.
 
  +
As explained above, the object that corresponds to an
Comme expliqué précédemment l'objet qui correspond à une
 
[[Glossary#Expression|expression]]
+
<tt>expanded</tt> type [[Glossary#Expression|expression]] cannot be referenced.
  +
No other location can directly designate the object in question; in particular no pointer can point to it.
<tt>expanded</tt> ne peut pas être référencé.
 
  +
So if, for example, one is dealing with a variable of type
Aucun autre endroit ne peut désigner directement l'objet en question,
 
  +
[[library_class:INTEGER|<tt>INTEGER</tt>]], the only way of operating on the corresponding object is to use the variable in question.
en particulier par l'intermédiaire d'un pointeur.
 
Ainsi, si l'on dispose par exemple d'une variable de type
 
[[library_class:INTEGER|<tt>INTEGER</tt>]], la seule fa&ccedil;on d'intervenir
 
sur l'objet correspondant implique de pouvoir utiliser la variable en
 
question.
 
   
Une [[Glossary#Expression|expression]] de type <tt>expanded</tt> désigne
+
An <tt>expanded</tt> type [[Glossary#Expression|expression]] always designates an object.
  +
In other words, an <tt>expanded</tt> expression is never [[Void|<tt>Void</tt>]].
toujours un objet.
 
  +
What is more, an <tt>expanded</tt> type [[Glossary#Expression|expression]] always corresponds to one and only one category of object.
Autrement dit, une expression <tt>expanded</tt> n'est jamais [[Void|<tt>Void</tt>]].
 
  +
In consequence, [[Dynamic dispatch|dynamic dispatch]] is never involved when an <tt>expanded</tt> object is the target of a call (that is, on the left of a dot).
Qui plus est, une expression de type <tt>expanded</tt> correspond toujours
 
  +
The invocation of a [[Glossary#Method|method]] with an <tt>expanded</tt> object as target corresponds to the most efficient possible direct call.
à une et une seule catégorie d'objet.
 
Par conséquent, il n'y a jamais de [[Dynamic dispatch|liaison dynamique]] en cas d'utilisation
 
d'un objet <tt>expanded</tt> comme cible d'un appel (i.e. à gauche du point).
 
L'invocation d'une [[Glossary#Method|méthode]] avec un objet <tt>expanded</tt> comme
 
cible correspond à un appel direct aussi efficace que possible.
 
   
  +
Without going into too much detail, since dynamic dispatch is not possible with an <tt>expanded</tt> object, it is useless to give such an object the information that lets you find its [[Glossary#DynamicType|dynamic type]].
Sans entrer trop dans les détails, comme la liaison dynamique n'est pas possible avec
 
  +
Thus, the memory space required for an <tt>expanded</tt> object is limited exactly to that needed to accommodate its different [[Glossary#Attribute|attributes]].
un objet <tt>expanded</tt>, il est inutile d'équiper un tel objet avec une
 
information permettant de retrouver le [[Glossary#DynamicType|type dynamique]].
 
Ainsi, la place mémoire pour un objet <tt>expanded</tt> se limite très exactement à la place
 
mémoire pour ranger ses différents [[Glossary#Attribute|attributs]].
 
   
 
<div id="AutomaticInitialization">
 
<div id="AutomaticInitialization">
   
==Initialisation des variables et attributs==
+
==Initialisation of variables and attributes==
 
</div>
 
</div>
En Eiffel, toutes les variables sont toujours initialisées automatiquement.
+
In Eiffel, all variables are always initialised automatically.
Ceci concerne toutes les sortes de variables&nbsp;:
+
This is the same for all kinds of variables:
[[Glossary#InstanceVariable|variables d'instances]],
+
[[Glossary#InstanceVariable|instance variables]],
[[Syntax diagrams#Routine|variables locales]] ainsi que la
+
[[Syntax diagrams#Routine|local variables]] and the
variable [[Syntax diagrams#Result|<tt>Result</tt>]] qui sert à préparer le
+
variable [[Syntax diagrams#Result|<tt>Result</tt>]] which is used to hold the result of a function.
  +
The way in which a variable is initialised depends entirely on its declaration type, which is either reference or <tt>expanded</tt>.
résultat d'une fonction.
 
La fa&ccedil;on d'initialiser la variable dépend uniquement de son type de
 
déclaration qui est soit un type référence soit un type <tt>expanded</tt>.
 
   
===Initialisation des variables de type référence===
+
===Initialisation of reference type variables===
   
Une variable dont le type est un ''type référence'' est toujours
+
A variable whose type is a ''reference type'' is always automatically initialised with [[Void|<tt>Void</tt>]].
  +
For example, if you declare a variable of type
initialisée automatiquement avec [[Void|<tt>Void</tt>]].
 
  +
<tt>POINT</tt> or type <tt>TRIANGLE</tt>, the non-<tt>expanded</tt> classes of the example above, the variable is automatically initialised with [[Void|<tt>Void</tt>]].
Par exemple, si on déclare une variable de type
 
  +
For reference types, an object is never automatically created following the declaration of a variable.
<tt>POINT</tt> ou de type <tt>TRIANGLE</tt>, les classes non <tt>expanded</tt> de l'exemple
 
utilisé précédemment, la variable est automatiquement initialisée
 
avec [[Void|<tt>Void</tt>]].
 
Pour les types référence, il n'y a jamais de création automatique d'objet suite à la
 
déclaration d'une variable.
 
   
  +
Among the standard classes that correspond to reference types, let us consider the [[library_class:STRING|<tt>STRING</tt>]] class.
Parmi les classes ordinaire usuelles, classes correspondant à un type référence, citons
 
  +
This class is in no way a special case.
la classe [[library_class:STRING|<tt>STRING</tt>]].
 
  +
A variable declared to be of type [[library_class:STRING|<tt>STRING</tt>]] is automatically initialised with [[Void|<tt>Void</tt>]].
Pas de cas particulier pour cette classe.
 
Une variable déclarée de type [[library_class:STRING|<tt>STRING</tt>]] est automatiquement
+
No object of the [[library_class:STRING|<tt>STRING</tt>]] class is created when a [[library_class:STRING|<tt>STRING</tt>]] type variable is declared.
  +
To take another common example, declaring a variable of type [[library_class:ARRAY|<tt>ARRAY[INTEGER]</tt>]] does not lead to the automatic creation of a table of <tt>INTEGER</tt>s, because the class [[library_class:ARRAY|<tt>ARRAY</tt>]] itself is still not an <tt>expanded</tt> class.
initialisée avec [[Void|<tt>Void</tt>]].
 
  +
So this simple initialisation rule applies to the majority of classes, which, it should be remembered, are ordinary, non-<tt>expanded</tt> classes.
Aucun objet de la classe [[library_class:STRING|<tt>STRING</tt>]] n'est crée
 
lors de la déclaration d'une variable dont le type est
 
[[library_class:STRING|<tt>STRING</tt>]].
 
Pour prendre un autre exemple courant, une variable déclarée avec le type
 
[[library_class:ARRAY|<tt>ARRAY[INTEGER]</tt>]] ne provoque pas, lui non
 
plus, la création automatique d'un tableau d'<tt>INTEGER</tt>s car la classe
 
[[library_class:ARRAY|<tt>ARRAY</tt>]] elle même est bien une classe
 
non <tt>expanded</tt>.
 
Ainsi, cette règle d'initialisation simple s'applique à la majeure parties des
 
classes qui, rappellons le, sont des classes ordinaire, des classes
 
non <tt>expanded</tt>.
 
   
   
===Initialisation des variables de type <tt>expanded</tt>===
+
===Initialisation of <tt>expanded</tt> type variables===
Les variables dont le type est <tt>expanded</tt> sont également initialisées
+
Variables whose type is <tt>expanded</tt> are initialised automatically.
  +
For certain truly basic <tt>expanded</tt> types, the initialisation is done directly by the compiler.
automatiquement.
 
  +
After presenting all these special cases, we will deal with the general case of an <tt>expanded</tt> class.
Pour certains types <tt>expanded</tt> véritablement élémentaires, l'initialisation
 
est prise en compte directement par le compilateur.
 
Après avoir présenté tous ces cas particuliers, le cas général d'une classe <tt>expanded</tt>
 
sera traité.
 
   
Pour la famille des <tt>INTEGER</tt>s, c'est à dire pour l'ensemble
+
For the family of <tt>INTEGER</tt>s, that is to say all the following types,
des types suivants,
 
 
<tt>{</tt>[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
 
<tt>{</tt>[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
 
[[library_class:INTEGER_16|<tt>INTEGER_16</tt>]],
 
[[library_class:INTEGER_16|<tt>INTEGER_16</tt>]],
Line 254: Line 171:
 
[[library_class:INTEGER|<tt>INTEGER</tt>]],
 
[[library_class:INTEGER|<tt>INTEGER</tt>]],
 
[[library_class:INTEGER_64|<tt>INTEGER_64</tt>]]<tt>}</tt>,
 
[[library_class:INTEGER_64|<tt>INTEGER_64</tt>]]<tt>}</tt>,
  +
or <tt>NATURAL</tt>s <tt>{</tt>[[library_class:NATURAL_8|<tt>NATURAL_8</tt>]],
l'objet servant à initialiser correspond à la valeur <tt>0</tt>.
 
  +
[[library_class:NATURAL_16|<tt>NATURAL_16</tt>]],
  +
[[library_class:NATURAL_32|<tt>NATURAL_32</tt>]],
  +
[[library_class:NATURAL|<tt>NATURAL</tt>]],
  +
[[library_class:NATURAL_64|<tt>NATURAL_64</tt>]]<tt>}</tt>
  +
the object used to initialise them corresponds to the value <tt>0</tt>.
   
  +
For the group of types
Pour l'ensemble des types
 
 
<tt>{</tt>[[library_class:REAL_32|<tt>REAL_32</tt>]],
 
<tt>{</tt>[[library_class:REAL_32|<tt>REAL_32</tt>]],
 
[[library_class:REAL_64|<tt>REAL_64</tt>]],
 
[[library_class:REAL_64|<tt>REAL_64</tt>]],
Line 263: Line 185:
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
 
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]]<tt>}</tt>,
 
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]]<tt>}</tt>,
l'objet servant à initialiser les variables correspond à la valeur <tt>0.0</tt>.
+
the object used to initialise them corresponds to the value <tt>0.0</tt>.
   
  +
For the
Pour le type
 
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]],
+
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]] type,
c'est la valeur <tt>False</tt> qui sert à initialiser.
+
the value <tt>False</tt> is used to initialise an object.
   
  +
For the
Pour le type
 
[[library_class:CHARACTER|<tt>CHARACTER</tt>]], c'est le caractère
+
[[library_class:CHARACTER|<tt>CHARACTER</tt>]] type, the character with the ASCII code 0 is used to initialise it. This character is denoted by <tt>'%U'</tt> in Eiffel.
dont le code ascii est 0 qui sert à initialiser.
 
Ce caractère se note <tt>'%U'</tt> en Eiffel.
 
   
  +
For the
Pour le type
 
[[library_class:POINTER|<tt>POINTER</tt>]],
+
[[library_class:POINTER|<tt>POINTER</tt>]] type,
l'initialisation des variables est faites avec la valeur machine permettant de
+
variable initialisation is done with the machine value that represents the <tt>null</tt> pointer.
  +
Since this value is not in normal use, there is no Eiffel notation for it. It is necessary to use the <tt>is_null</tt> method of the [[library_class:POINTER|<tt>POINTER</tt>]] class to test whether an expression of this type corresponds to the <tt>null</tt> value.
représenter le pointeur <tt>null</tt>.
 
Comme cette valeur n'est pas d'un usage courant,
 
il n'existe pas de notation Eiffel pour dénoter cette valeur.
 
Il faut utiliser la méthode <tt>is_null</tt> de la classe
 
[[library_class:POINTER|<tt>POINTER</tt>]] pour tester le fait qu'une expression
 
de ce type correspond à la valeur <tt>null</tt>.
 
   
  +
In the general case, that is to say for an <tt>expanded</tt> class that is not one of the special cases above, the initialisation is programmed by the class designer. In fact, an <tt>expanded</tt> class must either have no creation clause, or '''one and only one of its constructors must have no arguments'''. This creation procedure is automatically run to effect initialisation.
Dans le cas général, c'est à dire pour une classe <tt>expanded</tt> ne faisant pas partie des cas
 
particuliers précédents, l'initialisation est programmé par le concepteur de la classe.
 
En fait, une classe <tt>expanded</tt> doit avoir '''un et un seul constructeur sans argument'''.
 
C'est cette procédure de création qui est déclenchée automatiquement pour réaliser
 
l'initialisation.
 
   
 
<div id="AvoidExpandedPitfall">
 
<div id="AvoidExpandedPitfall">
  +
==Quelques conseils avant d'écrire une classe <tt>expanded</tt>==
 
  +
==Some advice before you write an <tt>expanded</tt> class==
 
</div>
 
</div>
En général, il n'est pas utile de définir de nouvelles classes <tt>expanded</tt>
+
In general, it is not useful to define new <tt>expanded</tt> classes
et ceci pour la très grande majorité des applications.
+
and this applies to the great majority of applications.
  +
As we have explained above, the principal use of <tt>expanded</tt> classes is to make it possible to integrate the most basic objects into the object model.
Comme nous l'avons présenté dans ce qui précède, l'intérêt principal des classes
 
  +
Having said that, it can perhaps be useful to resort to an <tt>expanded</tt> class, either to [[#RoutineTank|group utility routines]], or to economise on memory in the special case when a [[#ManySmallObjects|large number of small objects]] is used.
<tt>expanded</tt> est de pouvoir intégrer les objets les plus élémentaires dans
 
  +
Finally, we will present the [[#ExpandedPitfalls|traps to avoid]] when designing an <tt>expanded</tt> class.
le modèle objet.
 
Ceci étant dit, il peut être utile de recourir à une classe <tt>expanded</tt>
 
soit pour mettre à disposition un
 
[[#RoutineTank|ensemble de routines utilitaires]], soit pour
 
économiser de la mémoire dans le cas particulier de l'utilisation d'un
 
[[#ManySmallObjects|très grand nombre d'objets]] de petites tailles.
 
Enfin, pour finir, nous présenterons
 
[[#ExpandedPitfalls|les pièges à eviter]]
 
lors de la conception d'une classe <tt>expanded</tt>.
 
   
 
<div id="RoutineTank">
 
<div id="RoutineTank">
===Regroupement d'un ensemble de routines===
+
===Grouping a collection of routines===
 
</div>
 
</div>
  +
With an object-oriented language, it is always most convenient, if possible, to put the object-handling methods directly in the class of the objects to be handled.
Avec un langage à objets, il convient toujours, quand cela est possible,
 
  +
In certain very special cases, it is not desirable, nor even possible, to keep to this basic rule.
de placer les méthodes de manipulation des objets directement dans la classe des objets
 
  +
que l'on manipule.
 
  +
The [[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]] class is a good example of an <tt>expanded</tt> class intended for grouping some [[Glossary#Routine|routines]] which cannot be placed directly in the classes that correspond to the idea of a
Dans certains cas bien particulier, il n'est pas souhaitable ni même possible de respecter
 
cette règle de base.
 
La classe
 
[[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]] est un bon
 
exemple d'utilisation d'une classe <tt>expanded</tt> afin de regrouper des
 
[[Glossary#Routine|routines]] qui ne peuvent pas être rangées
 
directement dans les classes correspondant à la notion de
 
 
[[library_class:COLLECTION|<tt>COLLECTION</tt>]].
 
[[library_class:COLLECTION|<tt>COLLECTION</tt>]].
   
En effet, bien que toutes les routines de la classe
+
Although all the routines of the
 
[[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]]
 
[[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]]
  +
class are used for sorting objects from the
servent en fait à trier des objets de la famille des
 
[[library_class:COLLECTION|<tt>COLLECTION</tt>]]s, il n'est pas possible de
+
[[library_class:COLLECTION|<tt>COLLECTION</tt>]]s family, it is not possible to put these methods directly into the [[library_class:COLLECTION|<tt>COLLECTION</tt>]] class.
  +
This is not possible for the simple reason that not all [[library_class:COLLECTION|<tt>COLLECTION</tt>]]s can be sorted.
mettre ces méthodes directement dans
 
la classe [[library_class:COLLECTION|<tt>COLLECTION</tt>]].
+
Only [[library_class:COLLECTION|<tt>COLLECTION</tt>]]s whose elements are [[library_class:COMPARABLE|<tt>COMPARABLE</tt>]] can be sorted.
  +
So the [[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]]
Ceci n'est pas possible pour la raison simple que toutes les
 
  +
class lets us add this extra generic constraint.
[[library_class:COLLECTION|<tt>COLLECTION</tt>]]s ne peuvent pas être triées.
 
Seules les [[library_class:COLLECTION|<tt>COLLECTION</tt>]]s dont les élements
+
The [[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]] class does not have any attribute; it is just a holder for methods.
  +
Furthermore, this class is expanded. So, to sort a whole table, for example, you can proceed in the following manner:
sont [[library_class:COMPARABLE|<tt>COMPARABLE</tt>]] peuvent êtres triées.
 
Ainsi, la classe [[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]]
 
permet d'ajouter cette contrainte générique supplémentaire.
 
La classe [[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER</tt>]]
 
ne comporte aucun attribut; ce n'est en fait qu'un réservoir à méthodes.
 
En outre, cette classe est <tt>expanded</tt>.
 
Ainsi, pour trier par exemple un tableau d'entier on peut procéder de la
 
manière suivante&nbsp;:
 
 
local
 
local
 
sorter: COLLECTION_SORTER[INTEGER]
 
sorter: COLLECTION_SORTER[INTEGER]
Line 345: Line 236:
 
array := <<1,3,2>>
 
array := <<1,3,2>>
 
sorter.sort(array)
 
sorter.sort(array)
  +
The point of using an <tt>expanded</tt> class in this case is that it is unnecessary to allocate space for an object of the
L'intérêt d'avoir utilisé dans ce cas une classe <tt>expanded</tt> réside dans le
 
  +
[[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER[INTEGER]</tt>]] class in the [[Glossary#Heap|heap]].
fait qu'il n'est pas nécessaire d'allouer dans le [[Glossary#Heap|tas]] un objet
 
  +
No doubt you have noticed in reading the above code that there is no creation instruction for the object associated with the variable <tt>sorter</tt>.
de la classe
 
  +
Furthermore, since the objects of this class have no attribute, the object corresponding to <tt>sorter</tt> is not even represented on the [[glossary#Stack|stack]]!
[[library_class:COLLECTION_SORTER|<tt>COLLECTION_SORTER[INTEGER]</tt>]].
 
  +
<br>
Vous l'avez bien sûr remarqué en lisant le code qui précède, il n'y a aucune instruction
 
  +
Here, using an <tt>expanded</tt> object lets us get better performance.
de création pour l'objet associé à la variable <tt>sorter</tt>.
 
En outre, comme les objets de cette classe n'ont aucun attribut, l'objet correspondant
 
à <tt>sorter</tt> n'est même pas représenté dans la [[glossary#Stack|pile]]&nbsp;!<br>
 
L'utilisation d'un objet <tt>expanded</tt> permet ici d'obtenir les meilleurs
 
performances.
 
   
 
<div id="ManySmallObjects">
 
<div id="ManySmallObjects">
  +
===Économie de mémoire pour de petits objets très nombreux===
 
  +
===Economising on memory for many small objects===
 
</div>
 
</div>
Une autre utilité des classes <tt>expanded</tt> consiste à pouvoir économiser de la
+
Another use for <tt>expanded</tt> classes is to let you economise on memory for small objects.
  +
By ''small object'' we mean an object whose memory requirement is comparable to or slightly higher than the machine's pointer size.
place mémoire pour les objets de petite taille.
 
  +
If for argument's sake we assume that an object of class <tt>FOO</tt> is exactly the same size as a machine pointer and that the application uses ''n'' objects of class <tt>FOO</tt>, we then need at least ''2 * n'' memory locations of the size of a machine pointer.
Nous entendons ici par ''objet de petite taille'' un objet dont la taille mémoire
 
  +
If we change the definition of the <tt>FOO</tt> class to make it <tt>expanded</tt>, we then save ''n'' memory locations of the size of a machine pointer.
est comparable ou légèrement supérieure à la taille d'un pointeur en machine.
 
En effet, si l'on considère pour simplifier, qu'un objet de la classe <tt>FOO</tt>
 
fait exactement la taille d'un pointeur machine et que l'application utilise ''n'' objets
 
de la classe <tt>FOO</tt>, il faut alors au minimum ''2 * n'' emplacements mémoire
 
de la taille d'un pointeur machine.
 
Si on change la définition de la classe <tt>FOO</tt> et que l'on définit cette classe
 
comme étant <tt>expanded</tt>, on économise alors ''n'' emplacements mémoire de la taille
 
d'un pointeur de la machine.
 
   
  +
Be careful, because to take advantage of this gain you must also be in the very special case where [[Dynamic dispatch|dynamic dispatch]] is not useful with a type <tt>FOO</tt> variable.
Attention, car pour pouvoir profiter de ce gain, il faut également être dans un cas très
 
  +
Indeed, as indicated above, as soon as an expression is <tt>expanded</tt> you can no longer take advantage of dynamic dispatch.
particulier dans lequel la [[Dynamic dispatch|liaison dynamique]] n'est pas utile
 
avec une variable de type <tt>FOO</tt>.
 
En effet, comme indiqué précédemment, dès qu'une expression est <tt>expanded</tt> on ne peut
 
plus profiter de la liaison dynamique.
 
 
Comme dans le cas précédent, l'utilisation d'une classe
 
<tt>expanded</tt> à la place d'une classe ordinaire permet une
 
économie de mémoire.
 
Notons également que les objets en question ne peuvent plus être
 
identifiés par leur addresse mémoire.
 
En effet, quand le type <tt>FOO</tt> est <tt>expanded</tt>, la
 
comparaison de deux variables de ce type avec
 
[[Comparison of objects#EqNeq|l'opérateur <tt>=</tt>]] ne compare plus deux
 
addresses, mais bien deux objets.
 
Il faut également être conscient de ce dernier point avant d'opter
 
pour la définition d'une classe <tt>expanded</tt>.
 
   
  +
As in the foregoing example, using an <tt>expanded</tt> class instead of an ordinary class allows memory savings.
  +
We should also note that the objects in question can no longer be identified by their memory address. Indeed, when the <tt>FOO</tt> type is expanded, the comparison of two variables of this type with the [[Comparison of objects#EqNeq|<tt>=</tt> operator]] no longer compares two addresses but actually compares two objects.
  +
You must also be aware of this final point before opting to define an <tt>expanded</tt> class.
 
<div id="ExpandedPitfalls">
 
<div id="ExpandedPitfalls">
   
===Les pièges à éviter avec les classes <tt>expanded</tt>===
+
===Traps to avoid with <tt>expanded</tt> classes===
 
</div>
 
</div>
Le premier piège à éviter concerne les classes ayant de nombreux attributs.
+
The first trap to avoid concerns classes with many attributes.
  +
When an <tt>expanded</tt> object is very big, passing this object as a parameter to a [[Glossary#Routine|routine]] can turn out to be much more expensive than with an ordinary object.
Quand un objet <tt>expanded</tt> est très gros, le passage en
 
  +
Indeed, for an ordinary object, only its memory address is copied onto the stack.
paramêtre de cet objet en tant qu'argument d'une [[Glossary#Routine|routine]] peut se
 
  +
For an <tt>expanded</tt> object, it is the object itself, that is to say all its [[Glossary#Attribute|attributes]], which is copied during parameter passing.
révéler beaucoup plus coûteux qu'avec un objet ordinaire.
 
  +
Note that the same can happen during the assignment of an <tt>expanded</tt> type variable.
En effet, pour un objet ordinaire, c'est uniquement l'adresse mémoire de cet objet
 
  +
For very big <tt>expanded</tt> objects, assignments can turn out to lower performance.
qui est recopiée dans la pile.
 
Pour un objet <tt>expanded</tt>, c'est l'objet lui même, c'est à dire
 
tous ses [[Glossary#Attribute|attributs]] qui sont recopiés lors du passage en paramêtre.
 
Notons que le même effet peut se produire dans le cas de l'affectation d'une variable
 
dont le type est <tt>expanded</tt>.
 
Pour les très gros objet <tt>expanded</tt>, l'affectation peut se
 
révéler moins performante.
 
   
  +
The second trap to avoid is much more dangerous, because it does not only risk slowing down the application's execution.
Le deuxième piège à éviter est beaucoup plus pervers car il ne risque
 
  +
This trap has to do with the mistaken interpretation that one can give to a modifying procedure call applied to an <tt>expanded</tt> object obtained by means of an indirect reading of an attribute:
pas seulement de ralentir l'exécution de l'application.
 
Ce piège concerne l'interprétation trompeuse que l'on peut
 
donner a un appel de procédure de modification appliquée sur un objet
 
<tt>expanded</tt> obtenu par le biais d'une lecture indirecte
 
d'attribut&nbsp;:
 
   
 
bar.foo.set_attribute(zoo)
 
bar.foo.set_attribute(zoo)
   
  +
is in fact equivalent to the following sequence of instructions:
équivaut en fait à la séquence de deux instructions suivante&nbsp;:
 
   
temporary_foo := bar.foo -- (1) recopie de l'objet expanded foo
+
temporary_foo := bar.foo -- (1) copy expanded object foo
temporary_foo.set_attribute(zoo) -- (2) application de la modification sur la copie de foo
+
temporary_foo.set_attribute(zoo) -- (2) modify the copy of foo
   
  +
In effect, even though <tt>foo</tt> is an [[Glossary#Attribute|attribute]], since <tt>foo</tt>'s class is <tt>expanded</tt>, the corresponding object is copied. So the object that you thought you were modifying with the procedure <tt>set_attribute</tt> is not the one associated with the attribute <tt>foo</tt>, but a temporary copy in memory!
En effet, même si <tt>foo</tt> est un [[Glossary#Attribute|attribut]], la classe de
 
  +
Note that when <tt>foo</tt> is a [[Glossary#Function|function]] call, the previously described transformation which introduces the variable <tt>temporary_foo</tt> does not change anything. It is just the same as if <tt>foo</tt> were a reference type.
<tt>foo</tt> étant <tt>expanded</tt>, une recopie de l'objet correspondant est effectuée.
 
L'objet que l'on pensait modifier à l'aide de la procédure <tt>set_attribute</tt>
 
n'est donc pas celui qui est associé à l'attribut <tt>foo</tt>, mais
 
une copie mémorisée dans une variable temporaire&nbsp;!
 
Notons que lorsque <tt>foo</tt> est un appel de
 
[[Glossary#Function|fonction]], la transformation précédente qui
 
introduit la variable <tt>temporary_foo</tt> ne change rien.
 
Il en est de même, si <tt>foo</tt> est un type référence.
 
   
  +
Unfortunately, the actual compiler does not yet warn of this pitfall.
Malheureusement, le compilateur actuel ne signale pas encore ce piège.
 
  +
We plan to change the compiler to make it able to flag up this trap by a warning message, but this is not yet implemented.
Nous avons prévu, mais ceci n'est pas encore implanté, de modifier le
 
  +
At the moment (August 2005) no implementation has yet been decided, but it is likely that, in the future, the compiler will ask you to add the temporary variable explicitly so that you can be aware of the real problem.
compilateur afin qu'il puisse prévenir de l'éventualité de ce
 
  +
Since several solutions can be envisaged, including adding new restrictions on the definition of <tt>expanded</tt> classes, it is best for the moment to be cautious in defining new <tt>expanded</tt> classes.
piège sous la forme d'un message d'avertissement.
 
À l'heure actuelle (aout 2005), rien n'est encore décidé&nbsp;/&nbsp;implanté, mais
 
il est probable que, dans le futur, le compilateur vous
 
demande d'ajouter explicitement la variable temporaire afin que l'on
 
soit conscient de l'éventuel problème.
 
Comme plusieurs solutions sont envisageables, y compris l'ajout de
 
nouvelles restriction concernant la définition des classes <tt>expanded</tt>
 
il convient en attendant d'être prudent lors de la définition de
 
nouvelles classes <tt>expanded</tt>.
 
   
  +
To avoid falling into this subtle trap, it is preferable whenever possible to avoid exporting the modification methods of <tt>expanded</tt> classes.
Pour éviter de tomber dans ce piège délicat, il est
 
  +
Best of all is not to have any modification methods at all.
préférable quand cela est possible d'éviter d'exporter les méthodes de
 
modification des classes <tt>expanded</tt>.
+
Note that all the following <tt>expanded</tt> basic classes respect this rule.
  +
There are no modification procedures in the classes:
Le mieux est encore de ne pas avoir de procédure de modification
 
  +
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]],
du tout.
 
Notons que toutes les classes élémentaires <tt>expanded</tt>
 
suivantes respectent cette régle.
 
Il n'y a pas de procédure de modifications dans les classes&nbsp;:
 
[[library_class:BOOLEAN|<tt>BOOLEAN</tt>]]
 
 
[[library_class:CHARACTER|<tt>CHARACTER</tt>]],
 
[[library_class:CHARACTER|<tt>CHARACTER</tt>]],
 
[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
 
[[library_class:INTEGER_8|<tt>INTEGER_8</tt>]],
Line 463: Line 303:
 
[[library_class:REAL_80|<tt>REAL_80</tt>]],
 
[[library_class:REAL_80|<tt>REAL_80</tt>]],
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
 
[[library_class:REAL_128|<tt>REAL_128</tt>]],
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]] et
+
[[library_class:REAL_EXTENDED|<tt>REAL_EXTENDED</tt>]] and
 
[[library_class:POINTER|<tt>POINTER</tt>]].
 
[[library_class:POINTER|<tt>POINTER</tt>]].
  +
Until the compiler can warn you of this possible problem, be careful when you use <tt>expanded</tt> classes.
Tant que le compilateur ne sera pas capable de vous avertir de cet
 
éventuel problème, soyez prudent quand vous utilisez des classes
 
<tt>expanded</tt>.
 

Latest revision as of 22:06, 1 March 2022

In our opinion, it is essential to have a good understanding of how objects are represented in memory while an application is running. The aim is not to make every one of us an expert in the subject, but more simply to have sufficient knowledge to be able to make design choices. Besides, it is often essential to be able to draw how objects appear in memory so as to be able to explain or think about the design of a new class. The section which explains the two categories of objects which exist during execution is essential. Next, a summary of the properties of expanded types goes into detail about certain points that are characteristic of these types.

You have to realise that all variables are automatically initialised in accordance with their declared type. This too needs to be understood.

The last section is only of interest to those few users who wish to define their own expanded class. This section can be skipped by most beginners.

The objects that are handled during the execution of an Eiffel program are handled either with or without an intermediate reference. Furthermore, when an object is handled through a reference, it can be handled only through a reference. In the same way, when an object is handled without a reference, it can only be handled in that way, that is to say without any intermediate reference.

Thus there are two sorts of objects. The most common classes correspond to objects that are handled through a reference. Less often, classes correspond to objects that are handled without an intermediate pointer. In this case, the class in question begins with the keyword expanded. In Eiffel jargon, when we speak of an expanded class, we are talking about a class whose objects are handled without an intermediate pointer, objects that are directly written, or expanded, onto the memory area that they use I. e. they are passed by value. In contrast, if we talk of a reference class or of a reference type, it is to emphasise that the objects in question are not expanded.

The chief point of this dichotomy is to make it possible to integrate the most basic entities into the object model. For example, a boolean value of the BOOLEAN class corresponds to an expanded object. Similarly, the classes INTEGER and REAL are also expanded. The following diagram shows what happens in memory; the classes POINT and TRIANGLE are ordinary classes, that is to say classes defined without the keyword expanded:

Expanded vs reference memory structure

In the figure above, the variable called a_boolean is declared as type BOOLEAN. Since the BOOLEAN class is expanded, the corresponding object is directly assigned to the memory area associated with the variable a_boolean. As the diagram shows, the a_boolean variable currently contains an object True which corresponds to the boolean value true. In the same way, the memory area associated with the variable a_integer of type INTEGER directly contains the object corresponding to the value 1 since the INTEGER class is also expanded. Finally, the variable a_real declared in the example as type REAL also directly contains the value 1.0.

In the diagram above, the variable point is declared as type POINT. Since we are not dealing with an expanded class, the memory area associated with the variable point does not directly contain the POINT object, but a pointer to that object. Thus the point variable does not directly contain an object of the POINT class; the point variable references a POINT object. Note that the diagram also shows us that each object of class POINT is itself made up of two attributes x and y whose type is REAL. As in the case of the point variable, the variable triangle is a reference to an object of the class TRIANGLE since the TRIANGLE class is an ordinary class, not expanded. Since the attributes p1, p2 and p3 are of the POINT type, in this case there are also pointers to the corresponding objects.

Whether or not an object is expanded, the syntax used to declare it is the same. The fact that a class is expanded or not depends only on the class definition itself. For example, the declaration of the variables a_boolean, a_integer, a_real, point and triangle corresponds to the following Eiffel code:

a_boolean: BOOLEAN; a_integer: INTEGER; a_real: REAL; point: POINT; triangle: TRIANGLE

Whether or not one is dealing with an expanded object, the notation is just the same. For example, the following instruction copies into the variable a_real the value of the attribute y of the POINT object referenced by the variable point:

a_real := point.y

The following instruction copies the pointer which points to the same POINT as the one referenced by the p1 attribute of the TRIANGLE which is itself referenced by the variable triangle:

point := triangle.p1

Without going into all the details of assignments, the effect of those two instructions in relation to the memory diagram above is to produce this memory configuration:

Expanded vs reference memory structure

Applying a method to an expanded object uses the same syntax as for an ordinary (not expanded) object. For example the following instruction applies the sqrt function to the INTEGER class object which is stored directly in the memory area associated with the variable a_integer. The result of calling the sqrt function is a REAL which overwrites the old object which was formerly stored directly in the variable a_real:

a_real := a_integer.sqrt

Having identical notation for handling ordinary (referenced) and expanded (not referenced) objects simplifies programming and provides consistency.

Being able to describe basic objects by a proper class is an important aid to consistency. A simple object, such as a 32 bit signed integer, is described by a proper class, the INTEGER class. As with any class, it is possible to change or adapt the methods in the INTEGER class. Of course, nearly all users only consult the list of available methods. Since the INTEGER class is used by almost every program, altering it is more and more an uncommon event, and must be done with care. Nevertheless, having a proper class lets users look up the list of available methods for INTEGER in the same way as they can for all other classes.

Among the predefined expanded classes corresponding to basic objects that must be familiar to all users are: BOOLEAN, INTEGER, REAL and CHARACTER. A well-informed user should also be familiar with the following expanded classes: INTEGER_8, INTEGER_16, INTEGER_32, INTEGER_64, REAL_32, REAL_64, REAL_80, REAL_128, REAL_EXTENDED and finally, for the most curious, there are the classes POINTER and NATIVE_ARRAY.

Principal characteristics of expanded type expressions

An expanded type expression has properties which one needs to know about. As explained above, the object that corresponds to an expanded type expression cannot be referenced. No other location can directly designate the object in question; in particular no pointer can point to it. So if, for example, one is dealing with a variable of type INTEGER, the only way of operating on the corresponding object is to use the variable in question.

An expanded type expression always designates an object. In other words, an expanded expression is never Void. What is more, an expanded type expression always corresponds to one and only one category of object. In consequence, dynamic dispatch is never involved when an expanded object is the target of a call (that is, on the left of a dot). The invocation of a method with an expanded object as target corresponds to the most efficient possible direct call.

Without going into too much detail, since dynamic dispatch is not possible with an expanded object, it is useless to give such an object the information that lets you find its dynamic type. Thus, the memory space required for an expanded object is limited exactly to that needed to accommodate its different attributes.

Initialisation of variables and attributes

In Eiffel, all variables are always initialised automatically. This is the same for all kinds of variables: instance variables, local variables and the variable Result which is used to hold the result of a function. The way in which a variable is initialised depends entirely on its declaration type, which is either reference or expanded.

Initialisation of reference type variables

A variable whose type is a reference type is always automatically initialised with Void. For example, if you declare a variable of type POINT or type TRIANGLE, the non-expanded classes of the example above, the variable is automatically initialised with Void. For reference types, an object is never automatically created following the declaration of a variable.

Among the standard classes that correspond to reference types, let us consider the STRING class. This class is in no way a special case. A variable declared to be of type STRING is automatically initialised with Void. No object of the STRING class is created when a STRING type variable is declared. To take another common example, declaring a variable of type ARRAY[INTEGER] does not lead to the automatic creation of a table of INTEGERs, because the class ARRAY itself is still not an expanded class. So this simple initialisation rule applies to the majority of classes, which, it should be remembered, are ordinary, non-expanded classes.


Initialisation of expanded type variables

Variables whose type is expanded are initialised automatically. For certain truly basic expanded types, the initialisation is done directly by the compiler. After presenting all these special cases, we will deal with the general case of an expanded class.

For the family of INTEGERs, that is to say all the following types, {INTEGER_8, INTEGER_16, INTEGER_32, INTEGER, INTEGER_64}, or NATURALs {NATURAL_8, NATURAL_16, NATURAL_32, NATURAL, NATURAL_64} the object used to initialise them corresponds to the value 0.

For the group of types {REAL_32, REAL_64, REAL, REAL_80, REAL_128, REAL_EXTENDED}, the object used to initialise them corresponds to the value 0.0.

For the BOOLEAN type, the value False is used to initialise an object.

For the CHARACTER type, the character with the ASCII code 0 is used to initialise it. This character is denoted by '%U' in Eiffel.

For the POINTER type, variable initialisation is done with the machine value that represents the null pointer. Since this value is not in normal use, there is no Eiffel notation for it. It is necessary to use the is_null method of the POINTER class to test whether an expression of this type corresponds to the null value.

In the general case, that is to say for an expanded class that is not one of the special cases above, the initialisation is programmed by the class designer. In fact, an expanded class must either have no creation clause, or one and only one of its constructors must have no arguments. This creation procedure is automatically run to effect initialisation.

Some advice before you write an expanded class

In general, it is not useful to define new expanded classes and this applies to the great majority of applications. As we have explained above, the principal use of expanded classes is to make it possible to integrate the most basic objects into the object model. Having said that, it can perhaps be useful to resort to an expanded class, either to group utility routines, or to economise on memory in the special case when a large number of small objects is used. Finally, we will present the traps to avoid when designing an expanded class.

Grouping a collection of routines

With an object-oriented language, it is always most convenient, if possible, to put the object-handling methods directly in the class of the objects to be handled. In certain very special cases, it is not desirable, nor even possible, to keep to this basic rule.

The COLLECTION_SORTER class is a good example of an expanded class intended for grouping some routines which cannot be placed directly in the classes that correspond to the idea of a COLLECTION.

Although all the routines of the COLLECTION_SORTER class are used for sorting objects from the COLLECTIONs family, it is not possible to put these methods directly into the COLLECTION class. This is not possible for the simple reason that not all COLLECTIONs can be sorted. Only COLLECTIONs whose elements are COMPARABLE can be sorted. So the COLLECTION_SORTER class lets us add this extra generic constraint. The COLLECTION_SORTER class does not have any attribute; it is just a holder for methods. Furthermore, this class is expanded. So, to sort a whole table, for example, you can proceed in the following manner:

local
   sorter: COLLECTION_SORTER[INTEGER]
   array: ARRAY[INTEGER]
do
   array := <<1,3,2>>
   sorter.sort(array)

The point of using an expanded class in this case is that it is unnecessary to allocate space for an object of the COLLECTION_SORTER[INTEGER] class in the heap. No doubt you have noticed in reading the above code that there is no creation instruction for the object associated with the variable sorter. Furthermore, since the objects of this class have no attribute, the object corresponding to sorter is not even represented on the stack!
Here, using an expanded object lets us get better performance.

Economising on memory for many small objects

Another use for expanded classes is to let you economise on memory for small objects. By small object we mean an object whose memory requirement is comparable to or slightly higher than the machine's pointer size. If for argument's sake we assume that an object of class FOO is exactly the same size as a machine pointer and that the application uses n objects of class FOO, we then need at least 2 * n memory locations of the size of a machine pointer. If we change the definition of the FOO class to make it expanded, we then save n memory locations of the size of a machine pointer.

Be careful, because to take advantage of this gain you must also be in the very special case where dynamic dispatch is not useful with a type FOO variable. Indeed, as indicated above, as soon as an expression is expanded you can no longer take advantage of dynamic dispatch.

As in the foregoing example, using an expanded class instead of an ordinary class allows memory savings. We should also note that the objects in question can no longer be identified by their memory address. Indeed, when the FOO type is expanded, the comparison of two variables of this type with the = operator no longer compares two addresses but actually compares two objects. You must also be aware of this final point before opting to define an expanded class.

Traps to avoid with expanded classes

The first trap to avoid concerns classes with many attributes. When an expanded object is very big, passing this object as a parameter to a routine can turn out to be much more expensive than with an ordinary object. Indeed, for an ordinary object, only its memory address is copied onto the stack. For an expanded object, it is the object itself, that is to say all its attributes, which is copied during parameter passing. Note that the same can happen during the assignment of an expanded type variable. For very big expanded objects, assignments can turn out to lower performance.

The second trap to avoid is much more dangerous, because it does not only risk slowing down the application's execution. This trap has to do with the mistaken interpretation that one can give to a modifying procedure call applied to an expanded object obtained by means of an indirect reading of an attribute:

bar.foo.set_attribute(zoo)

is in fact equivalent to the following sequence of instructions:

temporary_foo := bar.foo             -- (1) copy expanded object foo
temporary_foo.set_attribute(zoo)     -- (2) modify the copy of foo

In effect, even though foo is an attribute, since foo's class is expanded, the corresponding object is copied. So the object that you thought you were modifying with the procedure set_attribute is not the one associated with the attribute foo, but a temporary copy in memory! Note that when foo is a function call, the previously described transformation which introduces the variable temporary_foo does not change anything. It is just the same as if foo were a reference type.

Unfortunately, the actual compiler does not yet warn of this pitfall. We plan to change the compiler to make it able to flag up this trap by a warning message, but this is not yet implemented. At the moment (August 2005) no implementation has yet been decided, but it is likely that, in the future, the compiler will ask you to add the temporary variable explicitly so that you can be aware of the real problem. Since several solutions can be envisaged, including adding new restrictions on the definition of expanded classes, it is best for the moment to be cautious in defining new expanded classes.

To avoid falling into this subtle trap, it is preferable whenever possible to avoid exporting the modification methods of expanded classes. Best of all is not to have any modification methods at all. Note that all the following expanded basic classes respect this rule. There are no modification procedures in the classes: BOOLEAN, CHARACTER, INTEGER_8, INTEGER_16, INTEGER_32, INTEGER, INTEGER_64, REAL_32, REAL_64, REAL, REAL_80, REAL_128, REAL_EXTENDED and POINTER. Until the compiler can warn you of this possible problem, be careful when you use expanded classes.