Update wikipage Creating a new void-safe project. (Signed-off-by:alexk).

git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@1714 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
This commit is contained in:
eiffel-org
2016-12-26 11:11:11 +00:00
parent 8fd055edec
commit 177fa94eee

View File

@@ -1,414 +1,385 @@
[[Property:title|Creating a new void-safe project]] [[Property:title|Creating a new void-safe project]]
[[Property:weight|2]] [[Property:weight|2]]
[[Property:uuid|92cea2e9-b094-6380-2c5d-1cd1eb3038b4]] [[Property:uuid|92cea2e9-b094-6380-2c5d-1cd1eb3038b4]]
{{TOC|limit=2}} {{TOC|limit=2}}
Now that we've been introduced to the Eiffel void-safe facilities, let's look at what it takes to set up a new void-safe software project. Here we'll look at the void-safety related project settings and how the can be used. Then we'll look deeper into the use of some of the void-safe tools. Now that we've been introduced to the Eiffel void-safe facilities, let's look at what it takes to set up a new void-safe software project. Here we'll look at the void-safety related project settings and how the can be used. Then we'll look deeper into the use of some of the void-safe tools.
==Project settings for void-safe projects== ==Project settings for void-safe projects==
There are three project settings that are related to void-safety. These settings can be set with great granularity throughout your project to allow you maximum flexibility, particularly when including classes or libraries that are void-unsafe or that have been converted to void-safety, but must do double duty in the void-safe and void-unsafe worlds. There are three project settings that are related to void-safety. These settings can be set with great granularity throughout your project to allow you maximum flexibility, particularly when including classes or libraries that are void-unsafe or that have been converted to void-safety, but must do double duty in the void-safe and void-unsafe worlds.
===The ''"Void-safe"'' setting=== ===The ''"Void-safe"'' setting===
The '''Void-safe''' setting determines whether and how the Eiffel compiler checks your project against the void-safe related validity rules. The '''Void-safe''' setting determines whether and how the Eiffel compiler checks your project against the void-safe related validity rules.
This is the essential void-safe project setting. It can assume one of three values: This is the essential void-safe project setting. It can assume one of three values:
# '''No''': No checking against any of the void-safety validity rules. Attachment marks '''attached''' and '''detachable''' are simply ignored. # '''No''': No checking against any of the void-safety validity rules. Attachment marks '''attached''' and '''detachable''' are simply ignored.
# '''Conformance''': The attachment marks are not ignored for type conformance checks (with respect to VJAR/VBAR and related validity rules). # '''Conformance''': The attachment marks are not ignored for type conformance checks (with respect to VJAR/VBAR and related validity rules).
# '''Initialization''': Validity rules are selectively checked. The initialization rule (VEVI) and the target rule (VUTA) are checked only for attached entities and attached call targets -- i.e., detachable cases are not checked. # '''Initialization''': Validity rules are selectively checked. The initialization rule (VEVI) and the target rule (VUTA) are checked only for attached entities and attached call targets -- i.e., detachable cases are not checked.
# '''Transitional''': It is an obsolete level which is for users who have already migrated their code to void-safety using an old version of the compiler which did not implement all the void-safety validity rules (especially with agent initialization). # '''Transitional''': It is an obsolete level which is for users who have already migrated their code to void-safety using an old version of the compiler which did not implement all the void-safety validity rules (especially with agent initialization).
# '''Complete''': Complete checking against all void-safety validity rules. # '''Complete''': Complete checking against all void-safety validity rules.
So, for a new void-safe project, you would want to set this option first to '''Conformance''', then '''Initialization'''' and finally to '''Complete'''. This will let you migrate your code progressively without much changes at each steps. So, for a new void-safe project, you would want to set this option first to '''Conformance''', then '''Initialization'''' and finally to '''Complete'''. This will let you migrate your code progressively without much changes at each steps.
===The ''"Are types attached by default?"'' setting===
===The ''"Full class checking"'' setting===
It is this setting that tells the compiler how to treat declarations which specify neither the <code>detachable</code> keyword nor the <code>attached</code> keyword, for example:
<code> This setting instructs the compiler to recheck inherited features in descendant classes. This setting is True and cannot be changed for projects with some void-safety level enabled.
x: T
</code>
A value of '''True''' will instruct the compiler to treat <code>x</code> as if it were declared: ==Void-safe libraries==
<code>
x: attached T As of EiffelStudio version 13.11, all libraries distributed with EiffelStudio are void-safe except the EiffelCOM library.
</code>
A value of '''False''', and <code>x</code> will be viewed as if it were: {{note|During a period of transition, there are different Eiffel configuration files (.ecf's) for void-unsafe and void-safe projects (for example, base.ecf and base-safe.ecf). If you have set the '''Void-safe''' setting to check for void-safety, then when you add a library to your project in EiffelStudio, you will see only the void-safe configurations by default. Starting with version 16.11 there is only one version of each of the configuration files for each library. The single configuration files serve both void-unsafe and void-safe projects.}}
<code>
x: detachable T ===Using generic classes===
</code>
Void-safety affects generic classes. Fortunately, from the viewpoint of those writing clients to the generic classes in the EiffelBase library, not much has changed. Still, you should understand the interplay between void-safety and [[ET: Genericity and Arrays|genericity]].
In a new project, ideally all of your declarations would be of attached types. But of course there are some occasions, for various reasons, that you must or should use detachable types.
Consider a generic class like <code>LIST [G]</code>. The formal generic parameter <code>G</code> represents an arbitrary type. In a generic derivation of <code>LIST [G]</code>, say <code>LIST [STRING]</code>, the formal generic type is replaced by an actual generic type, in this case <code>STRING</code>.
So, for a new void-safe project, it is recommended that a value of '''True''' is used.
Remember that unconstrained genericity, <code>LIST [G]</code>, for example, is really a case of [[ET: Inheritance#Constrained genericity|constrained genericity]] in which the generic parameter is constrained to <code>ANY</code>, that is, it could be written <code>LIST [G -> ANY]</code>.
{{Warning|As of EiffelStudio 14.05, this setting will always be True by default and future releases of EiffelStudio will not let you change this.}}
With the advent of void-safe Eiffel, the unconstrained generic class name <code>LIST [G]</code> now equates to <code>LIST [G -> detachable ANY]</code>. Because any type, say <code>T</code>, (synonymous with <code>attached T</code> in void-safe Eiffel) conforms to <code>detachable T</code>, this change facilitates the production of generic classes, but has little effect on writers of clients to those classes.
{{SeeAlso| [[Void-safety: Background, definition, and tools#Types as "attached" or "detachable"|Types as "attached" or "detachable"]].}} This change works for all the generic classes in EiffelBase ... except for one: <code>ARRAY</code>. Arrays are a special case because we often create arrays with a pre-allocated number of elements. In the case of expanded types, there's not a problem. For example, in this code
<code>
my_array: ARRAY [INTEGER]
===The ''"Full class checking"'' setting=== ...
create my_array.make (1, 100)
This setting instructs the compiler to recheck inherited features in descendant classes. This setting is True and cannot be changed for projects with some void-safety level enabled. </code>
we create <code>my_array</code> with one hundred <code>INTEGER</code> elements. <code>INTEGER</code> is an expanded type, and each element is initialized by applying the default initialization rule for <code>INTEGER</code>, i.e, the integer representation of zero.
==Void-safe libraries== However, if <code>my_array</code> had been declared of a type with reference semantics, say <code>STRING</code> (meaning, of course, <code>attached STRING</code>, the default rule would not work well, because the default initialization for references types is <code>Void</code> which would not be allowed in an array of elements of any attached type.
As of EiffelStudio version 13.11, all libraries distributed with EiffelStudio are void-safe except the EiffelCOM library. The solution to this challenge is fairly simple. For arrays of elements of detachable or expanded types, there is no different behavior. When dealing with arrays of elements of attached types, we must be careful.
{{note|During a period of transition, there will be different Eiffel configuration files (.ecf's) for void-unsafe and void-safe projects (for example, base.ecf and base-safe.ecf). If you have set the '''Void-safe''' setting to check for void-safety, then when you add a library to your project in EiffelStudio, you will see only the void-safe configurations by default. After the transition period, it is expected that there will be only one version of each of the configuration files for each library. The single configuration files will serve both void-unsafe and void-safe projects. }} Creating an array using <code>ARRAY</code>'s creation procedure <code>make</code> may still be safe in some cases. Specifically, <code>make</code> can be used with arrays of elements of attached types if the arguments have values such that an empty array will be created, that is, when
<code>
===Using generic classes=== min_index = max_index + 1
</code>
Void-safety affects generic classes. Fortunately, from the viewpoint of those writing clients to the generic classes in the EiffelBase library, not much has changed. Still, you should understand the interplay between void-safety and [[ET: Genericity and Arrays|genericity]].
In all other situations involving arrays of elements of attached types, <code>make</code> may not be used to do the creation. Rather, you should use the creation procedure <code>make_filled</code> which takes three arguments. The first is an object of the type of the array, and the second and third are the minimum and maximum indexes, respectively. When the array is created, each of the elements will be initialized with a reference to the object of the first argument.
Consider a generic class like <code>LIST [G]</code>. The formal generic parameter <code>G</code> represents an arbitrary type. In a generic derivation of <code>LIST [G]</code>, say <code>LIST [STRING]</code>, the formal generic type is replaced by an actual generic type, in this case <code>STRING</code>.
So, a call using <code>make_filled</code> would look like this:
Remember that unconstrained genericity, <code>LIST [G]</code>, for example, is really a case of [[ET: Inheritance#Constrained genericity|constrained genericity]] in which the generic parameter is constrained to <code>ANY</code>, that is, it could be written <code>LIST [G -> ANY]</code>. <code>
my_array: ARRAY [STRING]
With the advent of void-safe Eiffel, the unconstrained generic class name <code>LIST [G]</code> now equates to <code>LIST [G -> detachable ANY]</code>. Because any type, say <code>T</code>, (synonymous with <code>attached T</code> in void-safe Eiffel) conforms to <code>detachable T</code>, this change facilitates the production of generic classes, but has little effect on writers of clients to those classes. ...
create my_array.make_filled (" ", 1, 100)
This change works for all the generic classes in EiffelBase ... except for one: <code>ARRAY</code>. Arrays are a special case because we often create arrays with a pre-allocated number of elements. In the case of expanded types, there's not a problem. For example, in this code </code>
<code> Upon creation, each element of the array will reference the same object; an object of type <code>STRING</code> composed of one space character.
my_array: ARRAY [INTEGER]
...
create my_array.make (1, 100) ==Using the ''attribute'' keyword carefully==
</code>
we create <code>my_array</code> with one hundred <code>INTEGER</code> elements. <code>INTEGER</code> is an expanded type, and each element is initialized by applying the default initialization rule for <code>INTEGER</code>, i.e, the integer representation of zero. The keyword <code>attribute</code> should be used with some care. You might be tempted to think that it would be convenient or add an extra element of safety to use [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attributes]] widely. And in a way, you would be correct. But you should also understand that there is a price to pay for using self-initializing attributes and stable attributes. It is that upon every access, an evaluation of the state of the attribute must be made. So, as a general rule, you should avoid using self-initializing attributes only for the purpose of lazy initialization.
However, if <code>my_array</code> had been declared of a type with reference semantics, say <code>STRING</code> (meaning, of course, <code>attached STRING</code>, the default rule would not work well, because the default initialization for references types is <code>Void</code> which would not be allowed in an array of elements of any attached type.
==More about the ''attached syntax''==
The solution to this challenge is fairly simple. For arrays of elements of detachable or expanded types, there is no different behavior. When dealing with arrays of elements of attached types, we must be careful.
The complete attached syntax is:
Creating an array using <code>ARRAY</code>'s creation procedure <code>make</code> may still be safe in some cases. Specifically, <code>make</code> can be used with arrays of elements of attached types if the arguments have values such that an empty array will be created, that is, when <code>
<code> attached {SOME_TYPE} exp as l_exp
min_index = max_index + 1 </code>
</code> In this section, we will see more ways in which to use this versatile language facility.
In all other situations involving arrays of elements of attached types, <code>make</code> may not be used to do the creation. Rather, you should use the creation procedure <code>make_filled</code> which takes three arguments. The first is an object of the type of the array, and the second and third are the minimum and maximum indexes, respectively. When the array is created, each of the elements will be initialized with a reference to the object of the first argument. ===As a CAP-like construct which yields a local variable===
So, a call using <code>make_filled</code> would look like this: In the introduction to the attached syntax, we used an example which showed how the attached syntax is directly relevant to void-safety. That is, the code:
<code> <code>
my_array: ARRAY [STRING] if x /= Void then
... -- ... Any other instructions here that do not assign to x
create my_array.make_filled (" ", 1, 100) x.f (a)
</code> end
Upon creation, each element of the array will reference the same object; an object of type <code>STRING</code> composed of one space character. </code>
is a CAP for <code>x</code> ... but that's only true if <code>x</code> is a local variable or a formal argument to the routine that contains the code.
{{note|Full void-safety on arrays of attached types requires a change to class <code>ARRAY</code> which can break existing code. During a transitional period, this and similar changes are available for testing and use in an "experimental" version of EiffelStudio. This version of EiffelStudio can be invoked by using the "-experiment" option from the command line, or by selecting it on Microsoft Windows by following the '''Start''' menu path to EiffelStudio. You are encouraged to try to compile your libraries and systems using experimental mode in order to prepare for the time when these changes are made permanent.<br/><br/>As of version 6.6, the normal mode of EiffelStudio becomes what had been accessible in earlier versions as "experimental".}}
So to access a detachable attribute safely, we could declare a local variable, make an assignment, and test for <code>Void</code> as above. Something like this:
<code>
==Using the ''attribute'' keyword carefully== my_detachable_attribute: detachable MY_TYPE
The keyword <code>attribute</code> should be used with some care. You might be tempted to think that it would be convenient or add an extra element of safety to use [[Void-safety: Background, definition, and tools#Self-initializing attributes|self-initializing attributes]] widely. And in a way, you would be correct. But you should also understand that there is a price to pay for using self-initializing attributes and stable attributes. It is that upon every access, an evaluation of the state of the attribute must be made. So, as a general rule, you should avoid using self-initializing attributes only for the purpose of lazy initialization. ...
some_routine
local
==More about the ''attached syntax''== x: like my_detachable_attribute
do
The complete attached syntax is: x := my_detachable_attribute
<code> if x /= Void then
attached {SOME_TYPE} exp as l_exp -- ... Any other instructions here that do not assign to x
</code> x.f (a)
In this section, we will see more ways in which to use this versatile language facility. end
...
===As a CAP-like construct which yields a local variable=== </code>
The attached syntax can both check the attached status of a detachable attribute and also provide a new local variable. So the routine becomes:
In the introduction to the attached syntax, we used an example which showed how the attached syntax is directly relevant to void-safety. That is, the code: <code>
<code> some_routine
if x /= Void then do
-- ... Any other instructions here that do not assign to x if attached my_detachable_attribute as x then
x.f (a) -- ... Any other instructions here that do not assign to x
end x.f (a)
</code> end
...
is a CAP for <code>x</code> ... but that's only true if <code>x</code> is a local variable or a formal argument to the routine that contains the code. </code>
So to access a detachable attribute safely, we could declare a local variable, make an assignment, and test for <code>Void</code> as above. Something like this: ===As a test for attachment===
<code>
my_detachable_attribute: detachable MY_TYPE In its simplest form, the attached syntax can be used to test attached status only:
<code>
... if attached x then
some_routine do_something
local else
x: like my_detachable_attribute do_something_different
do end
x := my_detachable_attribute </code>
if x /= Void then
-- ... Any other instructions here that do not assign to x So in this simple form, <code>attached x</code> can be used instead of <code>x /= Void</code>. The two are semantically equivalent, and which one you choose is a matter of personal preference.
x.f (a)
end
... ===As a tool for "once per object"===
</code>
The attached syntax can both check the attached status of a detachable attribute and also provide a new local variable. So the routine becomes: There is a code pattern for functions that exists in some Eiffel software to effect "once-per-object / lazy evaluation".
<code>
some_routine {{note|As of EiffelStudio version 6.6, the use of this code pattern effecting "once per object" is no longer necessary. V6.6 includes explicit support for <code>once</code> routines which can be adjusted by a [[ET: Once routines and shared objects#Adjusting once semantics with "once keys"|once key]] to specify once per object.}}
do
if attached my_detachable_attribute as x then This "once-per-object" code pattern employs a cached value for some object which is not exported. When it is applied, the "once-per-object" function checks the attachment status of the cached value. If the cached value is void, then it is created and assigned to <code>Result</code>. If the cached value was found already to exist, then it is just assigned to <code>Result</code>.
-- ... Any other instructions here that do not assign to x
x.f (a) Here's an example of this pattern used to produce some descriptive text of an instance of its class:
end
... <code>
</code> feature -- Access
===As a test for attachment=== descriptive_text: STRING
local
In its simplest form, the attached syntax can be used to test attached status only: l_result: like descriptive_text_cache
<code> do
if attached x then l_result := descriptive_text_cache
do_something if l_result = Void then
else create Result.make_empty
do_something_different -- ... Build Result with appropriate descriptive text for Current
end descriptive_text_cache := Result
</code> else
Result := l_result
So in this simple form, <code>attached x</code> can be used instead of <code>x /= Void</code>. The two are semantically equivalent, and which one you choose is a matter of personal preference. end
ensure
result_attached: Result /= Void
===As a tool for "once per object"=== result_not_empty: not Result.is_empty
result_consistent: Result = descriptive_text
There is a code pattern for functions that exists in some Eiffel software to effect "once-per-object / lazy evaluation". end
{{note|As of EiffelStudio version 6.6, the use of this code pattern effecting "once per object" is no longer necessary. V6.6 includes explicit support for <code>once</code> routines which can be adjusted by a [[ET: Once routines and shared objects#Adjusting once semantics with "once keys"|once key]] to specify once per object.}} feature {NONE} -- Implementation
This "once-per-object" code pattern employs a cached value for some object which is not exported. When it is applied, the "once-per-object" function checks the attachment status of the cached value. If the cached value is void, then it is created and assigned to <code>Result</code>. If the cached value was found already to exist, then it is just assigned to <code>Result</code>. descriptive_text_cache: like descriptive_text
Here's an example of this pattern used to produce some descriptive text of an instance of its class: </code>
This example will not compile in a void-safe project (class types are attached by default). The problem is that the attribute <code>descriptive_text_cache</code> is of an attached type, therefore will be flagged by the compiler as not properly set (VEVI). Of course, it will be ... that's the whole idea here: not to initialize <code>descriptive_text_cache</code> until it's actually used. So it sounds like <code>descriptive_text_cache</code> should be declared detachable. That is:
<code> <code>
feature -- Access descriptive_text_cache: detachable like descriptive_text
</code>
descriptive_text: STRING This change will make this routine compile in a void-safe project. But you should notice that there is a ripple-down effect due to the change. Within the routine, <code>l_result</code> is typed <code>like descriptive_text_cache</code>, so it also will be detachable. Therefore we might expect trouble, because later in the routine we have:
local <code>
l_result: like descriptive_text_cache Result := l_result
do </code>
l_result := descriptive_text_cache Because we know Result is attached and l_result is detachable, we might expect a compiler error in which the source of an assignment does not conform to its target (VJAR).
if l_result = Void then
create Result.make_empty But we don't get such an error. The reason is two-fold. First, <code>l_result</code> is a local variable whose use can be protected by a CAP. Second, the CAP in this case is the check to ensure that <code>l_result</code> is not void. We only make the assignment to <code>Result</code> if <code>l_result</code> is not void. So the compiler can prove that <code>l_result</code> cannot be void at the point at which the assignment occurs ... therefore, no error.
-- ... Build Result with appropriate descriptive text for Current
descriptive_text_cache := Result Because the '''attached syntax''' can test attached status and provide a local variable, it can be used to remove some unnecessary code from this routine. The version of the routine that follows shows the attached syntax being used to test the attached status of <code>descriptive_text_cache</code> and yield the local variable <code>l_result</code> in the case that <code>descriptive_text_cache</code> is indeed attached.
else <code>
Result := l_result descriptive_text: STRING
end do
ensure if attached descriptive_text_cache as l_result then
result_attached: Result /= Void Result := l_result
result_not_empty: not Result.is_empty else
result_consistent: Result = descriptive_text create Result.make_empty
end -- ... Build Result with appropriate descriptive text for Current
descriptive_text_cache := Result
feature {NONE} -- Implementation end
ensure
descriptive_text_cache: like descriptive_text result_attached: Result /= Void
result_not_empty: not Result.is_empty
</code> result_consistent: Result = descriptive_text
This example will not compile in a void-safe project (assuming types are attached by default). The problem is that the attribute <code>descriptive_text_cache</code> is of an attached type, therefore will be flagged by the compiler as not properly set (VEVI). Of course, it will be ... that's the whole idea here: not to initialize <code>descriptive_text_cache</code> until it's actually used. So it sounds like <code>descriptive_text_cache</code> should be declared detachable. That is: end
<code>
descriptive_text_cache: detachable like descriptive_text feature {NONE} -- Implementation
</code>
This change will make this routine compile in a void-safe project. But you should notice that there is a ripple-down effect due to the change. Within the routine, <code>l_result</code> is typed <code>like descriptive_text_cache</code>, so it also will be detachable. Therefore we might expect trouble, because later in the routine we have: descriptive_text_cache: like descriptive_text
<code>
Result := l_result </code>
</code>
Because we know Result is attached and l_result is detachable, we might expect a compiler error in which the source of an assignment does not conform to its target (VJAR).
===As a replacement for assignment attempt===
But we don't get such an error. The reason is two-fold. First, <code>l_result</code> is a local variable whose use can be protected by a CAP. Second, the CAP in this case is the check to ensure that <code>l_result</code> is not void. We only make the assignment to <code>Result</code> if <code>l_result</code> is not void. So the compiler can prove that <code>l_result</code> cannot be void at the point at which the assignment occurs ... therefore, no error.
The assignment attempt ( <code>?=</code> ) has traditionally been used to deal with external objects (e.g., persistent objects from files and databases) and to narrow the type of an object in order to use more specific features. The latter is a process known by names such as "down casting" in some technological circles. A classic example is doing specific processing on some elements of a polymorphic data structure. Let's look at an example. Suppose we have a <code>LIST</code> of items of type <code>POLYGON</code>:
Because the '''attached syntax''' can test attached status and provide a local variable, it can be used to remove some unnecessary code from this routine. The version of the routine that follows shows the attached syntax being used to test the attached status of <code>descriptive_text_cache</code> and yield the local variable <code>l_result</code> in the case that <code>descriptive_text_cache</code> is indeed attached. <code>
<code> my_polygons: LIST [POLYGON]
descriptive_text: STRING </code>
do <code>POLYGON</code>s could be of many specific types, and one of those could be <code>RECTANGLE</code>. Suppose too that we want to print the measurements of the diagonals of all the <code>RECTANGLE</code>s in the list. Class <code>RECTANGLE</code> might have a query <code>diagonal</code> returning such a measurement, but <code>POLYGON</code> would not, for the reason that the concept of diagonal is not meaningful for all <code>POLYGON</code>s, e.g., <code>TRIANGLE</code>s.
if attached descriptive_text_cache as l_result then
Result := l_result As we traverse the list we would use assignment attempt to try to attach each <code>POLYGON</code> to a variable typed as <code>RECTANGLE</code>. If successful, we can print the result of the application of <code>diagonal</code>.
else <code>
create Result.make_empty l_my_rectangle: RECTANGLE
-- ... Build Result with appropriate descriptive text for Current
descriptive_text_cache := Result ...
end from
ensure my_polygons.start
result_attached: Result /= Void until
result_not_empty: not Result.is_empty my_polygons.exhausted
result_consistent: Result = descriptive_text loop
end l_my_rectangle ?= my_polygons.item
if l_my_rectangle /= Void then
feature {NONE} -- Implementation print (l_my_rectangle.diagonal)
print ("%N")
descriptive_text_cache: like descriptive_text end
my_polygons.forth
</code> end
</code>
The '''attached syntax''' allows us to check both attached status and type, and provides us with a fresh local variable when appropriate:
===As a replacement for assignment attempt=== <code>
from
The assignment attempt ( <code>?=</code> ) has traditionally been used to deal with external objects (e.g., persistent objects from files and databases) and to narrow the type of an object in order to use more specific features. The latter is a process known by names such as "down casting" in some technological circles. A classic example is doing specific processing on some elements of a polymorphic data structure. Let's look at an example. Suppose we have a <code>LIST</code> of items of type <code>POLYGON</code>: my_polygons.start
<code> until
my_polygons: LIST [POLYGON] my_polygons.exhausted
</code> loop
<code>POLYGON</code>s could be of many specific types, and one of those could be <code>RECTANGLE</code>. Suppose too that we want to print the measurements of the diagonals of all the <code>RECTANGLE</code>s in the list. Class <code>RECTANGLE</code> might have a query <code>diagonal</code> returning such a measurement, but <code>POLYGON</code> would not, for the reason that the concept of diagonal is not meaningful for all <code>POLYGON</code>s, e.g., <code>TRIANGLE</code>s. if attached {RECTANGLE} my_polygons.item as l_my_rectangle then
print (l_my_rectangle.diagonal)
As we traverse the list we would use assignment attempt to try to attach each <code>POLYGON</code> to a variable typed as <code>RECTANGLE</code>. If successful, we can print the result of the application of <code>diagonal</code>. print ("%N")
<code> end
l_my_rectangle: RECTANGLE my_polygons.forth
end
... </code>
from As with the other examples of the '''attached syntax''', it is no longer necessary to make a declaration for the local variable, in this case <code>l_my_rectangle</code>.
my_polygons.start
until
my_polygons.exhausted ==More about CAPs==
loop
l_my_rectangle ?= my_polygons.item ===Use of <code>check</code> instructions===
if l_my_rectangle /= Void then
print (l_my_rectangle.diagonal) In void-safe mode, the compiler will accept code that it can prove will only apply features to attached references at runtime ... and you help this process along by using the tools of void-safety, like attached types and CAPs. On the other hand, the compiler will reject code that it cannot guarantee is void-safe. Sometimes this may cause you a problem. There may be subtle situations in which you feel quite certain that a section of code will be free of void calls at runtime, but the compiler doesn't see it the same way, and rejects your code. In cases like this, you can usually satisfy the compiler by using <code>check</code> instructions.
print ("%N")
end Technically speaking, <code>check</code> instructions are not CAPs. But they are useful in cases in which an entity is always expected to be attached at a certain point in the code. In the following example, the attribute <code>my_detachable_any</code> is detachable. But at the particular point at which it is the source of the assignment to <code>l_result</code>, it is expected always to be attached. If it is not attached at the time of the assignment, and therefore <code>l_result</code> becomes void, then an exception should occur. The <code>check</code> instruction provides this behavior.
my_polygons.forth
end The following sample shows the <code>check</code> instruction at work. There are reasons why this is not the best use use of <code>check</code> in this case, and we will discuss that next.
</code>
The '''attached syntax''' allows us to check both attached status and type, and provides us with a fresh local variable when appropriate: <code>
<code> -- A not-so-good example of using check.
from
my_polygons.start my_detachable_any: detachable ANY
until ...
my_polygons.exhausted my_attached_any: ANY
loop local
if attached {RECTANGLE} my_polygons.item as l_my_rectangle then l_result: like my_detachable_any
print (l_my_rectangle.diagonal) do
print ("%N") l_result := my_detachable_any
end check
my_polygons.forth attached l_result
end end
</code> Result := l_result
As with the other examples of the '''attached syntax''', it is no longer necessary to make a declaration for the local variable, in this case <code>l_my_rectangle</code>. end
</code>
==More about CAPs== Here the assertion in the <code>check</code> guarantees that <code>l_result</code> is attached at the time of its assignment to <code>Result</code>. If <code>my_detachable_any</code> is ever not attached to an object, then an exception will be raised.
===Use of <code>check</code> instructions=== So what's wrong with the sample above? It would be fine in ''workbench'' code, but what happens if the code is in ''finalized'' mode, in which assertions are typically discarded?
In void-safe mode, the compiler will accept code that it can prove will only apply features to attached references at runtime ... and you help this process along by using the tools of void-safety, like attached types and CAPs. On the other hand, the compiler will reject code that it cannot guarantee is void-safe. Sometimes this may cause you a problem. There may be subtle situations in which you feel quite certain that a section of code will be free of void calls at runtime, but the compiler doesn't see it the same way, and rejects your code. In cases like this, you can usually satisfy the compiler by using <code>check</code> instructions. The answer is that the <code>check</code> in the sample above would no longer be effective, and the resulting executable would no longer be void-safe.
Technically speaking, <code>check</code> instructions are not CAPs. But they are useful in cases in which an entity is always expected to be attached at a certain point in the code. In the following example, the attribute <code>my_detachable_any</code> is detachable. But at the particular point at which it is the source of the assignment to <code>l_result</code>, it is expected always to be attached. If it is not attached at the time of the assignment, and therefore <code>l_result</code> becomes void, then an exception should occur. The <code>check</code> instruction provides this behavior. The solution to this problem is found in a different form of the <code>check</code> instruction. Consider the same example, but this time using <code>check ... then ... end</code>:
The following sample shows the <code>check</code> instruction at work. There are reasons why this is not the best use use of <code>check</code> in this case, and we will discuss that next. <code>
-- A better way of using check.
<code>
-- A not-so-good example of using check. my_detachable_any: detachable ANY
...
my_detachable_any: detachable ANY my_attached_any: ANY
... do
my_attached_any: ANY check attached my_detachable_any as l_result then
local Result := l_result
l_result: like my_detachable_any end
do end
l_result := my_detachable_any </code>
check
attached l_result Here, in the improved version of the example, the <code>check ... then ... end</code> is used along with the <code>attached</code> syntax. This streamlines the code a bit by eliminating the need to declare a separate local entity, while achieving the same effect as the previous example. If <code>my_detachable_any</code> is attached at runtime, then the temporary variable <code>l_result</code> is created and attached to the same object. Then the body of the <code>check ... then ... end</code> is executed. If <code>my_detachable_any</code> is not attached, an exception occurs.
end
Result := l_result Another important benefit, one that solves the problem with the original example, comes from the way in which <code>check ... then ... end</code> is handled by the compiler. The <code>check ... then ... end</code> form '''is always monitored, even if assertion checking is turned off at all levels''', as is usually done in finalized code.
end
</code> ===Choosing CAPs versus the Attached Syntax===
Here the assertion in the <code>check</code> guarantees that <code>l_result</code> is attached at the time of its assignment to <code>Result</code>. If <code>my_detachable_any</code> is ever not attached to an object, then an exception will be raised. The attached syntax is convenient because it can check attached status and deliver a new local variable at the same time. But there are cases in which you might choose instead to define a local variable and use a CAP. Suppose you had code acting on several similar and detachable expressions, and you use the attached syntax in each case:
<code>
So what's wrong with the sample above? It would be fine in ''workbench'' code, but what happens if the code is in ''finalized'' mode, in which assertions are typically discarded? foobar
do
The answer is that the <code>check</code> in the sample above would no longer be effective, and the resulting executable would no longer be void-safe. if attached dictionary_entry ("abc") as l_abc then
l_abc.do_something
The solution to this problem is found in a different form of the <code>check</code> instruction. Consider the same example, but this time using <code>check ... then ... end</code>: end
if attached dictionary_entry ("def") as l_def then
<code> l_def.do_something
-- A better way of using check. end
if attached dictionary_entry ("ghi") as l_ghi then
my_detachable_any: detachable ANY l_ghi.do_something
... end
my_attached_any: ANY end
do </code>
check attached my_detachable_any as l_result then This routine causes three local variables to be allocated for the duration of routine <code>foobar</code>, one each for <code>l_abc</code>, <code>l_def</code>, and <code>l_ghi</code>. And it is no better to do this:
Result := l_result <code>
end foobar
end do
</code> if attached dictionary_entry ("abc") as l_entry then
l_entry.do_something
Here, in the improved version of the example, the <code>check ... then ... end</code> is used along with the <code>attached</code> syntax. This streamlines the code a bit by eliminating the need to declare a separate local entity, while achieving the same effect as the previous example. If <code>my_detachable_any</code> is attached at runtime, then the temporary variable <code>l_result</code> is created and attached to the same object. Then the body of the <code>check ... then ... end</code> is executed. If <code>my_detachable_any</code> is not attached, an exception occurs. end
if attached dictionary_entry ("def") as l_entry then
Another important benefit, one that solves the problem with the original example, comes from the way in which <code>check ... then ... end</code> is handled by the compiler. The <code>check ... then ... end</code> form '''is always monitored, even if assertion checking is turned off at all levels''', as is usually done in finalized code. l_entry.do_something
end
===Choosing CAPs versus the Attached Syntax=== if attached dictionary_entry ("ghi") as l_entry then
l_entry.do_something
The attached syntax is convenient because it can check attached status and deliver a new local variable at the same time. But there are cases in which you might choose instead to define a local variable and use a CAP. Suppose you had code acting on several similar and detachable expressions, and you use the attached syntax in each case: end
<code> end
foobar </code>
do Even though the names are the same, still three separate local variables are allocated for <code>foobar</code>.
if attached dictionary_entry ("abc") as l_abc then
l_abc.do_something In cases like this, you could effect a minor performance improvement by declaring one local variable and reusing it. In the following code, only one local variable is used and access to it is protected by the CAP <code>if l_entry /= Void then</code>.
end <code>
if attached dictionary_entry ("def") as l_def then foobar
l_def.do_something local
end l_entry: like dictionary_entry
if attached dictionary_entry ("ghi") as l_ghi then do
l_ghi.do_something l_entry := dictionary_entry ("abc")
end if l_entry /= Void then
end l_entry.do_something
</code> end
This routine causes three local variables to be allocated for the duration of routine <code>foobar</code>, one each for <code>l_abc</code>, <code>l_def</code>, and <code>l_ghi</code>. And it is no better to do this: l_entry := dictionary_entry ("def")
<code> if l_entry /= Void then
foobar l_entry.do_something
do end
if attached dictionary_entry ("abc") as l_entry then l_entry := dictionary_entry ("ghi")
l_entry.do_something if l_entry /= Void then
end l_entry.do_something
if attached dictionary_entry ("def") as l_entry then end
l_entry.do_something end
end </code>
if attached dictionary_entry ("ghi") as l_entry then
l_entry.do_something ==Stable attributes==
end
end Remember that stable attributes are actually detachable attributes, with the difference that they can never be the target of an assignment in which the source is <code>Void</code> or anything that could have a value of <code>Void</code>.
</code>
Even though the names are the same, still three separate local variables are allocated for <code>foobar</code>. Stable attributes are useful in situations in which there are valid object life scenarios in which some particular attribute will never need an object attached, or will only need an object attached late in the scenario. So in this case, the attribute is used only under certain runtime conditions. Declaring these attributes as stable eliminates the need to make attachments during object creation. Yet once needed, that is, once the attribute is attached, it will always be attached.
In cases like this, you could effect a minor performance improvement by declaring one local variable and reusing it. In the following code, only one local variable is used and access to it is protected by the CAP <code>if l_entry /= Void then</code>. Also, you should remember that unlike other attributes, you can access stable attributes directly in a CAP:
<code> <code>
foobar my_stable_attribute: detachable SOME_TYPE
local note
l_entry: like dictionary_entry option: stable
do attribute
l_entry := dictionary_entry ("abc") end
if l_entry /= Void then
l_entry.do_something ...
end
l_entry := dictionary_entry ("def") if my_stable_attribute /= Void then
if l_entry /= Void then my_stable_attribute.do_something
l_entry.do_something end
end
l_entry := dictionary_entry ("ghi") ...
if l_entry /= Void then </code>
l_entry.do_something
end {{SeeAlso| [[Void-safety: Background, definition, and tools#Types as "attached" or "detachable"|Types as "attached" or "detachable"]].}}
end
</code>
==Stable attributes==
Remember that stable attributes are actually detachable attributes, with the difference that they can never be the target of an assignment in which the source is <code>Void</code> or anything that could have a value of <code>Void</code>.
Stable attributes are useful in situations in which there are valid object life scenarios in which some particular attribute will never need an object attached, or will only need an object attached late in the scenario. So in this case, the attribute is used only under certain runtime conditions. Declaring these attributes as stable eliminates the need to make attachments during object creation. Yet once needed, that is, once the attribute is attached, it will always be attached.
Also, you should remember that unlike other attributes, you can access stable attributes directly in a CAP:
<code>
my_stable_attribute: detachable SOME_TYPE
note
option: stable
attribute
end
...
if my_stable_attribute /= Void then
my_stable_attribute.do_something
end
...
</code>