From 265a446dab911635f36f037eaa68eed6a4598c76 Mon Sep 17 00:00:00 2001 From: eiffel-org Date: Tue, 6 Feb 2018 13:41:39 +0000 Subject: [PATCH] merge changes from branch 17.05 onto trunk git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1941 abb3cda0-5349-4a8f-a601-0c33ac3a8c38 --- ...afety-background-definition-and-tools.wiki | 24 +- .../eiffel-two-minute-fact-sheet.wiki | 194 ++++++------- .../eiffel-tutorial-et/et-agents.wiki | 6 +- .../invitation-eiffel-i2e/i2e-classes.wiki | 2 +- .../i2e-design-contract-and-assertions.wiki | 2 +- ...e-event-driven-programming-and-agents.wiki | 2 +- ...tween-ise-eiffel-55-and-ise-eiffel-56.wiki | 4 +- .../type-selection.wiki | 2 +- .../eiffelbase/eiffelbase-tutorial/index.wiki | 1 - .../scoop-asynchronous-calls.wiki | 272 +++++++++--------- .../scoop-implementation.wiki | 42 +-- .../abel/tutorial/advanced-queries.wiki | 4 +- .../trunk/solutions/networking/index.wiki | 11 + .../eiffel-net/event-programming-agents.wiki | 34 ++- 14 files changed, 293 insertions(+), 307 deletions(-) diff --git a/documentation/trunk/eiffel/Language_reference/void-safe-programming-eiffel/void-safety-background-definition-and-tools.wiki b/documentation/trunk/eiffel/Language_reference/void-safe-programming-eiffel/void-safety-background-definition-and-tools.wiki index 72fb6ee1..4245f60c 100644 --- a/documentation/trunk/eiffel/Language_reference/void-safe-programming-eiffel/void-safety-background-definition-and-tools.wiki +++ b/documentation/trunk/eiffel/Language_reference/void-safe-programming-eiffel/void-safety-background-definition-and-tools.wiki @@ -55,7 +55,7 @@ Another thought might be that we could just have the compiler do all the work fo So, all of this boils down to the fact that we have to take some actions that help the compiler along. That's what the following are about. -===Certified Attachment Patterns (CAPs)=== +==Certified Attachment Patterns (CAPs)== We know that in the context of certain code patterns, it is clear that it would be impossible for a reference to be void. These patterns are identified and we call them CAPs, short for Certified Attachment Patterns. Here is a very straightforward example expressed in a syntax that should be familiar to all Eiffel developers: @@ -73,7 +73,7 @@ It is important to understand that in this example (and with other CAPs), {{note|You will find more useful information about CAPs in [[Creating a new void-safe project#More about CAPs|More about CAPs]]. Learn how certain code patterns are determined to be CAPs in [[What makes a Certified Attachment Pattern]]. }} -===The ''attached syntax'' (object test)=== +==The ''attached syntax'' (object test)== For the purposes of void-safety, the '''attached syntax''' does double duty for us. It allows us to make certain that a reference is attached, and it provides us a safe way to access objects that are attached to class attributes. @@ -100,7 +100,7 @@ In the example above, x is tested to make certain that it is attach One way to make sure we comply with the target rule would be always use a CAP or the attached syntax every time we want to apply a feature to a referenced object. That might work, but it falls among the impractical approaches to the problem ... it would break a very high percentage of existing Eiffel code, not to mention cluttering things up quite a bit. -===Types as "attached" or "detachable"=== +==Types as "attached" or "detachable"== Rather than trying to protect every feature call, Eiffel allows us to declare any variable as being of an '''attached type'''. This is an important extension to the Eiffel type system. @@ -126,7 +126,7 @@ This doesn't mean that on every declaration you must put either an ''attached ma In Eiffel then, all declarations will have types that are either '''attached''' or '''detachable'''. As a result, we need only use CAPs and the attached syntax with detachable types. So the important thing to remember is that ''direct access to class attributes of detachable types is never void-safe.'' -====Attachment and conformance==== +===Attachment and conformance=== The distinction between attached and detachable types results in a small but important addition to the rules of conformance. Because variables declared as attached types can never be void, then it is important not to allow any assignment of a detachable source to an attached target. However, assigning an attached source to a detachable target is permissible. The following code shows both cases (as described earlier, class types are attached by default). @@ -140,7 +140,7 @@ The distinction between attached and detachable types results in a small but imp -===Initialization rule=== +==Initialization rule== If we have attached types, then we can assume variables declared of these types, once attached, will always be attached. But how do they get attached in the first place? That's what the initialization rule is all about. @@ -173,7 +173,7 @@ Still, it's not too hard to understand the basics of initializing variables of a * A variable is considered properly set if it is '''self-initializing'''. What it means to be self-initializing is explained below. -===Self-initializing attributes=== +==Self-initializing attributes== A self-initializing attribute is guaranteed to have a value when accessed at run time. Declarations of self-initializing attributes are characterized by the use of the code that follows the attribute keyword. The code is executed to initialize the attribute in the case that the attribute is accessed prior to being initialized in any other way. @@ -188,7 +188,7 @@ So, self-initializing attributes are ordinary attributes, with the restriction t In the example above, the attribute value will be attached to an object of type STRING, in fact, the empty string, if no other initialization occurs before the first access of value. -===Rule for conformance=== +==Rule for conformance== You will remember that the Eiffel type system dictates that an assignment instruction: @@ -206,7 +206,7 @@ The same goes for routine calls. In a call: where x is the formal argument for r, then if x is of an attached type, then y must be of an attached type. -===Stable attributes=== +==Stable attributes== Stable attributes are really stable ''detachable'' attributes, as adding the concept of stability is meaningful only for detachable attributes. Declaring a detachable attribute as stable, means that it behaves like a detachable attribute except that its assignment rules mimic those of attached attributes. In other words, a stable attribute does not need to be attached during object creation the way that attributes declared as attached must. But like attached type attributes, stable attributes can never be the target of an assignment in which the source is Void or a detachable type. @@ -221,7 +221,7 @@ This means that even though stable attributes do not need to be initialized like Stable attributes are also interesting in that they are the only exception to the rule given above in the [[Void-safety: Background, definition, and tools#Certified Attachment Patterns (CAPs)|CAPs section]] that stated that direct access to attributes cannot be protected by a CAP. A stable attribute can be used under the protection of a CAP. This is because once a stable attribute has an object attached, it can never again be set to Void. So there's no worry about having the attribute's state going unexpectedly from attached to non-attached because of the actions of other routines or threads. -===Rule for generic parameters=== +==Rule for generic parameters== Generic classes provide another question. A generic class like @@ -265,7 +265,7 @@ class C [G -> attached ANY] then x in this class G represents an attached type. Consequently, the actual generic type in any derivation must be attached ... and feature calls on x are safe. -===Rule for ARRAYs=== +==Rule for ARRAYs== The rule for generic parameters applies to all generic types ... except ARRAYs. In the typical creation of an ARRAY, we would provide a minimum and maximum index. @@ -285,7 +285,3 @@ The first argument is an object of the actual generic type, in this case an empt For more detail on void-safe use of arrays and other generic classes, see the section: [[Creating a new void-safe project#Using generic classes|Using generic classes]]. - - - - diff --git a/documentation/trunk/eiffel/Overview/eiffel-two-minute-fact-sheet.wiki b/documentation/trunk/eiffel/Overview/eiffel-two-minute-fact-sheet.wiki index efad724c..ecd37799 100644 --- a/documentation/trunk/eiffel/Overview/eiffel-two-minute-fact-sheet.wiki +++ b/documentation/trunk/eiffel/Overview/eiffel-two-minute-fact-sheet.wiki @@ -1,97 +1,97 @@ -[[Property:title|Two-Minute fact sheet]] -[[Property:weight|0]] -[[Property:uuid|f672bfb8-ddea-beb1-eaa6-e374a6a6bc92]] -If you are both curious about Eiffel and in a hurry, take a couple of minutes to read these facts about Eiffel. If anything here seems too good to be true, please suspend your disbelief. Press on to the more detailed documentation for the rationale, and our success stories for the evidence behind these facts. - -===Eiffel is the most comprehensive approach to the construction of successful object-oriented software.=== - -Software produced with Eiffel is typically: - -*Cheaper -- You spend less on development, debugging, maintenance -*Better -- You get the bugs before they get you -*Shorter time-to-market -- You release quality products ahead of your competitors -*Easier -- In every way: understanding, maintenance, reuse, and extension - -===Systems developed using Eiffel can be made portable across major industry platforms.=== - -*Windows NT/2000/XP/Vista including CLS compliance on Microsoft .NET -*Major Unix versions -*Macintosh OS X -*Linux -*OpenVMS - -===Eiffel is the only approach that covers analysis, design, implementation and maintenance in a single framework.=== - -Eiffel consists of: - -====The Eiffel Method==== - -*Is Based on a small number of powerful ideas from computer science and software engineering -**An example of these is Design by Contract -***Defines a software system as a set of components interacting through precisely specified contracts -***Contracts are active and enforceable throughout the life-cycle -***Design by Contract promotes: -****Precise software specification -****Software reliability -****Safe, effective software reuse -*Uses a "single-product" model -**All life-cycle phases are supported by a single notation -***No need to switch, say, from "analysis language" to "design language" -**Products of all phases are recorded in a single document with multiple views - -====The Eiffel Programming Language==== - -*Exists to express the products of the Eiffel Method -*Supports features not always available in competing technologies -**Contracts and contract monitoring -**Exception handling based on software specification (versus ad hoc try/catch) -**Void-safety: calls on void (null) references are eliminated at compile time -**Inheritance -***Includes multiple and repeated inheritance -***Safe and fully controllable -**Genericity (generic classes), including constrained genericity -**Platform independent concurrency ([[Concurrent programming with SCOOP|SCOOP]]) -*Widely recognized as simultaneously the simplest and most complete implementation of object-oriented concepts -*Is clean, elegant, readable, easy to learn - - -====EiffelStudio and the Eiffel Libraries==== - -*'''EiffelStudio''' -**Runs on all major platforms (of course, it's built with Eiffel) -**Features lightning-fast compilation (Melting Ice Technology) -**Generates lightning-fast executables -***Final compilation generates standard C (MSIL in the case of .NET) -***Speed of executables rivals native C -**Provides multiple views of your product -***Views for different life-cycle phases and developer roles -***Graphical views -**Features automated generation HTML and XML documentation - -*'''The Eiffel Libraries''' -**Contain rich, time-tested, multi-platform components -**Include facilities for -***GUI building and graphics -***Web -***Networking -***Fundamental algorithms and data structures -***Object persistence and database access -***Multi-threading -***Lexical analysis and parsing -***Interfacing with other technologies - -===Eiffel has a proven track record of successful projects=== - -*Some of the largest successful object-oriented projects ever built, including systems target to: -**Finance and securities -**Education -**Trading -**Manufacturing -**Telecommunications -**Government and national defense -**Science - -For a more detailed overview see [[Invitation to Eiffel (I2E)|An Invitation to Eiffel]] . - - - +[[Property:title|Two-Minute fact sheet]] +[[Property:weight|0]] +[[Property:uuid|f672bfb8-ddea-beb1-eaa6-e374a6a6bc92]] +If you are both curious about Eiffel and in a hurry, take a couple of minutes to read these facts about Eiffel. If anything here seems too good to be true, please suspend your disbelief. Press on to the more detailed documentation for the rationale, and our success stories for the evidence behind these facts. + +===Eiffel is the most comprehensive approach to the construction of successful object-oriented software.=== + +Software produced with Eiffel is typically: + +*Cheaper -- You spend less on development, debugging, maintenance +*Better -- You get the bugs before they get you +*Shorter time-to-market -- You release quality products ahead of your competitors +*Easier -- In every way: understanding, maintenance, reuse, and extension + +===Systems developed using Eiffel can be made portable across major industry platforms.=== + +*Windows NT/2000/XP/Vista including CLS compliance on Microsoft .NET +*Major Unix versions +*Macintosh OS X +*Linux +*OpenVMS + +===Eiffel is the only approach that covers analysis, design, implementation and maintenance in a single framework.=== + +Eiffel consists of: + +====The Eiffel Method==== + +*Is Based on a small number of powerful ideas from computer science and software engineering +**An example of these is Design by Contract +***Defines a software system as a set of components interacting through precisely specified contracts +***Contracts are active and enforceable throughout the life-cycle +***Design by Contract promotes: +****Precise software specification +****Software reliability +****Safe, effective software reuse +*Uses a "single-product" model +**All life-cycle phases are supported by a single notation +***No need to switch, say, from "analysis language" to "design language" +**Products of all phases are recorded in a single document with multiple views + +====The Eiffel Programming Language==== + +*Exists to express the products of the Eiffel Method +*Supports features not always available in competing technologies +**Contracts and contract monitoring +**Exception handling based on software specification (versus ad hoc try/catch) +**Void-safety: calls on void (null) references are eliminated at compile time +**Inheritance +***Includes multiple and repeated inheritance +***Safe and fully controllable +**Genericity (generic classes), including constrained genericity +**Platform independent concurrency ([[Concurrent programming with SCOOP|SCOOP]]) +*Widely recognized as simultaneously the simplest and most complete implementation of object-oriented concepts +*Is clean, elegant, readable, easy to learn + + +====EiffelStudio and the Eiffel Libraries==== + +*'''EiffelStudio''' +**Runs on all major platforms (of course, it's built with Eiffel) +**Features lightning-fast compilation (Melting Ice Technology) +**Generates lightning-fast executables +***Final compilation generates standard C (MSIL in the case of .NET) +***Speed of executables rivals native C +**Provides multiple views of your product +***Views for different life-cycle phases and developer roles +***Graphical views +**Features automated generation of HTML and XML documentation + +*'''The Eiffel Libraries''' +**Contain rich, time-tested, multi-platform components +**Include facilities for +***GUI building and graphics +***Web +***Networking +***Fundamental algorithms and data structures +***Object persistence and database access +***Multi-threading +***Lexical analysis and parsing +***Interfacing with other technologies + +===Eiffel has a proven track record of successful projects=== + +*Some of the largest successful object-oriented projects ever built, including systems target to: +**Finance and securities +**Education +**Trading +**Manufacturing +**Telecommunications +**Government and national defense +**Science + +For a more detailed overview see [[Invitation to Eiffel (I2E)|An Invitation to Eiffel]] . + + + diff --git a/documentation/trunk/eiffel/Tutorials/eiffel-tutorial-et/et-agents.wiki b/documentation/trunk/eiffel/Tutorials/eiffel-tutorial-et/et-agents.wiki index 31ae2f59..03dc9616 100644 --- a/documentation/trunk/eiffel/Tutorials/eiffel-tutorial-et/et-agents.wiki +++ b/documentation/trunk/eiffel/Tutorials/eiffel-tutorial-et/et-agents.wiki @@ -51,7 +51,7 @@ Among the features of ROUTINE and its descendants the most importan 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 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 + integral (f: FUNCTION [TUPLE [REAL], REAL]; low, high: REAL): REAL -- Integral of `f' over the interval [`low', `high'] require meaningful_interval: low <= high @@ -120,7 +120,7 @@ In the agent agent record_city (name, population, ?, ?), we say tha 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 [TUPLE [INTEGER, INTEGER]] where the tuple type specifies the open operands. @@ -241,6 +241,8 @@ Inline agents are interesting also as an implementation of the notion of [http:/ Agents provide a welcome complement to the other mechanisms of Eiffel. They do not conflict with them but, when appropriate -- as in the examples sketched in this section -- provide clear and expressive programming schemes, superior to the alternatives. +Compatibility note: earlier versions of the agent classes (ROUTINE, PROCEDURE, FUNCTION, PREDICATE) had an extra initial generic parameter, for which ANY was generally used. The compiler has been engineered to accept the old style in most cases. + {{SeeAlso|[[Event Programming with Agents]] }} diff --git a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-classes.wiki b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-classes.wiki index 9c3ba152..51bd61cc 100644 --- a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-classes.wiki +++ b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-classes.wiki @@ -7,7 +7,7 @@ Such objects are called the '''direct instances''' of the class. Classes and obj {{info|"Object-Oriented" is a misnomer; "Class-Oriented Analysis, Design and Programming" would be a more accurate description of the method. }} -To see what a class looks like, let us look at a simple example, ACCOUNT, which describes bank accounts. But before exploring the class itself it is useful to study how it maybe used by other classes, called its '''clients'''. +To see what a class looks like, let us look at a simple example, ACCOUNT, which describes bank accounts. But before exploring the class itself it is useful to study how it may be used by other classes, called its '''clients'''. A class X may become a client of ACCOUNT by declaring one or more '''entities''' of type ACCOUNT. Such a declaration is of the form: acc: ACCOUNT diff --git a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-design-contract-and-assertions.wiki b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-design-contract-and-assertions.wiki index 9a8e9208..53f3af4a 100644 --- a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-design-contract-and-assertions.wiki +++ b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-design-contract-and-assertions.wiki @@ -143,7 +143,7 @@ Under EiffelStudio you may also set up compilation options, for the whole system This ability to check assertions provides a powerful testing and debugging mechanism, in particular because the classes of the EiffelBase Libraries, widely used in Eiffel software development, are protected by carefully written assertions. -Run-time monitoring, however, is only one application of assertions, whose role as design and documentation aids, as part of theory of Design by Contract™, exerts a pervasive influence on the Eiffel style of software development. +Run-time monitoring, however, is only one application of assertions, whose role as design and documentation aids, as part of the theory of Design by Contract™, exerts a pervasive influence on the Eiffel style of software development. diff --git a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-event-driven-programming-and-agents.wiki b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-event-driven-programming-and-agents.wiki index c7e7b9cb..b1c38b8a 100644 --- a/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-event-driven-programming-and-agents.wiki +++ b/documentation/trunk/eiffel/Tutorials/invitation-eiffel-i2e/i2e-event-driven-programming-and-agents.wiki @@ -1,7 +1,7 @@ [[Property:title|I2E: Event-Driven Programming and Agents]] [[Property:weight|-7]] [[Property:uuid|16fdab60-ae42-1bb8-f4bb-89e34d18a842]] -The division of roles in object technology is clear: of the two principal constituents of a system, object types and operations, the first dominates. Classes, representing object types, determines the structure of the software; every routine, representing an operations, belongs to a class. +The division of roles in object technology is clear: of the two principal constituents of a system, object types and operations, the first dominates. Classes, representing object types, determines the structure of the software; every routine, representing an operation, belongs to a class. In some circumstances it is useful to define an object that denotes an operation. This is especially useful if you want to build an object structure that refers to operations, so that you can later traverse the structure and execute the operations encountered. A typical application is '''event-driven programming''' for Graphical User Interfaces (GUI), including Web programming. In GUI programming you will want to record properties of the form diff --git a/documentation/trunk/eiffelstudio/eiffelstudio-reference/compiler/compiler-history/eiffelstudio-5-compiler-history/major-changes-between-ise-eiffel-55-and-ise-eiffel-56.wiki b/documentation/trunk/eiffelstudio/eiffelstudio-reference/compiler/compiler-history/eiffelstudio-5-compiler-history/major-changes-between-ise-eiffel-55-and-ise-eiffel-56.wiki index 475c979d..27fcfc3c 100644 --- a/documentation/trunk/eiffelstudio/eiffelstudio-reference/compiler/compiler-history/eiffelstudio-5-compiler-history/major-changes-between-ise-eiffel-55-and-ise-eiffel-56.wiki +++ b/documentation/trunk/eiffelstudio/eiffelstudio-reference/compiler/compiler-history/eiffelstudio-5-compiler-history/major-changes-between-ise-eiffel-55-and-ise-eiffel-56.wiki @@ -8,7 +8,9 @@ * Implemented once manifest strings. They can be used at the same places where normal manifest strings can be used, e.g.: s := once "abc" io.put_string (once "Hello World!") -Once manifest strings are not created every time they are accessed. Instead one instance is created at the first access and then it is reused for subsequent accesses.==What's new== +Once manifest strings are not created every time they are accessed. Instead one instance is created at the first access and then it is reused for subsequent accesses. + +==What's new== {{seealso|[[Differences between standard ECMA-367 and Eiffel Software implementation|Differences between standard ECMA-367 and Eiffel Software implementation]] }} * Implemented once manifest strings. They can be used at the same places where normal manifest strings can be used, e.g.: diff --git a/documentation/trunk/eiffelstudio/eiffelstudio-reference/wizards-and-dialogs/dialogs/new-feature-dialog/new-feature-dialog-feature-properties-modification/type-selection.wiki b/documentation/trunk/eiffelstudio/eiffelstudio-reference/wizards-and-dialogs/dialogs/new-feature-dialog/new-feature-dialog-feature-properties-modification/type-selection.wiki index 584f8a33..7bb9a499 100644 --- a/documentation/trunk/eiffelstudio/eiffelstudio-reference/wizards-and-dialogs/dialogs/new-feature-dialog/new-feature-dialog-feature-properties-modification/type-selection.wiki +++ b/documentation/trunk/eiffelstudio/eiffelstudio-reference/wizards-and-dialogs/dialogs/new-feature-dialog/new-feature-dialog-feature-properties-modification/type-selection.wiki @@ -37,7 +37,7 @@ The code generated for the selected type is quite straightforward, an example: [[Image:feature-wizard-complextype]] - new_feature: FUNCTION [ANY, TUPLE [INTEGER], BOOLEAN] + new_feature: FUNCTION [TUPLE [INTEGER], BOOLEAN] diff --git a/documentation/trunk/solutions/basic-computing/eiffelbase/eiffelbase-tutorial/index.wiki b/documentation/trunk/solutions/basic-computing/eiffelbase/eiffelbase-tutorial/index.wiki index 3f50107f..e76063cf 100644 --- a/documentation/trunk/solutions/basic-computing/eiffelbase/eiffelbase-tutorial/index.wiki +++ b/documentation/trunk/solutions/basic-computing/eiffelbase/eiffelbase-tutorial/index.wiki @@ -1,7 +1,6 @@ [[Property:title|EiffelBase Tutorial]] [[Property:weight|-2]] [[Property:uuid|d540615d-802b-8e12-af74-4d01d1fc4760]] -==EiffelBase Tutorial== Learn about the EiffelBase library. diff --git a/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-asynchronous-calls.wiki b/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-asynchronous-calls.wiki index b746f6ee..fd3bc333 100644 --- a/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-asynchronous-calls.wiki +++ b/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-asynchronous-calls.wiki @@ -1,136 +1,136 @@ -[[Property:title|Asynchronous Calls]] -[[Property:weight|6]] -[[Property:uuid|d3d3873c-5c84-7566-547e-1ede38544081]] -==Overview== - -As we've seen in [[Separate Calls]], feature calls to a non-separate target are always synchronous. -Furthermore, queries are always synchronous as well, because the caller has to wait for the result. - -{| border="1" -|- -! Target -! Query -! Command -|- -| non-separate -| synchronous -| synchronous -|- -| separate -| synchronous -| potentially asynchronous -|} - -Asynchronous calls can therefore only happen on commands with a separate target. -Indeed, such calls are by default executed asynchronously, but there are some important exceptions to this rule. -A command to a separate target is executed synchronously if any of the following applies: -* The client (caller) and supplier (target) region are the same. -* The target region is passive. -* The callee needs a lock currently held by the caller (lock passing). -* The caller holds the locks of the callee (separate callbacks). - -== Triggers for Synchronization == - -=== Same Regions === - -The first case happens when a reference is declared separate, but happens to be non-separate. This case follows directly from the type system: A non-separate type A always conforms to its variation separate A. At run-time such cases can be detected with an object test: - - -sep_object: separate A ---... -if attached {A} sep_object as non_sep_object then - -- ... -end - - -=== Passive Regions === - -In the SCOOP model, a passive region does not have a processor attached to it. -This means that clients of the passive region need to apply features logged against a passive region themselves. -The logical consequence of this is that all call to a passive region, including commands, are executed synchronously. - -=== Lock Passing === - -Lock passing is another source of synchronization. It is one of the trickiest issues to detect, and to fully understand it we must first introduce a few more definitions. - -In [[Exclusive Access]] we have learned that an object is ''controlled'' if it appears as a formal argument of the enclosing routine. SCOOP however always grants exclusive access over a whole region. We therefore introduce the new term ''Lock'': - -{{definition|Lock|Exclusive access to a SCOOP region and all objects therein.}} - -Note the difference between ''controlled'' and ''locked'': -* ''Controlled'' applies to a single object, whereas ''locked'' applies to a region. -* The ''controlled'' property can be determined statically at compile-time, whereas ''locked'' is determined at runtime. -* The set of ''controlled'' objects of a processor is always a subset of the set of objects in ''locked'' regions. - -{{note|In terms of implementation, a ''lock'' corresponds to an open call queue to a region.}} - -Now consider a small classes HASH_STORAGE and EXAMPLE: - -class HASH_STORAGE feature - - hash_code: INTEGER - - set_hash_code (a_string: separate STRING) - do - hash_code := a_string.hash_code - end -end - -class EXAMPLE feature - - run (a_hash_storage: separate HASH_STORAGE; a_string: separate STRING) - do - a_hash_storage.set_hash_code (a_string) - io.put_integer (a_hash_storage.hash_code) - end -end - - -You might notice a problem here: -In the feature {EXAMPLE}.run, exclusive access to 'a_hash_storage' and 'a_string' is guaranteed by the SCOOP semantics. -Or in other words, the corresponding regions are ''locked''. The feature {HASH_STORAGE}.set_hash_code however needs access to ''a_string'' as well. -In the SCOOP model, as seen so far, this would result in a deadlock. The handler of the HASH_STORAGE object waits for exclusive access on the string object, and the EXAMPLE object waits for the query {HASH_STORAGE}.hash_code to return. - -To resolve this problem, SCOOP implements a technique called ''Lock Passing''. -Locks on regions can be passed to the handler of the target of a separate call. -Lock passing happens whenever the client processor (the handler of the EXAMPLE object) has locked a region that holds an object which is passed as an actual argument to a separate call. Note that this also includes non-separate reference objects, because a processor always holds a lock over its own region. - -When a client has passed its locks to the supplier processor, it cannot continue execution until the called feature has been applied by the supplier processor, and the supplier processor has given back the locks to the client. Therefore, this type of call must be synchronous. - -{{note|During lock passing, a processor gives away all the locks that it currently holds, including the lock on itself.}} - -{{note| Lock passing happens for every synchronous call, in particular also for queries and passive processors.}} - -The advantage of lock passing is that it enables some very common programming patterns without triggering a deadlock. The disadvantage, however, is that it's hard to tell '''when''' it happens. However, there are a few cases when lock passing is guaranteed to happen, namely when the actual argument passed to a separate call is -* a formal argument of the enclosing routine, -* of a non-separate reference type or -* Current. - -There are, however, some cases where it's not immediately obvious that lock passing happens. -For example, a region might be locked because of a controlled argument somewhere further up in the call stack (i.e. not the enclosing routine, but the caller of that routine), or because an object is passed as an argument which happens to be on the same region as one of the controlled objects. - -There is a workaround to disable lock passing for a specific call: - -async_call (a_procedure: separate PROCEDURE [ANY, TUPLE]) - do - a_procedure.call (Void) - end - -example (a_object: separate ANY) - do - async_call (agent a_object.some_feature (Current)) - end - - -The feature async_call can be defined somewhere in the project and can be reused. The downside is that an agent needs to be created, but there's no lock passing happening, because all arguments to the agent are closed and only Void is passed to the separate call which cannot trigger lock passing. -However, this mechanism should be used with some care, because it's easy to run into one of the above mentioned deadlocks. - -=== Separate Callbacks === - -The last occurrence of synchronous calls is closely related to lock passing. If a processor '''A''' has passed a non-separate reference argument to another processor '''B''', and thus has passed its locks away, it cannot proceed its execution. Sometimes however processor '''B''' has to log some calls back to '''A''', which is called a ''separate callback''. - -{{definition|Separate Callback | A separate call where the caller holds the locks of the callee. }} - -During a separate callback processor '''B''' has to give back the locks it has previously received from '''A'''. -This in turn means '''B''' has to wait until '''A''' has finished its execution of the separate callback and returned the locks, which effectively makes the call synchronous. - +[[Property:title|Asynchronous Calls]] +[[Property:weight|6]] +[[Property:uuid|d3d3873c-5c84-7566-547e-1ede38544081]] +==Overview== + +As we've seen in [[Separate Calls]], feature calls to a non-separate target are always synchronous. +Furthermore, queries are always synchronous as well, because the caller has to wait for the result. + +{| border="1" +|- +! Target +! Query +! Command +|- +| non-separate +| synchronous +| synchronous +|- +| separate +| synchronous +| potentially asynchronous +|} + +Asynchronous calls can therefore only happen on commands with a separate target. +Indeed, such calls are by default executed asynchronously, but there are some important exceptions to this rule. +A command to a separate target is executed synchronously if any of the following applies: +* The client (caller) and supplier (target) region are the same. +* The target region is passive. +* The callee needs a lock currently held by the caller (lock passing). +* The caller holds the locks of the callee (separate callbacks). + +== Triggers for Synchronization == + +=== Same Regions === + +The first case happens when a reference is declared separate, but happens to be non-separate. This case follows directly from the type system: A non-separate type A always conforms to its variation separate A. At run-time such cases can be detected with an object test: + + +sep_object: separate A +--... +if attached {A} sep_object as non_sep_object then + -- ... +end + + +=== Passive Regions === + +In the SCOOP model, a passive region does not have a processor attached to it. +This means that clients of the passive region need to apply features logged against a passive region themselves. +The logical consequence of this is that all call to a passive region, including commands, are executed synchronously. + +=== Lock Passing === + +Lock passing is another source of synchronization. It is one of the trickiest issues to detect, and to fully understand it we must first introduce a few more definitions. + +In [[Exclusive Access]] we have learned that an object is ''controlled'' if it appears as a formal argument of the enclosing routine. SCOOP however always grants exclusive access over a whole region. We therefore introduce the new term ''Lock'': + +{{definition|Lock|Exclusive access to a SCOOP region and all objects therein.}} + +Note the difference between ''controlled'' and ''locked'': +* ''Controlled'' applies to a single object, whereas ''locked'' applies to a region. +* The ''controlled'' property can be determined statically at compile-time, whereas ''locked'' is determined at runtime. +* The set of ''controlled'' objects of a processor is always a subset of the set of objects in ''locked'' regions. + +{{note|In terms of implementation, a ''lock'' corresponds to an open call queue to a region.}} + +Now consider a small classes HASH_STORAGE and EXAMPLE: + +class HASH_STORAGE feature + + hash_code: INTEGER + + set_hash_code (a_string: separate STRING) + do + hash_code := a_string.hash_code + end +end + +class EXAMPLE feature + + run (a_hash_storage: separate HASH_STORAGE; a_string: separate STRING) + do + a_hash_storage.set_hash_code (a_string) + io.put_integer (a_hash_storage.hash_code) + end +end + + +You might notice a problem here: +In the feature {EXAMPLE}.run, exclusive access to 'a_hash_storage' and 'a_string' is guaranteed by the SCOOP semantics. +Or in other words, the corresponding regions are ''locked''. The feature {HASH_STORAGE}.set_hash_code however needs access to ''a_string'' as well. +In the SCOOP model, as seen so far, this would result in a deadlock. The handler of the HASH_STORAGE object waits for exclusive access on the string object, and the EXAMPLE object waits for the query {HASH_STORAGE}.hash_code to return. + +To resolve this problem, SCOOP implements a technique called ''Lock Passing''. +Locks on regions can be passed to the handler of the target of a separate call. +Lock passing happens whenever the client processor (the handler of the EXAMPLE object) has locked a region that holds an object which is passed as an actual argument to a separate call. Note that this also includes non-separate reference objects, because a processor always holds a lock over its own region. + +When a client has passed its locks to the supplier processor, it cannot continue execution until the called feature has been applied by the supplier processor, and the supplier processor has given back the locks to the client. Therefore, this type of call must be synchronous. + +{{note|During lock passing, a processor gives away all the locks that it currently holds, including the lock on itself.}} + +{{note| Lock passing happens for every synchronous call, in particular also for queries and passive processors.}} + +The advantage of lock passing is that it enables some very common programming patterns without triggering a deadlock. The disadvantage, however, is that it's hard to tell '''when''' it happens. However, there are a few cases when lock passing is guaranteed to happen, namely when the actual argument passed to a separate call is +* a formal argument of the enclosing routine, +* of a non-separate reference type or +* Current. + +There are, however, some cases where it's not immediately obvious that lock passing happens. +For example, a region might be locked because of a controlled argument somewhere further up in the call stack (i.e. not the enclosing routine, but the caller of that routine), or because an object is passed as an argument which happens to be on the same region as one of the controlled objects. + +There is a workaround to disable lock passing for a specific call: + +async_call (a_procedure: separate PROCEDURE [TUPLE]) + do + a_procedure.call (Void) + end + +example (a_object: separate ANY) + do + async_call (agent a_object.some_feature (Current)) + end + + +The feature async_call can be defined somewhere in the project and can be reused. The downside is that an agent needs to be created, but there's no lock passing happening, because all arguments to the agent are closed and only Void is passed to the separate call which cannot trigger lock passing. +However, this mechanism should be used with some care, because it's easy to run into one of the above mentioned deadlocks. + +=== Separate Callbacks === + +The last occurrence of synchronous calls is closely related to lock passing. If a processor '''A''' has passed a non-separate reference argument to another processor '''B''', and thus has passed its locks away, it cannot proceed its execution. Sometimes however processor '''B''' has to log some calls back to '''A''', which is called a ''separate callback''. + +{{definition|Separate Callback | A separate call where the caller holds the locks of the callee. }} + +During a separate callback processor '''B''' has to give back the locks it has previously received from '''A'''. +This in turn means '''B''' has to wait until '''A''' has finished its execution of the separate callback and returned the locks, which effectively makes the call synchronous. + diff --git a/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-implementation.wiki b/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-implementation.wiki index 03ab7ef2..7b2cd4a6 100644 --- a/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-implementation.wiki +++ b/documentation/trunk/solutions/concurrent-computing/concurrent-eiffel-scoop/scoop-implementation.wiki @@ -1,13 +1,9 @@ [[Property:title|SCOOP implementation]] [[Property:weight|9]] [[Property:uuid|eeb07907-e036-f3d6-5297-a7c44cfd1900]] -The implementation of SCOOP within EiffelStudio varies from the definition as it has been presented in publications during the model's evolution. -Some of the differences stem from the reality that SCOOP systems could be optimized for performance, including maximizing concurrency. For example, even though the SCOOP rules state that a separate call to a query is synchronous, i. e., the calling processor waits until the query completes before proceeding, if a static analysis can show that the wait is not necessary to the proper functioning of the remainder of the calling routine, then the call to the query can be done asynchronously. -In other ways, particularly for early versions, the EiffelStudio implementation may not cover all the goals of SCOOP as stated in the various publications. Certain elements that are defined in the SCOOP descriptions may not yet be present, or only partially implemented in the EiffelStudio implementation. - -The differences between the EiffelStudio implementation of SCOOP and current and previous definitions of the SCOOP model are shown below. +The implementation of SCOOP is the result of many years of design and refinement of the model. This page describes specific properties of its current state, in particular ways in which it differs from some of the earlier publications about the model. =Known limitations= @@ -15,44 +11,18 @@ The differences between the EiffelStudio implementation of SCOOP and current and ==Supported concurrency mechanisms== -Although the SCOOP model can support virtually any underlying concurrency mechanism, the initial SCOOP implementation in EiffelStudio version 6.8 supports only one executable, using multiple process threads as SCOOP [[Concurrent programming with SCOOP#Processors|processors]]. +At the core of the SCOOP model lies the notion of [[Concurrent programming with SCOOP#Processors|processor]]: a mechanism that can execute instructions sequentially. As a general model covering many forms of concurrency, SCOOP allows many possible implementations of this concept. In the EiffelStudio implementation, processors are implemented as threads of the operating system. ==Maximum number of SCOOP processors== -In the initial release, the allowable maximum number of SCOOP processors per system is 1024. +The maximum number of SCOOP processors per system is currently 1024. -==Separate anchored types== - -Applicable prior to revision number 86657: - -Separate status for anchored types is not supported properly. So declarations of the form: - - - my_entity: separate like my_query - - -and - - - my_entity: separate like Current - - -should be used only if you are using revision 86657 or later. - -Also, if you use an anchored declaration such as: - - - my_entity: like my_query - - -and the type of my_query is separate, you should make sure you are using revision 86657 or later. - ==Agents targeted to objects of separate types== -In version 6.8, agents targeted on separate objects are not supported. +Agents targeted on separate objects are currently not supported. =Workarounds= @@ -101,7 +71,7 @@ If the agent does not take any arguments, you must pass Void, otherwise the comp is on the same processor as the caller and thus triggers lock passing (see [[Asynchronous Calls]]): -do_call (proc: separate PROCEDURE [ANY, TUPLE]) +do_call (proc: separate PROCEDURE [TUPLE]) do proc.call (Void) end @@ -110,7 +80,7 @@ do_call (proc: separate PROCEDURE [ANY, TUPLE]) If the agent does take arguments, things get a bit more tricky. If the call must be asynchronous, you have to do a workaround with the feature {ROUTINE}.empty_operands like this: -do_call (a_procedure: separate PROCEDURE [ANY, TUPLE[separate STRING]]; a_string: separate STRING) +do_call (a_procedure: separate PROCEDURE [TUPLE[separate STRING]]; a_string: separate STRING) local l_tuple: separate TUPLE [separate STRING] do diff --git a/documentation/trunk/solutions/database-access/abel/tutorial/advanced-queries.wiki b/documentation/trunk/solutions/database-access/abel/tutorial/advanced-queries.wiki index a2914690..f69a9935 100644 --- a/documentation/trunk/solutions/database-access/abel/tutorial/advanced-queries.wiki +++ b/documentation/trunk/solutions/database-access/abel/tutorial/advanced-queries.wiki @@ -36,7 +36,7 @@ Note that for performance reasons it is usually better to use predefined criteri ===Agent Criteria=== An agent criterion will filter the objects according to the result of an agent applied to them. -The criterion is initialized with an agent of type PREDICATE [ANY, TUPLE [ANY]]. +The criterion is initialized with an agent of type PREDICATE [TUPLE [ANY]]. There should be either an open target or a single open argument, and the type of the objects in the query result should conform to the agent's open operand. ==Creating criteria objects== @@ -57,7 +57,7 @@ feature -- Creating a criterion -- containing either a single PREDICATE or three -- values of type [STRING, STRING, ANY]. - new_agent (a_predicate: PREDICATE [ANY, TUPLE [ANY]]): PS_CRITERION + new_agent (a_predicate: PREDICATE [TUPLE [ANY]]): PS_CRITERION -- Creates an agent criterion. new_predefined (object_attribute: STRING; operator: STRING; value: ANY): PS_CRITERION diff --git a/documentation/trunk/solutions/networking/index.wiki b/documentation/trunk/solutions/networking/index.wiki index 2df4b437..91e6f889 100644 --- a/documentation/trunk/solutions/networking/index.wiki +++ b/documentation/trunk/solutions/networking/index.wiki @@ -3,4 +3,15 @@ [[Property:uuid|4ddb235c-fea6-ee00-05af-6493e2c652a7]] == Network communication solutions== +There are a few network related library either coming with EiffelStudio delivery, or available as iron package: +* '''EiffelNet''': +: manipulation of sockets, network addresses, IPv4, IPv6. But also basic limited implementation for a few protocols. $ISE_LIBRARY/library/net/net.ecf + +* '''ZeroMQ''': +: wrapping for the [http://zeromq.org/ ZeroMQ] Distributed Messaging . [https://svn.eiffel.com/eiffelstudio/trunk/Src/library/zeromq] + +* '''http_client''': +: simple web client to send http (GET, POST, ...) request and receive associated response. $ISE_LIBRARY/contrib/library/network/http_client/http_client.ecf + + diff --git a/documentation/trunk/solutions/platform-specifics/microsoft-windows/net/eiffel-net-language/eiffel-net/event-programming-agents.wiki b/documentation/trunk/solutions/platform-specifics/microsoft-windows/net/eiffel-net-language/eiffel-net/event-programming-agents.wiki index bf1d6dec..440d1cd5 100644 --- a/documentation/trunk/solutions/platform-specifics/microsoft-windows/net/eiffel-net-language/eiffel-net/event-programming-agents.wiki +++ b/documentation/trunk/solutions/platform-specifics/microsoft-windows/net/eiffel-net-language/eiffel-net/event-programming-agents.wiki @@ -7,13 +7,13 @@ The implementation of agents is an advanced topic, but you do not have to unders ==Objects that Represent Operations== -Object technology is based on the idea that when we model real world objects, we model them based on the things that they have and what they can do ... their properties and their operations. The operations in Eiffel are the routines, i.e., the functions and procedures, of classes. Operations are not objects. +Object technology is based on the idea that when we model systems based on objects, representing the "things" they manipulate. As to operations on these objects, they appear in the corresponding classes, as routines (functions and procedures). Operations are not objects. -Having said that, it is sometimes desirable for us to model operations. We do this in the same fashion that we model other concepts: statically as classes, and as objects at runtime. +Sometimes, on the other hand, the "things" we model with our objects could represent operations. For example, we might want to build a list of tasks to be performed later; each task is defined by a routine. Each of the objects in the list will represent the corresponding routine. -An object that represents an operation is called an agent. +Such an object, representing an operation, is called an agent. -If we can have a runtime object that represents an operation, then we can place the object in the structure of another object, where at some later time, a client can cause the associated operation to execute. +If we can have a run-time object that represents an operation, then we can place the object in the structure of another object, where at some later time, a client can cause the associated operation to execute. This is a very desirable model for event driven processing, like graphical user interfaces. The operations that are executed when a user take some action like clicking on a button, could be represented by agents. When the user interface element is initialized, agents that represent the action routines are stored within the interface element. Then at the time that an event, say a button click, occurs, the agents for that event are retrieved and their associated operations are executed. @@ -23,9 +23,9 @@ Another area in which agents are commonly used is in traversing data structures. We know that there are two types of routines in Eiffel, functions and procedures. -Not surprisingly, the implementation of agents relies on three classes in the Base Library. Class ROUTINE, and its heirs FUNCTION and PROCEDURE. +The implementation of agents correspondingly relies on three classes in the Base Library: class ROUTINE for the general notion, and its heirs FUNCTION, with and PROCEDURE. In addition, PREDICATE, an heir of FUNCTION , covers the particular case of a function returning a boolean result. -When you use an agent from a client routine, you will be building an instance of either FUNCTION or ROUTINE. This happens implicitly as you will see. +When you use an agent from a client routine, you will be building an instance of either FUNCTION or ROUTINE. ==Using Agents== @@ -42,10 +42,10 @@ It is important to understand that step_forward does not get applie In this example, the routine "step_forward" on which the agent is based takes no arguments. If you drilled down into the workings of this example you would find that class that implements the feature extend is class EV_NOTIFY_ACTION_SEQUENCE. You would also see that the signature for the feature extend is as essentially as follows. - extend (v: PROCEDURE [ANY, TUPLE]) + extend (v: PROCEDURE [TUPLE]) -We don't have to know too much about the workings of agents to see that "extend" takes an argument v which is of type PROCEDURE. It turns out that the actual generic parameter TUPLE represents the set of "open" arguments. In this case, extend is expecting an agent which has no open arguments. +We don't have to know too much about the workings of agents to see that "extend" takes an argument v which is of type PROCEDURE. The actual generic parameter TUPLE represents the set of "open" arguments. In this case, extend is expecting an agent with no open arguments. ===Open and Closed Arguments=== @@ -53,7 +53,7 @@ It is this business of open and closed arguments which really makes agents remar Suppose a class has a feature declared as shown below. - my_procedure: PROCEDURE [ANY, TUPLE] + my_procedure: PROCEDURE [TUPLE] Then what can be assigned to my_procedure?. An agent, of course. Say the class has procedures as follows. @@ -76,14 +76,14 @@ Then the following assignment is valid. my_procedure := agent no_argument_procedure -What this means is that the agent created and associated with the procedure no_argument_procedure must conform to the type PROCEDURE [ANY, TUPLE]. The feature my_procedure (which is of type PROCEDURE [ANY, TUPLE]) can be attached at runtime to an agent representing a procedure with no open arguments, which indeed is what no_argument_procedure is. +What this means is that the agent created and associated with the procedure no_argument_procedure must conform to the type PROCEDURE [TUPLE]. The feature my_procedure (which is of type PROCEDURE [TUPLE]) can be attached at runtime to an agent representing a procedure with no open arguments, which indeed is what no_argument_procedure is. Now let's turn our attention to the other procedure two_argument_procedure. You might think that because it takes two arguments, that you would not be able to build an agent from it which could be assigned to the attribute my_procedure. But you can do it by closing the two arguments at the time that the agent is created, as in the following. my_procedure := agent two_argument_procedure (1, 2) -- Is Valid -What happens here is that values are fixed for those arguments at the time that the agent, an object of type PROCEDURE [ ANY, TUPLE] is created. +What happens here is that values are fixed for those arguments at the time that the agent, an object of type PROCEDURE [ TUPLE] is created. So this is the wonderful thing about agents. A routine which will be represented as an agent does not have to be an exact fit for the expected signature. By closing some arguments at agent creation, you have effectively produced a new and conforming routine. @@ -93,14 +93,14 @@ To leave an argument open, you hold its place with a question mark. If you inten my_procedure := agent two_argument_procedure (?, 2) -- Argument 1 left open my_procedure := agent two_argument_procedure (?, ?) -- Both arguments left open - my_procedure := agent two_argument_procedure -- Both arguments left open + my_procedure := agent two_argument_procedure -- Both arguments left open If an argument is open, then it means that a value is not provided for that argument at the time that the agent is created. The implication is that the value must be provided at some time prior to the time that the agent's associated routine gets executed. A precondition to executing a routine associated with an agent is that the agent has a valid set of arguments (called operands within the ROUTINE classes) for the call. If you were to leave one or both of the arguments to two_argument_procedure open as in the examples above, the assignment would still work due to the rules governing TUPLE conformance. But, at runtime unless the other arguments had been provided, the "valid operands" precondition would be violated. Let's see an example in which we leave a target open. Suppose we have a class that has a feature coded as below - my_strings: LINKED_LIST [STRING] + my_strings: LINKED_LIST [STRING] and some code to put some strings in my_strings: @@ -133,7 +133,7 @@ Now suppose we want to print the values of all the strings in my_stringsLINKED_LIST has a feature do_all which comes to it from its ancestor LINEAR. The do_all feature's signature looks like this: - do_all (action: PROCEDURE [ANY, TUPLE [G]]) + do_all (action: PROCEDURE [TUPLE [G]]) As an argument do_all takes an agent based on a procedure with one open argument which is the same type as the list items (in this class, G is the formal generic parameter representing the type of the items being stored). Then it traverses the list executing the routine associated with that agent and uses the current list item to satisfy the open argument. @@ -190,8 +190,14 @@ Here again we'll use a feature of the LINKED_LIST class. There is a my_list.do_if (agent print_on_new_line(?), agent {STRING}.has('!')) + The agent for the action is the same as we used earlier. We've added an agent for the test. It represents applying the has feature of the STRING class. Here the target is left open, because we want each of the strings in the list to be the target of has. +Compatibility note + +Versions of the Kernel Library classes ROUTINE, PROCEDURE, FUNCTION and PREDICATE prior to EiffelStudio 17-05 had an extra generic parameter at the initial position; the usual actual generic parameter was ANY. It has been removed. The compiler has been engineered so that in almost all cases it will still accept the old style. + +