From 9e103d150771ff8cf4c23bb5a325a69b95db2b06 Mon Sep 17 00:00:00 2001 From: halw Date: Tue, 21 Oct 2008 19:55:42 +0000 Subject: [PATCH] Author:halw Date:2008-10-21T19:55:42.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@92 abb3cda0-5349-4a8f-a601-0c33ac3a8c38 --- documentation/current/community/index.wiki | 4 +- .../method/eiffel-tutorial-et/et-agents.wiki | 162 ++++++++-------- .../et-dynamic-structure-execution-model.wiki | 131 ++++++------- ...t-lexical-conventions-and-style-rules.wiki | 22 +-- .../et-other-mechanisms.wiki | 174 ++++++++++-------- ...et-static-picture-system-organization.wiki | 10 +- .../once-features-multithreaded-mode.wiki | 35 ++-- 7 files changed, 279 insertions(+), 259 deletions(-) diff --git a/documentation/current/community/index.wiki b/documentation/current/community/index.wiki index 62c6d8da..d1bb61e3 100644 --- a/documentation/current/community/index.wiki +++ b/documentation/current/community/index.wiki @@ -1,7 +1,9 @@ [[Property:title|Community]] [[Property:weight|2]] [[Property:uuid|75c75712-7c3e-2757-51b7-77b404471e2e]] -EiffelStudio community: +Eiffel is a community. Members of the Eiffel community can contribute to this documentation through this book. + + :'''You can become a contributor!''' diff --git a/documentation/current/method/eiffel-tutorial-et/et-agents.wiki b/documentation/current/method/eiffel-tutorial-et/et-agents.wiki index cb120a5c..414407df 100644 --- a/documentation/current/method/eiffel-tutorial-et/et-agents.wiki +++ b/documentation/current/method/eiffel-tutorial-et/et-agents.wiki @@ -14,181 +14,181 @@ In a number of applications, however, we may need objects that represent operati * Numerical computation, where we may define a routine that computes the integral of any applicable function on any applicable interval; to represent that function and pass its representation to the integration routine, we will use an agent. -Operations in Eiffel are expressed as routines, and indeed every agent will have an associated routine. Remember, however, that the fundamental distinction between objects and operations remains: an agent is an object, and it is not a routine; it represents a routine. As further evidence that this is a proper data abstraction, note that the procedure call , available on all agents to call the associated routine, is only one of the features of agents. Other features may denote properties such as the class to which the routine belongs, its precondition and postcondition, the result of the last call for a function, the number of arguments. +Operations in Eiffel are expressed as routines, and indeed every agent will have an associated routine. Remember, however, that the fundamental distinction between objects and operations remains: an agent is an object, and it is not a routine; it represents a routine. As further evidence that this is a proper data abstraction, note that the procedure call, available on all agents to call the associated routine, is only one of the features of agents. Other features may denote properties such as the class to which the routine belongs, its precondition and postcondition, the result of the last call for a function, the number of arguments. ==Building an agent== In the simplest form, also one of the most common, you obtain an agent just by writing -agent r + agent r -where r is the name of a routine of the enclosing class. This is an expression, which you may assign to a writable entity, or pass as argument to a routine. Here for example is how you will specify event handling in the style of the EiffelVision 2 GUI library: +where r is the name of a routine of the enclosing class. This is an expression, which you may assign to a writable entity, or pass as argument to a routine. Here for example is how you will specify event handling in the style of the EiffelVision 2 GUI library: -your_icon.click_actions.extend (agent your_routine) + your_icon.click_actions.extend (agent your_routine) -This adds to the end of my_icon.click_actions -- the list of agents associated with the "click" event for my_icon , denoting an icon in the application's user interface -- an agent representing your_routine . Then when a user clicks on the associated icon at execution, the EiffelVision 2 mechanisms will call the procedure call on every agent of the list, which for this agent will execute your_routine . This is a simple way to associate elements of your application, more precisely its "business model" (the processing that you have defined, directly connected to the application's business domain), with elements of its GUI. +This adds to the end of my_icon.click_actions -- the list of agents associated with the "click" event for my_icon, denoting an icon in the application's user interface -- an agent representing your_routine. Then when a user clicks on the associated icon at execution, the EiffelVision 2 mechanisms will call the procedure call on every agent of the list, which for this agent will execute your_routine. This is a simple way to associate elements of your application, more precisely its "business model" (the processing that you have defined, directly connected to the application's business domain), with elements of its GUI. -Similarly although in a completely different area, you may request the integration of a function your_function over the interval 0..1 through a call such as +Similarly although in a completely different area, you may request the integration of a function your_function over the interval 0..1 through a call such as -your_integrator.integral (agent your_function, 0, 1) + your_integrator.integral (agent your_function, 0, 1) In the third example area cited above, you may call an iterator of EiffelBase through -your_list.do_all (agent your_proc) + your_list.do_all (agent your_proc) -with your_list of a type such as LIST [YOUR_TYPE] . This will apply your_proc to every element of the list in turn. +with your_list of a type such as LIST [YOUR_TYPE]. This will apply your_proc to every element of the list in turn. -The agent mechanism is type-checked like the rest of Eiffel; so the last example is valid if and only if your_proc is a procedure with one argument of type YOUR_TYPE . +The agent mechanism is type-checked like the rest of Eiffel; so the last example is valid if and only if your_proc is a procedure with one argument of type YOUR_TYPE. ==Operations on agents== -An agent agent r built from a procedure r is of type PROCEDURE [T, ARGS] where T represents the class to which r belongs and ARGS the type of its arguments. If r is a function of result type RES , the type is FUNCTION [T, ARGS, RES] . Classes PROCEDURE and FUNCTION are from the Kernel Library of EiffelBase, both inheriting from ROUTINE [T, ARGS] . +An agent agent r built from a procedure r is of type PROCEDURE [T, ARGS] where T represents the class to which r belongs and ARGS the type of its arguments. If r is a function of result type RES, the type is FUNCTION [T, ARGS, RES]. Classes PROCEDURE and FUNCTION are from the Kernel Library of EiffelBase, both inheriting from ROUTINE [T, ARGS]. -Among the features of ROUTINE and its descendants the most important are call , already noted, which calls the associated routine, and item , appearing only in FUNCTION and yielding the result of the associated function, which it obtains by calling call . +Among the features of ROUTINE and its descendants the most important are call, already noted, which calls the associated routine, and item, appearing only in FUNCTION and yielding the result of the associated function, which it obtains by calling call. -As an example of using these mechanisms, here is how the function integral could look like in our INTEGRATOR example class. The details of the integration algorithm (straight forward, and making no claims to numerical sophistication) do not matter, but you see, in the highlighted line, the place were we evaluate the mathematical function associated with f , by calling item on f : +As an example of using these mechanisms, here is how the function integral could look like in our INTEGRATOR example class. The details of the integration algorithm (straight forward, and making no claims to numerical sophistication) do not matter, but you see, in the highlighted line, the place were we evaluate the mathematical function associated with f, by calling item on f: -integral (f: FUNCTION [ANY, TUPLE [REAL], REAL]; low, high: REAL): REAL is - -- Integral of `f' over the interval [`low', `high'] - require - meaningful_interval: low <= high - local - x: REAL - do - from - x := low - invariant - x >= low - x <= high + step - -- Result approximates the integral over - -- the interval [low, low.max (x - step)] - until - x > high - loop - Result := Result + step * f.item ([x]) - x := x + step - end - end + integral (f: FUNCTION [ANY, TUPLE [REAL], REAL]; low, high: REAL): REAL + -- Integral of `f' over the interval [`low', `high'] + require + meaningful_interval: low <= high + local + x: REAL + do + from + x := low + invariant + x >= low + x <= high + step + -- Result approximates the integral over + -- the interval [low, low.max (x - step)] + until + x > high + loop + Result := Result + step * f.item ([x]) + x := x + step + end + end -Function integral takes three arguments: the agent f representing the function to be integrated, and the two interval bounds. When we need to evaluate that function for the value x , in the line +Function integral takes three arguments: the agent f representing the function to be integrated, and the two interval bounds. When we need to evaluate that function for the value x, in the line -Result := Result + step * f.item ([x]) + Result := Result + step * f.item ([x]) -we don't directly pass x to item ; instead, we pass a one-element tuple [x] , using the syntax for manifest tuples introduced in [[10 Other Mechanisms|"Tuple types", page 90]] . You will always use tuples for the argument to call and item , because these features must be applicable to any routine, and so cannot rely on a fixed number of arguments. Instead they take a single tuple intended to contain all the arguments. This property is reflected in the type of the second actual generic parameter to f , corresponding to ARGS (the formal generic parameter of FUNCTION ): here it's TUPLE [REAL] to require an argument such as [ x] , where x is of type REAL . +we don't directly pass x to item; instead, we pass a one-element tuple [x], using the syntax for manifest tuples introduced in [[10 Other Mechanisms#Tuple_types|"Tuple types"]] . You will always use tuples for the argument to call and item, because these features must be applicable to any routine, and so cannot rely on a fixed number of arguments. Instead they take a single tuple intended to contain all the arguments. This property is reflected in the type of the second actual generic parameter to f, corresponding to ARGS (the formal generic parameter of FUNCTION): here it's TUPLE [REAL] to require an argument such as [ x], where x is of type REAL. Similarly, consider the agent that the call seen above: -your_icon.click_actions.extend (agent your_routine) + your_icon.click_actions.extend (agent your_routine) -added to an EiffelVision list. When the EiffelVision mechanism detects a mouse click event, it will apply to each element item of the list of agents, your_icon.click_actions , an instruction such as +added to an EiffelVision list. When the EiffelVision mechanism detects a mouse click event, it will apply to each element item of the list of agents, your_icon.click_actions, an instruction such as -item.call ([x, y]) + item.call ([x, y]) -where x and y are the coordinates of the mouse clicking position. If item denotes the list element agent your_routine, inserted by the above call to extend , the effect will be the same as that of calling +where x and y are the coordinates of the mouse clicking position. If item denotes the list element agent your_routine, inserted by the above call to extend, the effect will be the same as that of calling -your_routine (x, y) + your_routine (x, y) -assuming that your_routine indeed takes arguments of the appropriate type, here INTEGER representing a coordinate in pixels. (Otherwise type checking would have rejected the call to extend .) +assuming that your_routine indeed takes arguments of the appropriate type, here INTEGER representing a coordinate in pixels. (Otherwise type checking would have rejected the call to extend.) ==Open and closed arguments== -In the examples so far, execution of the agent's associated routine, through item or call , passed exactly the arguments that a direct call to the routine would expect. You can have more flexibility. In particular, you may build an agent from a routine with more arguments than expected in the final call, and you may set the values of some arguments at the time you define the agent. +In the examples so far, execution of the agent's associated routine, through item or call, passed exactly the arguments that a direct call to the routine would expect. You can have more flexibility. In particular, you may build an agent from a routine with more arguments than expected in the final call, and you may set the values of some arguments at the time you define the agent. Assume for example that a cartographical application lets a user record the location of a city by clicking on the corresponding position on the map. The application may do this through a procedure -record_city (cn: STRING; pop: INTEGER; x, y: INTEGER) - -- Record that the city of name `cn' is at coordinates - -- `x' and `y' with population `pop'. + record_city (cn: STRING; pop: INTEGER; x, y: INTEGER) + -- Record that the city of name `cn' is at coordinates + -- `x' and `y' with population `pop'. Then you can associate it with the GUI through a call such as -map.click_actions.extend (agent record_city (name, population, ?, ?)) + map.click_actions.extend (agent record_city (name, population, ?, ?)) -assuming that the information on the name and the population has already been determined. What the agent denotes is the same as agent your_routine as given before, where your_routine would be a fictitious two-argument routine obtained from record_city -- a four-argument routine -- by setting the first two arguments once and for all to the values given, name and population . +assuming that the information on the name and the population has already been determined. What the agent denotes is the same as agent your_routine as given before, where your_routine would be a fictitious two-argument routine obtained from record_city -- a four-argument routine -- by setting the first two arguments once and for all to the values given, name and population. -In the agent agent record_city (name, population, ?, ?) , we say that these first two arguments, with their set values, are '''closed'''; the last two are '''open'''. The question mark syntax introduced by this example may only appear in agent expressions; it denotes open arguments. This means, by the way, that you may view the basic form used in the preceding examples, agent your_routine , as an abbreviation -- assuming your_routine has two arguments -- for agent your_routine (?, ?) . It is indeed permitted, to define an agent with all arguments open, to omit the argument list altogether; no ambiguity may result. +In the agent agent record_city (name, population, ?, ?), we say that these first two arguments, with their set values, are '''closed'''; the last two are '''open'''. The question mark syntax introduced by this example may only appear in agent expressions; it denotes open arguments. This means, by the way, that you may view the basic form used in the preceding examples, agent your_routine, as an abbreviation -- assuming your_routine has two arguments -- for agent your_routine (?, ?). It is indeed permitted, to define an agent with all arguments open, to omit the argument list altogether; no ambiguity may result. -For type checking, agent record_city (name, population, ?, ?) and agent ,your_routine are acceptable in exactly the same situations, since both represent routines with two arguments. The type of both is +For type checking, agent record_city (name, population, ?, ?) and agent your_routine (?, ?) are acceptable in exactly the same situations, since both represent routines with two arguments. The type of both is -PROCEDURE [ANY, TUPLE [INTEGER, INTEGER]] + PROCEDURE [ANY, TUPLE [INTEGER, INTEGER]] where the tuple type specifies the open operands. -A completely closed agent, such as agent your_routine (25, 32) or agent record_city (name, population, 25, 32) , has the type TUPLE , with no parameters; you will call it with call ([ ]) , using an empty tuple as argument. +A completely closed agent, such as agent your_routine (25, 32) or agent record_city (name, population, 25, 32), has the type TUPLE, with no parameters; you will call it with call ([ ]), using an empty tuple as argument. -The freedom to start from a routine with an arbitrary number of arguments, and choose which ones you want to close and which ones to leave open, provides a good part of the attraction of the agent mechanism. It means in particular that in GUI applications you can limit to the strict minimum the "glue" code (sometimes called the controller in the so-called MVC, Model-View Controller, scheme of GUI design) between the user interface and "business model" parts of a system. A routine such as record_city is a typical example of an element of the business model, uninfluenced -- as it should be -- by considerations of user interface design. Yet by passing it in the form of an agent with partially open and partially closed arguments, you may be able to use it directly in the GUI, as shown above, without any "controller" code. +The freedom to start from a routine with an arbitrary number of arguments, and choose which ones you want to close and which ones to leave open, provides a good part of the attraction of the agent mechanism. It means in particular that in GUI applications you can limit to the strict minimum the "glue" code (sometimes called the controller in the so-called MVC, Model-View Controller, scheme of GUI design) between the user interface and "business model" parts of a system. A routine such as record_city is a typical example of an element of the business model, uninfluenced -- as it should be -- by considerations of user interface design. Yet by passing it in the form of an agent with partially open and partially closed arguments, you may be able to use it directly in the GUI, as shown above, without any "controller" code. As another example of the mechanism's versatility, we saw above an integral function that could integrate a function of one variable over an interval, as in -your_integrator.integral (agent your_function (0, 1)) + your_integrator.integral (agent your_function (0, 1)) -Now assume that function3 takes three arguments. To integrate function3 with two arguments fixed, you don't need a new integral function; just use the same integral as before, judiciously selecting what to close and what to leave open: +Now assume that function3 takes three arguments. To integrate function3 with two arguments fixed, you don't need a new integral function; just use the same integral as before, judiciously selecting what to close and what to leave open: -your_integrator.integral (agent function3 (3.5, ?, 6.0), 0, 1) + your_integrator.integral (agent function3 (3.5, ?, 6.0), 0, 1) ==Open targets== -All the agent examples seen so far were based on routines of the enclosing class. This is not required. Feature calls, as you remember, were either unqualified, as in f (x, y) , or qualified, as in a.g (x, y) . Agents, too, have a qualified variant as in +All the agent examples seen so far were based on routines of the enclosing class. This is not required. Feature calls, as you remember, were either unqualified, as in f (x, y), or qualified, as in a.g (x, y). Agents, too, have a qualified variant as in -agent a.g + agent a.g -which is closed on its target a and open on the arguments. Variants such as agent a.g (x, y) , all closed, and agent a.g (?, y) , open on one argument, are all valid. +which is closed on its target a and open on the arguments. Variants such as agent a.g (x, y), all closed, and agent a.g (?, y), open on one argument, are all valid. -You may also want to make the target open. The question mark syntax could not work here, since it wouldn't tell us the class to which feature g belongs, known in the preceding examples from the type of a . As in creation expressions, we must list the type explicitly; the convention is the same: write the types in braces, as in +You may also want to make the target open. The question mark syntax could not work here, since it wouldn't tell us the class to which feature g belongs, known in the preceding examples from the type of a. As in creation expressions, we must list the type explicitly; the convention is the same: write the types in braces, as in -agent {SOME_TYPE}.g -agent {SOME_TYPE}.g (?, ?) -agent {SOME_TYPE}.g (?, y) + agent {SOME_TYPE}.g + agent {SOME_TYPE}.g (?, ?) + agent {SOME_TYPE}.g (?, y) The first two of these examples are open on the target and both operands; they mean the same. The third is closed on one argument, open on the other and on the target. These possibilities give even more flexibility to the mechanism because they mean that an operation that needs agents with certain arguments open doesn't care whether they come from an argument or an operand of the original routine. This is particularly useful for iterators and means that if you have two lists -your_account_list: LIST [ACCOUNT] -your_integer_list: LIST [INTEGER] + your_account_list: LIST [ACCOUNT] + your_integer_list: LIST [INTEGER] you may write both -your_account_list.do_all (agent deposit_one_grand) -your_integer_list.do_all (agent add_to_n) + your_account_list.do_all (agent deposit_one_grand) + your_integer_list.do_all (agent add_to_n) -even though the two procedures used in the agents have quite different forms. We are assuming here that the first one, in class ACCOUNT , is something like +even though the two procedures used in the agents have quite different forms. We are assuming here that the first one, in class ACCOUNT, is something like -deposit_one_grand is - -- Add one thousand dollars to `balance' of account. - do - balance := balance + 1000 - end + deposit_one_grand + -- Add one thousand dollars to `balance' of account. + do + balance := balance + 1000 + end -so that it doesn't take an argument: it is normally called on its target, as in my_account.deposit_one_grand . In contrast, the other routine has an argument: +so that it doesn't take an argument: it is normally called on its target, as in my_account.deposit_one_grand. In contrast, the other routine has an argument: -add_to_n (x: INTEGER) is - -- Add `x' to the value of `total'. - do - total := total + x - end + add_to_n (x: INTEGER) + -- Add `x' to the value of `total'. + do + total := total + x + end -where total is an integer attribute of the enclosing class. Without the versatility of playing with open and closed arguments for both the original arguments and target, you would have to write separate iteration mechanisms for these two cases. Here you can use a single iteration routine of LIST and similar classes of EiffelBase, do_all , for both purposes:
+where total is an integer attribute of the enclosing class. Without the versatility of playing with open and closed arguments for both the original arguments and target, you would have to write separate iteration mechanisms for these two cases. Here you can use a single iteration routine of LIST and similar classes of EiffelBase, do_all, for both purposes:
* Depositing money on every account in a list of accounts. * Adding all the integers in a list of integers. diff --git a/documentation/current/method/eiffel-tutorial-et/et-dynamic-structure-execution-model.wiki b/documentation/current/method/eiffel-tutorial-et/et-dynamic-structure-execution-model.wiki index e61edfe7..e7293af6 100644 --- a/documentation/current/method/eiffel-tutorial-et/et-dynamic-structure-execution-model.wiki +++ b/documentation/current/method/eiffel-tutorial-et/et-dynamic-structure-execution-model.wiki @@ -106,7 +106,7 @@ It's easy to deduce, from a feature's syntactic appearance, the category to whic Classes, as noted, are a static notion. Objects appear at run time; they are created explicitly. Here is the basic instruction to create an object of type ACCOUNT and attach it to x: - create x + create x assuming that x has been declared of type ACCOUNT. Such an instruction must be in a routine of some class -- the only place where instructions can appear -- and its effect at run time will be threefold: create a new object of type ACCOUNT; initialize its fields to default values; and attach the value of x to it. Here the object will have two fields corresponding to the two attributes of the generating class: an integer for balance, which will be initialized to 0, and a reference for all_deposits, which will be initialized to a void reference: @@ -197,7 +197,7 @@ A create clause may list zero or more (here just one) procedures of In this case the original form of creation instruction, create x , is not valid any more for creating an instance of ACCOUNT1; you must use the form - create x.make (2000) + create x.make (2000) known as a creation call. Such a creation call will have the same effect as the original form -- creation, initialization, attachment to -- x followed by the effect of calling the selected creation procedure, which here will call deposit with the given argument. @@ -216,28 +216,28 @@ The example assumed x declared of type ACCOUNT (or -deposit (sum: INTEGER) - -- Add sum to account. - local - new: AMOUNT - do - create new.make (sum) - all_deposits.extend (new) - balance := balance + sum - end + deposit (sum: INTEGER) + -- Add sum to account. + local + new: AMOUNT + do + create new.make (sum) + all_deposits.extend (new) + balance := balance + sum + end This example is a variant of deposit for which we assume that the elements of a DEPOSIT_LIST such as all_deposits are no longer just integers, but objects, instances of a new class, AMOUNT. Such an object will contain an integer value, but possibly other information as well. So for the purpose of procedure deposit we create an instance of AMOUNT and insert it, using procedure extend, into the list all_deposits. The object is identified through the local entity new, which is only needed within each execution of the routine (as opposed to an attribute, which yields an object field that will remain in existence for as long as the object). The last case of entity, Result, serves to denote, within the body of a function, the final result to be returned by that function. This was illustrated by the function deposit_count, which read -deposit_count: INTEGER - -- Number of deposits made since opening (provisional version) - do - if all_deposits /= Void then - Result := all_deposits.count + deposit_count: INTEGER + -- Number of deposits made since opening (provisional version) + do + if all_deposits /= Void then + Result := all_deposits.count + end end - end The value returned by any call will be the value of the expression all_deposits.count (to be explained in detail shortly) for that call, unless all_deposits is a Void reference ( /= means "not equal"). @@ -248,29 +248,29 @@ The default initialization rules seen earlier for attributes (see the table abov Apart from object creation, the basic computational mechanism, in the object-oriented style of computation represented by Eiffel, is feature call. In its basic form, it appears as - target.feature (argument1, ...) + target.feature (argument1, ...) where target is an entity or more generally an expression, feature is a feature name, and there may be zero or more argument expressions. In the absence of any argument the part in parentheses should be removed. We have already seen such calls. If the feature denotes a procedure, the call is an instruction, as in - all_deposits.extend (new) + all_deposits.extend (new) If feature denotes a query (function or attribute), the call is an expression, as in the right-hand side of - Result := all_deposits.count + Result := all_deposits.count Following the principle of Uniform Access (mentioned earlier in the section ''Objects, fields, values, and references''), this form is the same for calls to attributes and to functions without arguments. In this example, feature count from class DEPOSIT_LIST may indeed be implemented in either of these two ways: we can keep a count field in each list, updating it for each insertion and removal; or we can compute count, whenever requested, by traversing the list and counting the number of items. In the case of a routine with arguments -- procedure or function -- the routine will be declared, in its class, as -some_feature (formal_1: TYPE_1; ...) - do - ... - end + some_feature (formal_1: TYPE_1; ...) + do + ... + end meaning that, at the time of each call, the value of each formal will be set to the corresponding actual (formal_1 to argument_1 and so on). @@ -283,18 +283,19 @@ Basic types such as INTEGER are, as noted, full-status citizens of With the dot notation seen so far, this would imply that simple arithmetic operations would have to be written with a syntax such as - i.plus (j) + i.plus (j) instead of the usual - i + j + i + j + This would be awkward. Infix and prefix features solve the problem, reconciling the object-oriented view of computation with common notational practices of mathematics. The addition function is declared in class INTEGER as -infix "+" (other: INTEGER): INTEGER - do - ... - end + infix "+" (other: INTEGER): INTEGER + do + ... + end Such a feature has all the properties and prerogatives of a normal "identifier" feature, except for the form of the calls, which is infix, as in i + j , rather than using dot notation. An infix feature must be a function, and take exactly one argument. Similarly, a function can be declared as prefix "-" , with no argument, permitting calls of the form -3 rather than (3).negated . @@ -303,19 +304,19 @@ Predefined library classes covering basic types such as INTEGER, infix "|-|" for a function computing the distance between two points, to be used in expressions such as - point1 |-| point2 + point1 |-| point2 ==Type declaration== Every entity appearing in an Eiffel text is declared as being of a certain type, using the syntax already encountered in the above examples: - entity_name: TYPE_NAME + entity_name: TYPE_NAME This applies to attributes, formal arguments of routines and local entities. You will also declare the result type for a function, as in the earlier example - deposit_count: INTEGER ... + deposit_count: INTEGER ... Specifying such a function result type also declares, implicitly, the type for Result as used in the function's body. @@ -337,7 +338,7 @@ class CLASS_NAME ... it defines a reference type. The entities declared of that type will denote references. So in the declaration - x: ACCOUNT + x: ACCOUNT the possible run-time values for x are references, which will be either void or attached to instances of class ACCOUNT . @@ -366,7 +367,7 @@ In this case the value of an entity declared as n: INTEGER is not a It is also possible, for some non-expanded class C, to declare an entity as - x: expanded C + x: expanded C so that the values for x will be objects of type C, rather than references to such objects. This is our first example of a type -- expanded C -- that is not directly a class, although it is based on a class, C. The base type of such a type is C. @@ -400,7 +401,7 @@ To assign, copy and compare values, you can rely on a number of mechanisms. Two Assignment uses the symbol := . The assignment instruction - x := y + x := y updates the value of x to be the same as that of y. This means that: @@ -419,18 +420,18 @@ For entities of expanded types, the values are objects; the object attached to < To copy an object, use - x.copy (y) + x.copy (y) which assumes that both x and y are non-void, and copies the contents of y's attached object onto those of x's. For expanded entities the effect is the same as that the of the assignment x := y. An operation performing similar duty to copy is twin . The assignment - x := y.twin + x := y.twin produces a newly created object (provided that y is non-void), initialized with a copy of the object attached to y and attaches the result to x . This means we may view twin as a function that performs the following two steps: - create Result - Result.copy (Current) + create Result + Result.copy (Current) The new object is created, then its content is updated to match the content of y to which the twin call is targeted. @@ -439,38 +440,38 @@ So, assuming both entities of reference types and y not void, the a To determine whether two values are equal, use the expression: - x = y + x = y For references, this comparison will yield true if the values are either both void or both attached to the same object; this is the case in the last figure in the state after the assignment, but not before. The symbol for not equal is /= , as in: - x /= y + x /= y As with assignment, there is also a form that works on objects rather than references: - x.is_equal (y) + x.is_equal (y) will return true when x and y are both non-void and attached to field-by-field identical objects. This can be true even when x = y is not, for example, in the figure, ''before'' the assignment, if the two objects shown are field-by-field equal. The expression x.is_equal (y) can be written alternatively in a notation similar in form to x = y . The expression: - x ~ y + x ~ y will be true only in cases in which x.is_equal (y) is true. A more general variant of is_equal is used under the form: - equal (x, y) + equal (x, y) This is always defined, even if x is void, returning true whenever is_equal would but also if x and y are both void. (In contrast, x.is_equal (y) is not defined for void x and would, if evaluated, yield an exception as explained in [[8 Design by Contract (tm), Assertions and Exceptions#Exception_handling|"Exception handling"]] below.) Void denotes a void reference. So you can make x void through the assignment - x := Void + x := Void and test whether it is void through: - if x = Void then ... + if x = Void then ... Note that the assignment, := , and the equality operators, =, ~, /~, and /= , are language constructions, whereas copy, twin, is_equal, and equal are '''library features''' coming from class ANY . @@ -488,7 +489,7 @@ It is useful, in some cases, to duplicate not just one object but an entire obje A related mechanism provides a powerful '''persistence''' facility. A call of the form - x.store (Some_file_or_network_connection) + x.store (Some_file_or_network_connection) will store a copy of the entire object structure starting at x , under a suitable representation. Like deep_twin, procedure store will follow all references to the end and maintain the properties of the structure. The function retrieved can then be used -- in the same system, or another -- to recreate the structure from the stored version. @@ -543,7 +544,7 @@ This form indicates that the features appearing in that clause are only '''avail With this specification a class text including the declaration acc: ACCOUNT and a call of the form - acc.all_deposits + acc.all_deposits violates the Feature Call rule and will be rejected by the EiffelStudio compiler. @@ -567,27 +568,27 @@ The preceding elements make it possible to understand the overall scheme of an E At any time during the execution of a system, one object is the '''current object''' of the execution, and one of the routines of the system, the '''current routine''', is being executed, with the current object as its target. (We will see below how the current object and current routine are determined.) The text of a class, in particular its routines, make constant implicit references to the current object. For example in the instruction - balance := balance + sum + balance := balance + sum appearing in the body of procedure deposit of class ACCOUNT, the name of the attribute balance, in both occurrences, denotes the balance field of the current object, assumed to be an instance of ACCOUNT. In the same way, the procedure body that we used for the creation procedure make in the ACCOUNT1 variant -make (sum: INTEGER) - -- Initialize account with sum . - do - deposit (sum) - end + make (sum: INTEGER) + -- Initialize account with sum . + do + deposit (sum) + end contains a call to the procedure deposit. Contrary to earlier calls written in dot notation as target.feature (...), the call to deposit has no explicit target; this means its target is the current object, an instance of ACCOUNT1. Such a call is said to be '''unqualified'''; those using dot notations are '''qualified''' calls. Although most uses of the current object are implicit, a class may need to name it explicitly. The predefined expression Current is available for that purpose. A typical use, in a routine merge (other: ACCOUNT ) of class ACCOUNT, would be a test of the form - if other = Current then - report_error ("Error: trying to merge an account with itself!") - else - ... Normal processing (merging two different account) ... - end + if other = Current then + report_error ("Error: trying to merge an account with itself!") + else + ... Normal processing (merging two different account) ... + end With these notions it is not hard to define precisely the overall scenario of a system execution by defining which object and routine will, at each instant, be the current object and the current routine: @@ -610,11 +611,11 @@ Restricting assignment targets to entities precludes assignments of the form obj.set_attribute (some_value) , where the base class of obj's type has defined the procedure -set_attribute (v: VALUE_TYPE) - -- Set value of attribute to v. - do - attribute := v - end + set_attribute (v: VALUE_TYPE) + -- Set value of attribute to v. + do + attribute := v + end This rule is essential to enforcing the method. Permitting direct assignments to an object's fields -- as in C++ and Java -- would violate all the tenets of information hiding by letting clients circumvent the interface carefully crafted by the author of a supplier class. It is the responsibility of each class author to define the exact privileges that the class gives to each of its clients, in particular field modification rights. Building a class is like building a machine: you design the internals, to give yourself the appropriate mechanisms; and you design the control panel, letting users (clients) access the desired subset of these mechanisms, safely and conveniently. diff --git a/documentation/current/method/eiffel-tutorial-et/et-lexical-conventions-and-style-rules.wiki b/documentation/current/method/eiffel-tutorial-et/et-lexical-conventions-and-style-rules.wiki index bc120f37..976d827b 100644 --- a/documentation/current/method/eiffel-tutorial-et/et-lexical-conventions-and-style-rules.wiki +++ b/documentation/current/method/eiffel-tutorial-et/et-lexical-conventions-and-style-rules.wiki @@ -6,7 +6,7 @@ Eiffel software texts are free-format: distribution into lines is not semantical Successive declarations or instructions may be separated by semicolons. Eiffel's syntax has been so designed, however, that (except in rare cases) '''the semicolon is optional'''. Omitting semicolons for elements appearing on separate lines lightens text and is the recommended practice since semicolons, as used by most programming languages, just obscure the text by distracting attention from the actual contents. Do use semicolons if you occasionally include successive elements on a single line. -56 names -- all unabbreviated single English words, except for elseif which is made of two words -- are reserved, meaning that you cannot use them to declare new entities. Here is the list: +56 names -- all unabbreviated single English words, except for elseif which is made of two words -- are reserved, meaning that you cannot use them to declare new entities. Here is the list: {| border="1" |- | agent @@ -76,25 +76,25 @@ Successive declarations or instructions may be separated by semicolons. Eiffel's Since this tutorial has covered all the essential mechanisms, you may ignore the keywords not encountered; they are reserved for future use. -Most of the reserved words are keywords, serving only as syntactic markers, and written in boldface in typeset texts such as the present one: class , feature , inherit . The others, such as Current , directly carry a semantic denotation; they start with an upper-case letter and are typeset in boldface. +Most of the reserved words are keywords, serving only as syntactic markers, and written in boldface in typeset texts such as the present one: class, feature, inherit. The others, such as Current, directly carry a semantic denotation; they start with an upper-case letter and are typeset in boldface. -These conventions about letter case are only style rules. Eiffel is case-insensitive, since it is foolish to assume that two identifiers denote two different things just on the basis of a letter written in lower or upper case. The obvious exception is manifest character constants (appearing in single quotes, such as 'A' ) and manifest character strings (appearing in double quotes, such as "UPPER and lower" ). +These conventions about letter case are only style rules. Eiffel is case-insensitive, since it is foolish to assume that two identifiers denote two different things just on the basis of a letter written in lower or upper case. The obvious exception is manifest character constants (appearing in single quotes, such as 'A') and manifest character strings (appearing in double quotes, such as "UPPER and lower"). The style rules, however, are precise, and any serious Eiffel project will enforce them; the tools of EiffelStudio also observe them in the texts they output (although they will not mess up with your source text unless you ask them to reformat it). Here are the conventions, illustrated by the examples of this tutorial: -* Class names in upper case, as ACCOUNT . -* Non-constant feature names and keywords in lower case, as balance and class . -* Constant features and predefined entities and expressions with an initial upper case, as Avogadro and Result . +* Class names in upper case, as ACCOUNT. +* Non-constant feature names and keywords in lower case, as balance and class. +* Constant features and predefined entities and expressions with an initial upper case, as Avogadro and Result. -In typeset documents including Eiffel texts, the standard for font styles is also precise. You should use bold face for keywords and italics for all other Eiffel elements. Comments, however, are typeset in roman . This lets a software element, such as an identifier, stand out clearly in what is otherwise a comment text expressed in English or another human language, as in the earlier example +In typeset documents including Eiffel texts, the standard for font styles is also precise. You should use bold face for keywords and italics for all other Eiffel elements. Comments, however, are typeset in roman. This lets a software element, such as an identifier, stand out clearly in what is otherwise a comment text expressed in English or another human language, as in the earlier example --- Add `sum' to account. + -- Add `sum' to account. -which makes clear that sum is a software element, not the English word. +which makes clear that sum is a software element, not the English word. -There is also an Eiffel style to the choice of identifiers. For features, stay away from abbreviations and use full words. In multi-word identifiers, separate the constituents by underscores, as in LINKED_LIST and set_owner . The competing style of no separation but mid-identifier upper-case, as in linkedList or setOwner , is less readable and not in line with standard Eiffel practices. +There is also an Eiffel style to the choice of identifiers. For features, stay away from abbreviations and use full words. In multi-word identifiers, separate the constituents by underscores, as in LINKED_LIST and set_owner. The competing style of no separation but mid-identifier upper-case, as in linkedList or setOwner, is less readable and not in line with standard Eiffel practices. -Features of reusable classes should use consistent names. A set of standard names -- put for the basic command to add or replace an element, count for the query that returns the number of element in a structure, item to access an element -- is part of the style rules, and used systematically in EiffelBase. Use them in your classes too. +Features of reusable classes should use consistent names. A set of standard names -- put for the basic command to add or replace an element, count for the query that returns the number of element in a structure, item to access an element -- is part of the style rules, and used systematically in EiffelBase. Use them in your classes too. For local entities and formal arguments of routines, it is all right to use abbreviated names, since these identifiers only have a local scope, and choosing a loud name would give them too much pretense, leading to potential conflicts with features. diff --git a/documentation/current/method/eiffel-tutorial-et/et-other-mechanisms.wiki b/documentation/current/method/eiffel-tutorial-et/et-other-mechanisms.wiki index f93ae567..b6f51202 100644 --- a/documentation/current/method/eiffel-tutorial-et/et-other-mechanisms.wiki +++ b/documentation/current/method/eiffel-tutorial-et/et-other-mechanisms.wiki @@ -12,18 +12,18 @@ Eiffel addresses this need through an original mechanism that also takes care of In the case of procedures, this provides a convenient initialization mechanism. A delicate problem in the absence of a once mechanism is how to provide the users of a library with a set of routines which they can call in any order, but which all need, to function properly, the guarantee that some context had been properly set up. Asking the library clients to precede the first call with a call to an initialization procedure setup is not only user-unfriendly but silly: in a well-engineered system we will want to check proper set-up in every of the routines, and report an error if necessary; but then if we were able to detect improper set-up we might as well shut up and set up ourselves (by calling setup). This is not easy, however, since the object on which we call setup must itself be properly initialized, so we are only pushing the problem further. Making setup a once procedure solves it: we can simply include a call -setup + setup at the beginning of each affected routine; the first one to come in will perform the needed initializations; subsequent calls will have, as desired, no effect. Once functions will give us shared objects. A common scheme is -console: WINDOW is - -- Shared console window - once - create Result.make (...) - end + console: WINDOW + -- Shared console window + once + create Result.make (...) + end Whatever client first calls this function will create the appropriate window and return a reference to it. Subsequent calls, from anywhere in the system, will return that same reference. The simplest way to make this function available to a set of classes is to include it in a class SHARED_STRUCTURES which the classes needing a set of related shared objects will simply inherit. @@ -38,16 +38,16 @@ The attributes studied earlier were variable: each represents a field present in It is also possible to declare constant attributes, as in -Solar_system_planet_count: INTEGER is 9 + Solar_system_planet_count: INTEGER = 9 These will have the same value for every instance and hence do not need to occupy any space in objects at execution time. (In other approaches similar needs would be addressed by symbolic constants, as in Pascal or Ada, or macros, as in C.) -What comes after the is is a manifest constant: a self-denoting value of the appropriate type. Manifest constants are available for integers, reals (also used for doubles), booleans ( True and False), characters (in single quotes, as 'A', with special characters expressed using a percent sign as in '%N' for new line, '%B' for backspace and '%U' for null). +What comes after the = is a manifest constant: a self-denoting value of the appropriate type. Manifest constants are available for integers, reals (also used for doubles), booleans ( True and False), characters (in single quotes, as 'A', with special characters expressed using a percent sign as in '%N' for new line, '%B' for backspace and '%U' for null). For integer constants, it is also possible to avoid specifying the values. A declaration of the form -a, b, c, ... n : INTEGER is unique + a, b, c, ... n : INTEGER = unique introduces a, b, c, ... n as constant integer attributes, whose value are assigned by the Eiffel compiler rather than explicitly by the programmer. The values are different for all unique attributes in a system; they are all positive, and, in a single declaration such as the above, guaranteed to be consecutive (so that you may use an invariant property of the form code > a and code < n to express that code should be one of the values). This mechanism replaces the "enumerated types" found in many languages, without suffering from the same problems. (Enumerated types have an ill-defined place in the type system; and it is not clear what operations are permitted.) @@ -56,12 +56,12 @@ You may use Unique values in conjunction with the inspect multi-bra Manifest constants are also available for strings, using double quotes as in -User_friendly_error_message: STRING is "Go get a life !" + User_friendly_error_message: STRING is "Go get a life !" with special characters again using the % codes. It is also possible to declare manifest arrays using double angle brackets: -<<1, 2, 3, 5, 7, 11, 13, 17, 19>> + <<1, 2, 3, 5, 7, 11, 13, 17, 19>> which is an expression of type ARRAY [INTEGER]. Manifest arrays and strings are not atomic, but denote instances of the Kernel Library classes STRING and ARRAY, as can be produced by once functions. @@ -70,23 +70,33 @@ which is an expression of type ARRAY [INTEGER]. Manifest arrays and Eiffel has a remarkably small set of instructions. The basic computational instructions have been seen: creation, assignment, assignment attempt, procedure call, retry. They are complemented by control structures: conditional, multi-branch, loop, as well as debug and check. -A conditional instruction has the form if ... then ... elseif ... then ... else ... end. The elseif ... then ... part (of which there may be more than one) and the else ... part are optional. After if and elseif comes a boolean expression; after then, elseif and else come zero or more instructions. +A conditional instruction has the form + + if ... then + ... + elseif ... then + ... + else + ... + end + +The elseif ... then ... part (of which there may be more than one) and the else ... part are optional. After if and elseif comes a boolean expression; after then, elseif and else come zero or more instructions. A multi-branch instruction has the form -inspect - ''exp'' -when ''v1'' then - ''inst1'' -when ''v2'' then - ''inst2'' -... -else - ''inst0'' -end + inspect + ''exp'' + when ''v1'' then + ''inst1'' + when ''v2'' then + ''inst2'' + ... + else + ''inst0'' + end -where the else ''inst0'' part is optional, exp is a character or integer expression, ''v1'', ''v1'', ... are constant values of the same type as exp, all different, and ''inst0'', ''inst1'', ''inst2'', ... are sequences of zero or more instructions. In the integer case, it is often convenient to use unique values ( [[10 Other Mechanisms|"Constant and unique attributes", page 83]] ) for the ''vi'' +where the else ''inst0'' part is optional, exp is a character or integer expression, ''v1'', ''v1'', ... are constant values of the same type as exp, all different, and ''inst0'', ''inst1'', ''inst2'', ... are sequences of zero or more instructions. In the integer case, it is often convenient to use unique values ( [[10 Other Mechanisms|"Constant and unique attributes", page 83]] ) for the ''vi''. The effect of such a multi-branch instruction, if the value of exp is one of the ''vi'', is to execute the corresponding ''insti''. If none of the ''vi'' matches, the instruction executes ''inst0'', unless there is no else part, in which case it triggers an exception. @@ -94,17 +104,17 @@ The effect of such a multi-branch instruction, if the value of exp The loop construct has the form -from - ''initialization'' -until - ''exit'' -invariant - ''inv'' -variant - ''var'' -loop - ''body'' -end + from + ''initialization'' + until + ''exit'' + invariant + ''inv'' + variant + ''var'' + loop + ''body'' + end where the invariant ''inv'' and variant ''var'' parts are optional, the others required. ''initialization'' and ''body'' are sequences of zero or more instructions; ''exit'' and ''inv'' are boolean expressions (more precisely, ''inv'' is an assertion); ''var'' is an integer expression. @@ -113,34 +123,41 @@ The effect is to execute ''initialization'', then, zero or more times until ''ex The assertion ''inv'', if present, expresses a '''loop invariant''' (not to be confused with class invariants). For the loop to be correct, ''initialization'' must ensure ''inv'', and then every iteration of ''body'' executed when ''exit'' is false must preserve the invariant; so the effect of the loop is to yield a state in which both ''inv'' and ''exit'' are true. The loop must terminate after a finite number of iterations, of course; this can be guaranteed by using a '''loop variant''' ''var''. It must be an integer expression whose value is non-negative after execution of ''initialization'', and decreased by at least one, while remain non-negative, by any execution of ''body'' when ''exit'' is false; since a non-negative integer cannot be decreased forever, this ensures termination. The assertion monitoring mode, if turned on at the highest level, will check these properties of the invariant and variant after initialization and after each loop iteration, triggering an exception if the invariant does not hold or the variant is negative or does not decrease. -An occasionally useful instruction is debug (''Debug_key'', ... ) ''instructions'' end where ''instructions'' is a sequence of zero or more instructions and the part in parentheses is optional, containing if present one or more strings, called debug keys. The EiffelStudio compiler lets you specify the corresponding debug compilation option: yes, no, or an explicit debug key. The ''instructions''will be executed if and only if the corresponding option is on. The obvious use is for instructions that should be part of the system but executed only in some circumstances, for example to provide extra debugging information. +An occasionally useful instruction is debug (''Debug_key'', ... ) ''instructions'' end where ''instructions'' is a sequence of zero or more instructions and the part in parentheses is optional, containing if present one or more strings, called debug keys. The EiffelStudio compiler lets you specify the corresponding debug compilation option: yes, no, or an explicit debug key. The ''instructions'' will be executed if and only if the corresponding option is on. The obvious use is for instructions that should be part of the system but executed only in some circumstances, for example to provide extra debugging information. -The final instruction is connected with Design by Contract™. The instruction check ''Assertion'' end, where ''Assertion'' is a sequence of zero or more assertions, will have no effect unless assertion monitoring is turned on at the Check level or higher. If so it will evaluate all the assertions listed, having no further effect if they are all satisfied; if any one of them does not hold, the instruction will trigger an exception. +The final instruction is connected with Design by Contract™. The instruction + + check + Assertion + end +, where Assertion is a sequence of zero or more assertions, will have no effect unless assertion monitoring is turned on at the Check level or higher. If so it will evaluate all the assertions listed, having no further effect if they are all satisfied; if any one of them does not hold, the instruction will trigger an exception. This instruction serves to state properties that are expected to be satisfied at some stages of the computation -- other than the specific stages, such as routine entry and exit, already covered by the other assertion mechanisms such as preconditions, postconditions and invariants. A recommended use of check involves calling a routine with a precondition, where the call, for good reason, does not explicitly test for the precondition. Consider a routine of the form -r (ref: SOME_REFERENCE_TYPE) is - require - not_void: ref /= Void - do - ref.some_feature - ... - end + r (ref: SOME_REFERENCE_TYPE) + require + not_void: ref /= Void + do + ref.some_feature + ... + end Because of the call to some_feature, the routine will only work if its precondition is satisfied on entry. To guarantee this precondition, the caller may protect it by the corresponding test, as in -if x /= Void then a.r (x) end + if x /= Void then + a.r (x) + end but this is not the only possible scheme; for example if an create x appears shortly before the call we know x is not void and do not need the protection. It is a good idea in such cases to use a check instruction to document this property, if only to make sure that a reader of the code will realize that the omission of an explicit test (justified or not) was not a mistake. This is particularly appropriate if the justification for not testing the precondition is less obvious. For example x could have been obtained, somewhere else in the algorithm, as clone (y) for some y that you know is not void. You should document this knowledge by writing the call as -check - x_not_void: x /= Void end - -- Because x was obtained as a clone of y, - -- and y is not void because [etc.] -end -a.r (x) + check + x_not_void: x /= Void end + -- Because x was obtained as a clone of y, + -- and y is not void because [etc.] + end + a.r (x) {{recommended|An extra indentation of the check part to separate it from the algorithm proper; and inclusion of a comment listing the rationale behind the developer's decision not to check explicitly for the precondition. }} @@ -155,14 +172,14 @@ This raises the issue of backward compatibility: how to move forward with a bett The notion of obsolete class and feature helps address this issue. By declaring a feature as obsolete, using the syntax -enter (i: INTEGER; x: G) is - obsolete - "Use ` put (x, i)' instead " - require - ... - do - put (x, i) - end + enter (i: INTEGER; x: G) + obsolete + "Use ` put (x, i)' instead " + require + ... + do + put (x, i) + end you state that you are now advising against using it, and suggest a replacement through the message that follows the keyword obsolete, a mere string. The obsolete feature is still there, however; using it will cause no other harm than a warning message when someone compiles a system that includes a call to it. Indeed, you don't want to hold a gun to your client authors' forehead (''"Upgrade now or die !"''); but you do want to let them know that there is a new version and that they should upgrade at their leisure. @@ -182,38 +199,38 @@ The design flexibility afforded by the obsolete keyword is critical The basic forms of creation instruction, and the one most commonly used, are the two illustrated earlier ( [[6 The Dynamic Structure: Execution Model|"Creating and initializing objects", page 20]] ): -create x.make (2000) -create x + create x.make (2000) + create x the first one if the corresponding class has a create clause, the second one if not. In either form you may include a type name in braces, as in -create {SAVINGS_ACCOUNT} x.make (2000) + create {SAVINGS_ACCOUNT} x.make (2000) which is valid only if the type listed, here SAVINGS_ACCOUNT, conforms to the type of x, assumed here to be ACCOUNT. This avoids introducing a local entity, as in -local - xs: SAVINGS_ACCOUNT -do - create xs.make (2000) - x := xs - ... + local + xs: SAVINGS_ACCOUNT + do + create xs.make (2000) + x := xs + ... and has exactly the same effect. Another variant is the '''creation expression''', which always lists the type, but returns a value instead of being an instruction. It is useful in the following context: -some_routine (create {ACCOUNT}.make (2000)) + some_routine (create {ACCOUNT}.make (2000)) which you may again view as an abbreviation for a more verbose form that would need a local entity, using a creation instruction: -local - x: ACCOUNT -do - create x.make (2000) - some_routine (x) - ... + local + x: ACCOUNT + do + create x.make (2000) + some_routine (x) + ... Unlike creation instructions, creation expressions must always list the type explicitly, {ACCOUNT} in the example. They are useful in the case shown: creating an object that only serves as an argument to be passed to a routine. If you need to retain access to the object through an entity, the instruction create x ... is the appropriate construct. @@ -222,7 +239,7 @@ The creation mechanism gets an extra degree of flexibility through the notion of One final twist is the mechanism for creating instances of formal generic parameters. For x of type G in a class C [G], it wouldn't be safe to allow create x, since G stands for many possible types, all of which may have their own creation procedures. To allow such creation instructions, we rely on constrained genericity. You may declare a class as -[G -> T create cp end] + [G -> T create cp end] to make G constrained by T, as we learned before, and specify that any actual generic parameter must have cp among its creation procedures. Then it's permitted to use create x.cp, with arguments if required by cp, since it is guaranteed to be safe. The mechanism is very general since you may use ANY for T and default_create for cp. The only requirement on cp is that it must be a procedure of T, not necessarily a creation procedure; this permits using the mechanism even if T is deferred, a common occurrence. It's only descendants of T that must make cp a creation procedure, by listing it in the create clause, if they want to serve as actual generic parameters for C. @@ -231,7 +248,7 @@ to make G constrained by T, as we learned before, and The study of genericity described arrays. Another common kind of container objects bears some resemblance to arrays: sequences, or "tuples", of elements of specified types. The difference is that all elements of an array were of the same type, or a conforming one, whereas for tuples you will specify the types we want for each relevant element. A typical tuple type is of the form -TUPLE [X, Y, Z] + TUPLE [X, Y, Z] denoting a tuple of least three elements, such that the type of the first conforms to X, the second to Y, and the third to Z. @@ -242,7 +259,7 @@ You may list any number of types in brackets, including none at all: TUPLE To write the tuples themselves -- the sequences of elements, instances of a tuple type -- you will also use square brackets; for example -[x1, y1, z1] + [x1, y1, z1] with x1 of type X and so on is a tuple of type TUPLE [X, Y, Z]. @@ -253,8 +270,7 @@ Features available on tuple types include count: INTEGER, yielding Tuples are appropriate when these are the only operations you need, that is to say, you are using sequences with no further structure or properties. Tuples give you "anonymous classes" with predefined features count, item and put. A typical example is a general-purpose output procedure that takes an arbitrary sequence of values, of arbitrary types, and prints them. It may simply take an argument of type TUPLE, so that clients can call it under the form - -write ([ ''your_integer'' , ''your_real'', ''your_account'']) + write ([your_integer, your_real, your_account]) As soon as you need a type with more specific features, you should define a class. diff --git a/documentation/current/method/eiffel-tutorial-et/et-static-picture-system-organization.wiki b/documentation/current/method/eiffel-tutorial-et/et-static-picture-system-organization.wiki index 9994c8fa..627c9bac 100644 --- a/documentation/current/method/eiffel-tutorial-et/et-static-picture-system-organization.wiki +++ b/documentation/current/method/eiffel-tutorial-et/et-static-picture-system-organization.wiki @@ -59,11 +59,11 @@ Above classes, you will find the concept of cluster. A cluster is a group of rel The subsequent sections will show how to write Eiffel classes with their features. In an Eiffel system, however, not everything has to be written in Eiffel: some features may be '''external''' , coming from languages such as C, C++, Java, C# Fortran and others. For example a feature declaration may appear (in lieu of the forms seen later) as -file_status (filedesc: INTEGER): INTEGER - -- Status indicator for filedesc - external - "C" alias "_fstat" - end + file_status (filedesc: INTEGER): INTEGER + -- Status indicator for filedesc + external + "C" alias "_fstat" + end to indicate that it is actually an encapsulation of a C function whose original name is fstat _. The alias clause is optional, but here it is needed because the C name, starting with an underscore, is not valid as an Eiffel identifier. diff --git a/documentation/current/solutions/concurrent-computing/eiffelthread/eiffelthread-tutorial/once-features-multithreaded-mode.wiki b/documentation/current/solutions/concurrent-computing/eiffelthread/eiffelthread-tutorial/once-features-multithreaded-mode.wiki index dbd76374..45f73e54 100644 --- a/documentation/current/solutions/concurrent-computing/eiffelthread/eiffelthread-tutorial/once-features-multithreaded-mode.wiki +++ b/documentation/current/solutions/concurrent-computing/eiffelthread/eiffelthread-tutorial/once-features-multithreaded-mode.wiki @@ -1,5 +1,6 @@ [[Property:title|Once features in multithreaded mode]] [[Property:weight|4]] +[[Property:uuid|5578da29-7603-b501-1a7d-305d20fd6485]] ==Manipulating Once features in multithreaded mode== Eiffel introduced the powerful mechanism of once routines. A once routine has a body that will be executed only once, at the first call. Subsequent calls will have no further effect and, in the case of a function, will return the same result as the first. This provides a simple way of sharing objects in an object-oriented context. @@ -21,27 +22,27 @@ Moreover, an Eiffel programmer should be able to have an alternative between a o Here is what you will do to implement a once per process feature: class - TEST_ONCE_PER_PROCESS + TEST_ONCE_PER_PROCESS - feature +feature -- Access - object_per_thread: OBJECT is - -- Once per thread. - once - create Result.make - end + object_per_thread: OBJECT is + -- Once per thread. + once + create Result.make + end - object_per_process: OBJECT is - -- New 'object' (once per process) - -- that could be shared between threads - -- without reinitializing it. - indexing - once_status: global - once - create Result.make - end + object_per_process: OBJECT is + -- New 'object' (once per process) + -- that could be shared between threads + -- without reinitializing it. + indexing + once_status: global + once + create Result.make + end - end -- class TEST_ONCE_PER_PROCESS +end -- class TEST_ONCE_PER_PROCESS You can do the same with once procedures.