0

How do you declare a variable to be the same type as a type parameter used to instantiate a generic class? The following code does not compile:

class
    TEST [G, H -> INTEGER]

feature

    f (i: INDEXABLE [G, H])
        local
            y: H
        do
            y := i.lower -- Type error here.
        end

end

The compiler says that the source of the assignment is not compatible with target.

Eleno
  • 2,864
  • 3
  • 33
  • 39

2 Answers2

1

In the current implementation, INDEXABLE [G, H] inherits from TABLE [G, INTEGER]. As a result, lower is of type INTEGER, not H. And INTEGER does not conform to the formal generic type H of the class TEST. This explains the error.

To me, it looks like a mistake in the declaration of class INDEXABLE. It should inherit from TABLE [G, H] instead. Then, the example code would compile.

Alexander Kogtenkov
  • 5,770
  • 1
  • 27
  • 35
  • Actually, `lower` comes from `READABLE_INDEXABLE`, but - yes - the problem is that its type is hard-coded. – Eleno Apr 25 '20 at 20:43
  • @Elena That's correct and is part of the design issue. I simplified the answer to avoid going too deep. `READABLE_INDEXABLE` should have had 2 formal generics instead of one, with the second parameter denoting the index type. However, it all goes down to types of indexes to access elements of ARRAYs, STRINGs, etc. And they are stuck to `INTEGER` (for historical reasons). So, the second parameters of `INDEXABLE` is questionable, and, probably, is an artifact of earlier ideas that did not find their way to the language. – Alexander Kogtenkov Apr 26 '20 at 07:28
1

Type anchoring can be used in those cases:

feature
    f (i: INDEXABLE [G, H])
        local
            y: like i.lower
        do
            y := i.lower
        end

Sometimes a generic type is not used as return type of any accessible feature on a class, so in those cases I like to declare a fake feature specifically to allow anchoring:

class SOME_CLASS [G]
feature
    generic_type_anchor: G
        do
            check
                for_anchoring_only: False
                -- This method should never actually be called, only used as an anchor in type declarations
            end
        end

This is particularly useful with complex inheritance trees or when descendant classes close the generics, in which case the correct type is not apparent from the declared type. Personally I tend to use type anchoring whenever values are semantically related as this helps expressing intent, simplifies refactoring (as there are fewer repetitions of types which by definition must match) and facilitates covariance.

Also as a side-note, expanded types (like INTEGER) cannot be used polymorphically (you need a reference for that; if class A is expanded and class B [expanded or reference] inherits A, you could not assign a value of type B to a variable of type A; inheritance from expanded types is implicitly non-conforming), and moreover the compiler disallows inheriting from basic expanded types (INTEGER, BOOLEAN, REAL_64, etc.), therefore the generic constraint in your example makes no sense because H could never be anything but INTEGER.

obnosim
  • 151
  • 3