# Difference between revisions of "Conversion rules"

Line 255: | Line 255: | ||

The answer is '''yes''' and therefore the code valid. But it should be invalid because the constraint INTEGER_REF and the fact that DOUBLE is frozen makes it impossible to create a type which satisfies both, the conformance to INTEGER_REF and to DOUBLE. | The answer is '''yes''' and therefore the code valid. But it should be invalid because the constraint INTEGER_REF and the fact that DOUBLE is frozen makes it impossible to create a type which satisfies both, the conformance to INTEGER_REF and to DOUBLE. | ||

− | == | + | ==Pattern matching rule== |

In case we check a class, which has at least one formal generic type parameter we want to find out, whether it is possible to derive a type which is conform to the constraint and to the type where we convert to. If such a type exists, the conversion is invalid as it violates the ''Conversion Principle''. | In case we check a class, which has at least one formal generic type parameter we want to find out, whether it is possible to derive a type which is conform to the constraint and to the type where we convert to. If such a type exists, the conversion is invalid as it violates the ''Conversion Principle''. | ||

Line 275: | Line 275: | ||

We replace the formal G in CT with DOUBLE and obtain TTC: B[DOUBLE] | We replace the formal G in CT with DOUBLE and obtain TTC: B[DOUBLE] | ||

− | We take this type and check whether it satisfies the constraint and is conform to the type we | + | We take this type and check whether it satisfies the constraint and is conform to the type we convert to. If both hold at the same time there exists a valid derivation of CT and therefore the ''Conversion Principle'' violated. |

* Check whether TTC is a valid generic derivation of CT and whether it conforms to TARGET | * Check whether TTC is a valid generic derivation of CT and whether it conforms to TARGET | ||

Line 283: | Line 283: | ||

As not both statements hold it is a valid conversion. | As not both statements hold it is a valid conversion. | ||

+ | It can be quite tricky to check this rule as for example: | ||

+ | <eiffel> | ||

+ | class B[G->H,H->G] | ||

+ | inherit | ||

+ | A[G] | ||

+ | convert | ||

+ | to_a: {A[STRING]} | ||

+ | feature | ||

+ | to_a: A[STRING] | ||

+ | do end | ||

+ | end | ||

+ | </eiffel> | ||

+ | We would obtain a TTC which lookes like this: B[STRING,G]<br> | ||

+ | Now one would have to define, whether this type satisfies the constraint or not. | ||

− | ==Conversion principle at runtime== | + | |

+ | == Relaxed rule == | ||

+ | As it turns out to be quite tricky to check validity as soon as formal generic type parameters are used one could also be a little bit more relaxed and say the following is valid code: | ||

+ | |||

+ | <eiffel> | ||

+ | class A[G] | ||

+ | convert | ||

+ | to_a: {A[STRING]} | ||

+ | end | ||

+ | </eiffel> | ||

+ | As soon as we find out statically that we have type conformance in a particular case, we do not do a conversion. So one would only to a conversion if it is necessary. | ||

+ | This seems to be ok as the conversion principle anyway can be violated at runtime. | ||

+ | |||

+ | |||

+ | |||

+ | ==Appendix: Conversion principle at runtime== | ||

+ | The ''Conversion Principle'' can be violated at runtime: | ||

<eiffel> | <eiffel> | ||

class X | class X |

## Revision as of 10:45, 22 January 2007

**Warning:** **Warning**: Article under development

## Contents

## Introduction

This article discusses issues recently discovered for the following two validity rules:

- 8.15.7 Validity:
*Conversion Procedure rule*, Validity code:**VYCP** - 8.15.8 Validity:
*Conversion Query rule*, Validity code:**VYCQ**

There are cases where both of them violate the conversion principle:

- 8.15.3 Validity:
*Conversion principle*: No type may both conform and convert to another.

This has to be verified for all static types. At runtime for dynamic types this principle cannot be easily guaranteed.

## Examples

As the conversion rules are strongly dual, each example can be transformed to show the issue for its sibling.

