Files
eiffel-org/documentation/current/method/void-safe-programming-eiffel/creating-new-void-safe-project.wiki
halw 9350c6adcd Author:halw
Date:2009-10-26T21:58:53.000000Z


git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@338 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
2009-10-26 21:58:53 +00:00

359 lines
19 KiB
Plaintext

[[Property:title|Creating a new void-safe project]]
[[Property:weight|2]]
[[Property:uuid|92cea2e9-b094-6380-2c5d-1cd1eb3038b4]]
=Creating a new void-safe project=
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==
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 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:
# '''No void safety''': No checking against any of the void-safety validity rules.
# '''On demand void safety''': Validity rules are selectively checked. Attachment status (VJAR/VBAR and related) is taken into account when performing conformance checks, but 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.
# '''Complete void safety''': Complete checking against all void-safety validity rules.
So, for a new void-safe project, you would want to set this option to either '''Complete void safety''' or '''On demand void safety'''.
===The ''"Are types attached by default?"'' 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>
x: T
</code>
A value of '''True''' will instruct the compiler to treat <code>x</code> as if it were declared:
<code>
x: attached T
</code>
A value of '''False''', and <code>x</code> will be viewed as if it were:
<code>
x: detachable T
</code>
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.
So, for a new void-safe project, it is recommended that a value of '''True''' is used.
===The ''"Full class checking"'' setting===
This setting instructs the compiler to recheck inherited features in descendant classes.
'''Full class checking''' should always be set to '''True''' when compiling void-safe code.
==Void-safe libraries==
As of EiffelStudio version 6.4, the majority of the libraries distributed with EiffelStudio are void-safe.
{{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. }}
===Using generic classes===
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]].
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>.
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>.
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.
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]
...
create my_array.make (1, 100)
</code>
we create <code>my_array</code> with one hundred <code>INTEGER</code> elements. Each element is initialized by applying the default initialization rule for <code>INTEGER</code>.
However, if <code>my_array</code> had been declared of a type with reference semantics, say <code>STRING</code>, the default rule would not work well, because the default initialization for references types is <code>Void</code>.
==Using the ''attribute'' keyword carefully==
The keyword <code>attribute</code> is 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 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.
==More about the ''attached syntax''==
The complete attached syntax is:
<code>
attached {SOME_CLASS} exp as l_exp
</code>
In this section, we will see more ways in which to use this versatile language facility.
===As a CAP which yields a local variable===
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>
if x /= Void then
-- ... Any other instructions here that do not assign to x
x.f (a)
end
</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.
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>
my_detachable_attribute: detachable MY_TYPE
...
some_routine
local
x: like my_detachable_attribute
do
x := my_detachable_attribute
if x /= Void then
-- ... Any other instructions here that do not assign to x
x.f (a)
end
...
</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:
<code>
some_routine
do
if attached my_detachable_attribute as x then
-- ... Any other instructions here that do not assign to x
x.f (a)
end
...
</code>
===As a test for attachment===
In its simplest form, the attached syntax can be used to test attached status only:
<code>
if attached x then
do_something
else
do_something_different
end
</code>
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.
===As a tool for "once per object"===
There is a code pattern for functions that exists in some Eiffel software to effect "once-per-object / lazy evaluation".
{{note|This is different from an Eiffel <code>once</code> routine, which is "once-per-thread" or "once-per-process" depending upon how it is configured. }}
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>.
Here's an example of this pattern used to produce some descriptive text of an instance of its class:
<code>
feature -- Access
descriptive_text: STRING
local
l_result: like descriptive_text_cache
do
l_result := descriptive_text_cache
if l_result = Void then
create Result.make_empty
-- ... Build Result with appropriate descriptive text for Current
descriptive_text_cache := Result
else
Result := l_result
end
ensure
result_attached: Result /= Void
result_not_empty: not Result.is_empty
result_consistent: Result = descriptive_text
end
feature {NONE} -- Implementation
descriptive_text_cache: like descriptive_text
</code>
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:
<code>
descriptive_text_cache: detachable like descriptive_text
</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:
<code>
Result := l_result
</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).
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.
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>
descriptive_text: STRING
do
if attached descriptive_text_cache as l_result then
Result := l_result
else
create Result.make_empty
descriptive_text_cache := Result
end
ensure
result_attached: Result /= Void
result_not_empty: not Result.is_empty
result_consistent: Result = descriptive_text
end
</code>
===As a replacement for assignment attempt===
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>:
<code>
my_polygons: LIST [POLYGON]
</code>
<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.
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>.
<code>
l_my_rectangle: RECTANGLE
...
from
my_polygons.start
until
my_polygons.exhausted
loop
l_my_rectangle ?= my_polygons.item
if l_my_rectangle /= Void then
print (l_my_rectangle.diagonal)
print ("%N")
end
end
</code>
The '''attached syntax''' allows us to check both attached status and type, and provides us with a fresh local variable when appropriate:
<code>
from
my_polygons.start
until
my_polygons.exhausted
loop
if attached {RECTANGLE} my_polygons.item as l_my_rectangle then
print (l_my_rectangle.diagonal)
print ("%N")
end
end
</code>
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>.
==More about CAPs==
===Use of <code>check</code> instructions===
You might wonder about the use of a CAP which employs a <code>check</code> instruction like this:
<code>
my_detachable_any: detachable ANY
...
my_attached_any: ANY
local
l_result: like my_detachable_any
do
l_result := my_detachable_any
check
attached l_result
end
Result := l_result
end
</code>
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> had not been attached, then an exception would have occurred.
This would be fine in ''workbench'' code, but what happens if the code is ''finalized'' and assertions are discarded?
The answer is that the <code>check</code> remains in force in finalized code, because it is necessary to prove void-safety.
{{note|As of version 6.4 this standard behavior is not yet implemented in EiffelStudio. That is, in version 6.4 it is still possible to disable run-time monitoring of <code>check</code> instructions. As a result, until the standard behavior is implemented, it is best not to discard <code>check</code> instruction monitoring, particularly in the case of void-safe checks.}}
===Choosing CAPs versus the Attached Syntax===
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>
foobar
do
if attached dictionary_entry ("abc") as l_abc then
l_abc.do_something
end
if attached dictionary_entry ("def") as l_def then
l_def.do_something
end
if attached dictionary_entry ("ghi") as l_ghi then
l_ghi.do_something
end
end
</code>
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:
<code>
foobar
do
if attached dictionary_entry ("abc") as l_entry then
l_entry.do_something
end
if attached dictionary_entry ("def") as l_entry then
l_entry.do_something
end
if attached dictionary_entry ("ghi") as l_entry then
l_entry.do_something
end
end
</code>
Even though the names are the same, still three separate local variables are allocated for <code>foobar</code>.
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>.
<code>
foobar
local
l_entry: like dictionary_entry
do
l_entry := dictionary_entry ("abc")
if l_entry /= Void then
l_entry.do_something
end
l_entry := dictionary_entry ("def")
if l_entry /= Void then
l_entry.do_something
end
l_entry := dictionary_entry ("ghi")
if l_entry /= Void then
l_entry.do_something
end
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>