mirror of
https://github.com/EiffelSoftware/eiffel-org.git
synced 2025-12-08 15:52:26 +01:00
Date:2009-05-17T21:20:21.000000Z git-svn-id: https://svn.eiffel.com/eiffel-org/trunk@218 abb3cda0-5349-4a8f-a601-0c33ac3a8c38
243 lines
9.0 KiB
Plaintext
243 lines
9.0 KiB
Plaintext
[[Property:title|Converting existing software to void-safety]]
|
|
[[Property:weight|6]]
|
|
[[Property:uuid|eb901272-d405-2277-005d-e37275b9baa4]]
|
|
{{underconstruction}}
|
|
|
|
|
|
|
|
If you have been using Eiffel for some time, you may be maintaining systems which were developed in the time before Eiffel became void-safe. If that's the case, then you will probably want to make those systems void-safe.
|
|
|
|
In this section we will use the experience of converting a set of simple (but not too simple) legacy Eiffel classes to show the types of issues that you may encounter, and how to deal with them.
|
|
|
|
The system we will use consists of these classes:
|
|
|
|
{| border="1"
|
|
|-
|
|
! Class name
|
|
! Description
|
|
|-
|
|
| APPLICATION
|
|
| Simple root class containing declarations of types NVP and NVP_LIST
|
|
|-
|
|
| NVP
|
|
| Class modeling name/value pairs of type STRING
|
|
|-
|
|
| NVP_LIST
|
|
| Class modeling a list of NVP's with specialized behavior
|
|
|}
|
|
|
|
|
|
=Conversion considerations=
|
|
|
|
==To redesign or not to redesign==
|
|
|
|
As you sift through your existing software during the void-safe conversion, you may not get very far before you see things that you wish had been done differently. This occurs often during reviews of existing systems, not just because of the introduction of void-safety. You will see some such cases in the routines of legacy classes below.
|
|
|
|
=Conversion process=
|
|
|
|
==Enable full class checking==
|
|
|
|
First make sure your project will compile correctly under the configuration of EiffelStudio that you intend to use to convert to void-safe.
|
|
|
|
Then set the project setting '''Full Class Checking''' to '''True'''. Do a ''clean'' compile of your system. To do this shut down and restart EiffelStudio. When the project selection dialog appears, select your project, then next to '''Action:''' select '''Compile''' in the drop-down, and check '''Clean'''.
|
|
|
|
Full class checking will analyze your classes to make sure that in cases of inheritance features of the parent classes are recheck for validity in the heirs.
|
|
|
|
Here's an example of the kind of error you might expect when compiling with full class checking:
|
|
|
|
|
|
[[Image:VGCC error]]
|
|
|
|
|
|
The situation here is that the feature <code>split</code> has been inherited (from class <code>TWO_WAY_LIST [G]</code>) by our class <code>NVP_LIST</code>. Feature <code>split</code> includes code to create and attach feature <code>sublist</code> which is typed <code>attached like Current</code> which in this case means <code>attached NVP_LIST</code>. To do this creation, <code>split</code> uses a creation procedure <code>make_sublist</code>.
|
|
|
|
Now here's the rub: <code>NVP_LIST</code> has not named <code>make_sublist</code> as a creation procedure:
|
|
<code>
|
|
create
|
|
make, make_from_string, make_from_file_named
|
|
</code>
|
|
So if we go to the <code>create</code> part of <code>NVP_LIST</code> and add <code>make_sublist</code> to its list of creation procedures, this will fix the problem:
|
|
<code>
|
|
create
|
|
make, make_from_string, make_from_file_named, make_sublist
|
|
</code>
|
|
|
|
So, fix any problems that arise out of turning on full class checking.
|
|
|
|
==Enable other project settings==
|
|
|
|
The second step in conversion of existing software is to change the values of the other void-safe related project settings and use the void-safe configurations for any delivered libraries and precompilations.
|
|
|
|
In the project settings for the target in which you are working:
|
|
# Set '''Void safe''' to either '''Complete void safety''' or '''On demand void safety'''.
|
|
# Set '''Are types attached by default?''' to '''True'''.
|
|
|
|
{{note|Remember that during a transitional period starting with V6.4, there will be multiple versions of the configuration files for Eiffel libraries and precompiles. For example, base.ecf (non-void-safe) and base-safe.ecf (void-safe). It is expected that in the future there will only be one configuration file (e.g., base.ecf) that will work with both void-safe and non-void-safe client software. }}
|
|
|
|
If necessary, remove Eiffel libraries and any precompiled library that your project uses and re-add them with their void-safe configuration files. Because you've set your target to void-safety, when you click '''Add Library''', you should see only void-safe configurations by default.
|
|
You will see a check box on the dialog that you can uncheck if you want to see all available library configurations:
|
|
|
|
|
|
[[Image:VoidSafeAddLibraryDialog]]
|
|
|
|
|
|
Now do a clean compile.
|
|
|
|
If you've replaced a precompiled library that you have not already built, EiffelStudio will offer to build it for you on the fly:
|
|
|
|
|
|
[[Image:VoidSafePrecompileOffer]]
|
|
|
|
|
|
Now you should see error messages representing any situation in your project in which the compiler determines that it cannot guarantee void safety.
|
|
|
|
This is what our legacy system produced:
|
|
|
|
|
|
[[Image:VoidSafeErrorList]]
|
|
|
|
|
|
==Fix the issues==
|
|
|
|
Next you fix the problems that the compiler discovered. The compiler errors concerning void-safety typically will be of three varieties.
|
|
|
|
# VEVI: violations of the '''Variable initialization rule'''. An attached variable is not '''properly set'''.
|
|
# VUTA: violations of the '''Target rule'''. The target of a feature call is not attached.
|
|
# VJAR (and other related codes): violations of attached status considered in conformance. The attachment status of the source of an assignment (or an argument to a feature call) is not compatible with that of the target of the assignment (or the formal argument).
|
|
|
|
Let's look at some specific cases and how fixing them unfolds.
|
|
|
|
|
|
[[Image:VoidSafeVEVI1]]
|
|
|
|
|
|
There are two VEVI errors like this in class <code>APPLICATION</code> our legacy system. They are probably the most obvious and easiest cases to handle.
|
|
|
|
<code>
|
|
feature {NONE} -- Initialization
|
|
|
|
make
|
|
-- Run application.
|
|
do
|
|
...
|
|
end
|
|
|
|
feature -- Access
|
|
|
|
my_nvp: NVP
|
|
-- NVP for testing
|
|
|
|
my_nvp_list: NVP_LIST
|
|
-- NVP_LIST for testing
|
|
</code>
|
|
|
|
Here attribute declarations for <code>my_nvp</code> and <code>my_nvp_list</code> are made. These are assumed to be attached because of the project setting. But the create routine <code>make</code> fails to create objects and attach them. So by adding those creations, as shown below, the compiler is satisfied.
|
|
|
|
<code>
|
|
make
|
|
-- Run application.
|
|
do
|
|
create my_nvp.make ("SomeName", "SomeValue")
|
|
create my_nvp_list.make
|
|
...
|
|
end
|
|
</code>
|
|
|
|
|
|
In second case, there is also an Initialization rule violation (VEVI), this time on <code>Result</code>, in this routine:
|
|
|
|
<code>
|
|
at_first (nm: STRING): NVP is
|
|
-- The first found NVP with name matching nm.
|
|
-- Or Void if not found
|
|
require
|
|
nm_valid: nm /= Void and then not nm.is_empty
|
|
local
|
|
tc: CURSOR
|
|
do
|
|
tc := cursor
|
|
start
|
|
name_search (nm)
|
|
if not exhausted then
|
|
Result := item
|
|
end
|
|
go_to (tc)
|
|
ensure
|
|
index_unchanged: index = old index
|
|
end
|
|
</code>
|
|
|
|
Here we cannot just ensure that <code>Result</code> is attached, because, as indicated by the header comment, <code>Result</code> is allowed to be void by design.
|
|
|
|
So the least impact to this routine will be to declare its type as <code>detachable</code>:
|
|
|
|
<code>
|
|
at_first (nm: STRING): detachable NVP is
|
|
-- The first found NVP with name matching nm.
|
|
-- Or Void if not found
|
|
</code>
|
|
|
|
|
|
The same change is made in other routines that can return void by design.
|
|
|
|
The change to <code>at_first</code> satisfies the VEVI issue in <code>at_first</code>, but it introduces a previously unseen conformance issue (VJAR) in a routine <code>value_at_first</code>:
|
|
|
|
|
|
[[Image:VoidSafeVJAR1]]
|
|
|
|
|
|
<code>value_at_first</code> looks like this:
|
|
|
|
<code>
|
|
value_at_first (nm: STRING): detachable STRING is
|
|
-- Value from first found NVP with name matching nm
|
|
-- Or Void of not found
|
|
require
|
|
nm_valid: nm /= Void and then not nm.is_empty
|
|
local
|
|
tn: NVP
|
|
do
|
|
tn := at_first (nm)
|
|
if tn /= Void then
|
|
Result := tn.value
|
|
end
|
|
end
|
|
</code>
|
|
|
|
The problem is that the local variable <code>tn</code> is declared as <code>attached</code>, but we know that now the result of <code>at_first</code> is detachable, making this assignment invalid:
|
|
<code>
|
|
tn := at_first (nm)
|
|
</code>
|
|
|
|
Here the '''attached syntax''' can fix the problem and streamline the routine:
|
|
|
|
<code>
|
|
value_at_first (nm: STRING): detachable STRING is
|
|
-- Value from first found NVP with name matching nm
|
|
-- Or Void of not found
|
|
require
|
|
nm_valid: nm /= Void and then not nm.is_empty
|
|
do
|
|
if attached at_first (nm) as tn then
|
|
Result := tn.value
|
|
end
|
|
end
|
|
</code>
|
|
|
|
In this version <code>tn</code> need not be declared as a local variable. Remember that the attached syntax provides a fresh local variable, if the expression is not void.
|
|
|
|
|
|
==Code patterns==
|
|
|
|
===CAPs===
|
|
|
|
===The '''attribute''' keyword===
|
|
|
|
===Using generic classes===
|
|
|
|
===Using '''check''' blocks===
|
|
|
|
==Transitioning steps==
|
|
|
|
|