#### Example 1

We have a conversion to the current type of the class. It should not be allowed. Currently no rule rejects this code.

- eweasel test: convert-to-current-type

class A[G] convert to_a: {A[G]} feature to_a: A[G] do end end

The conversion to **A[G]** should indeed not be valid because they are conform.

The only rule that matters in our case is **VYCQ(3)**.

What VYCQ(3) asks is the following

Is A[ANY] conform to A[G]?

The answer is **no** and thus the code regarded as valid.

Summary:

- correct result: invalid
- old rules: valid
- wildcard rule: invalid
- complex rule: invalid

#### Example 2

This example shows a special case which is valid under the current rule but can possibly lead to a conflict between conformance and conversion.

- eweasel test: convert-to-possible-actual-type

class A[G] convert to_a: {A[STRING]} feature to_a: A[STRING] do end end

In the case where G's actual type parameter is a subtype of STRING it yields in a situation where the two types are conform again.

The interesting rule is again **VYCQ(3)**:

Is A[ANY] conform to A[STRING]?

The answer is **no** and thus the code regarded as valid.
Summary:

- correct result: invalid
- old rules: valid
- wildcard rule: invalid
- complex rule: invalid

#### Example 3

- eweasel test: convert-to-base-class

class A[G,H] convert to_a: {A[G,G]} feature to_a: A[G,G] do end end

**VYCQ(3)**:

Is A[ANY,ANY] conform to A[G,G]?

The answer is **no** and thus the code regarded as valid.
Summary:

- correct result: invalid
- old rules: valid
- wildcard rule: invalid
- complex rule: invalid

#### Example 4

This is an example which is valid under the current rules and should remain valid. Even though we inherit from A[ANY] the conversion to A[STRING] should be valid.

- eweasel test: convert-to-base-class-inherited

class A[G] end class B[G] inherit A[ANY] convert to_b: {A[STRING]} feature to_b: A[STRING] do end end

**VYCQ(3)**:

Is B[ANY] conform to A[STRING]?

The answer is **no** and thus the code regarded as valid.

Summary:

- correct result: valid
- old rules: valid
- wildcard rule: valid
- complex rule: valid

#### Example 5

This is the second example which is valid under the current rules. The code is valid as the *Conversion principle* cannot possibly be violated.

- eweasel test: convert-to-base-class-inherited

class A[G,H] end class B[G->INTEGER,H->DOUBLE] inherit A[G,H] convert to_a: {A[DOUBLE,INTEGER]} feature to_a: A[DOUBLE,INTEGER] do end end

**VYCQ(3)**:

Is B[INTEGER,DOUBLE] conform to A[DOUBLE,INTEGER]?

The answer is **no** and thus the code regarded as valid.

Summary:

- correct result: valid
- old rules: valid
- wildcard rule: valid
- complex rule: valid

#### Example 6

This is the second example which is valid under the current rules. The code is valid as the *Conversion principle* cannot possibly be violated.

- eweasel test: convert-to-base-class-inherited

class A[G] end class B[G->INTEGER_REF] inherit A[G] convert to_a: {A[DOUBLE]} feature to_a: A[DOUBLE] do end end

**VYCQ(3)**:

Is B[INTEGER_REF] conform to A[DOUBLE]?

The answer is **no** and thus the code regarded as valid.

Summary:

- correct result: valid
- old rules: valid
- wildcard rule: invalid
- complex rule: valid

## Understanding the matter

If we take the inheritance hierarchy of an Eiffel system it can be abstracted to a directed acyclic graph.

The following illustration shows where conversion is valid and where not.

## Possible solution

Instead of restricting VYCQ(2) and VYCP(2) to non-generic types we allow generic types too. As VYC*(2) is even using the notion of *current type*, it might indeed be possible that it was the authors original intention.

We define an additional function *FTN* which replaces every formal generic with another type:

- By a wildcard type, which is conform to anything if the formals constraint type is not frozen.
- By the (single) frozen type which occurs in the constraint of the formal.

The wildcard type virtually makes the conformance check for this formal obsolete, as the result is always true.

The new version could look like this:

- VYCP'(2)
*FTN(SOURCE)*does not conform to*CT* - VYCQ'(2)
*FTN(CT)*does not conform to*TARGET*

To complete and take the

#### New rule applied to examples

**Example 1 for VYCQ'(2):**

Is A[WILDCARD] conform to A[G]?

The answer is **yes** and the validity rule is violated, which is good.

**Example 2 for VYCQ'(2):**

Is A[WILDCARD] conform to A[STRING]?

The answer is **yes** and we reject the code.

**Example 3 for VYCQ'(2):**

Is A[WILDCARD,WILDCARD] conform to A[G,G]?

The answer is again **yes** and therefore the code not valid.

**Example 4 for VYCQ'(2):**

Is B[WILDCARD] conform to A[STRING]?

As *B* only inherits from *A[ANY]* the answer is **no** and we're fine.

**Example 5 for VYCQ'(2):**

Is B[INTEGER,DOUBLE] conform to A[DOUBLE,INTEGER]?

The answer is **no** and therefore the code valid.

**Example 6 for VYCQ'(2):**

Is B[WILDCARD] conform to A[DOUBLE]?

The answer is **yes** and therefore the code valid. But it should be invalid because the constraint INTEGER_REF and the fact that DOUBLE is frozen makes it impossible to create a type which satisfies both, the conformance to INTEGER_REF and to DOUBLE.

## Pattern matching rule

In case we check a class, which has at least one formal generic type parameter we want to find out, whether it is possible to derive a type which is conform to the constraint and to the type where we convert to. If such a type exists, the conversion is invalid as it violates the *Conversion Principle*.

The algorithm is explained together with Example 6:

For every conversion we check whether the base class of the class we check is conform to the base class of the type we convert to.

- If CT inherits from the base class of TARGET, we call that derivation of the same base class CPCT (for corresponding parent of CT).

In Example 6: B inherits from A. TARGET: A[DOUBLE] CPCT: A[G]

If that is true, the generic derivation might contain formal generic parameters. We perform a pattern matching and replace the formals with the according derivation found in the type we convert to.

- Find for every formal at position
*i*of CPCT the corresponding class type found at position i in TARGET. Create a new instance called TTC (Type to check) of CT by using the class types for all formals used.

Formal G in CPCT has position 1. The type at position 1 in TARGET is DOUBLE. We replace the formal G in CT with DOUBLE and obtain TTC: B[DOUBLE]

We take this type and check whether it satisfies the constraint and is conform to the type we convert to. If both hold at the same time there exists a valid derivation of CT and therefore the *Conversion Principle* violated.

- Check whether TTC is a valid generic derivation of CT and whether it conforms to TARGET

B[DOUBLE] doesnotsatisfy the constraint (INTEGER_REF). B[DOUBLE] is conform TARGET.

As not both statements hold it is a valid conversion.

It can be quite tricky to check this rule as for example:

class B[G->H,H->G] inherit A[G] convert to_a: {A[STRING]} feature to_a: A[STRING] do end end

We would obtain a TTC which lookes like this: B[STRING,G]

Now one would have to define, whether this type satisfies the constraint or not.

## Relaxed rule

As it turns out to be quite tricky to check validity as soon as formal generic type parameters are used one could also be a little bit more relaxed and say the following is valid code:

class A[G] convert to_a: {A[STRING]} end

As soon as we find out statically that we have type conformance in a particular case, we do not do a conversion. So one would only to a conversion if it is necessary. This seems to be ok as the conversion principle anyway can be violated at runtime.

## Appendix: Conversion principle at runtime

The *Conversion Principle* can be violated at runtime:

class X convert to_y: {Y} feature to_y: Y do end end class Y end class XY inherit X Y end class TEST feature test local x: X xy: XY do create xy x := xy -- A conversion is done. The dynamic types conform. needs_y (x) end needs_y (y: Y) do end