Search code examples
eiffel

Eiffel: best way to compare types without getting a catcall


Got a Catcall trying to compare 2 types, how could I do that avoiding passing through another not dedicated method (like to string, class_id or stuff like that)?

enter image description here

SIT_UTIL

    class_name_lowercase (a_string: STRING): STRING
            -- a copy lowercased and pruned from preceding '!'
        do
            Result := a_string
            if Result.index_of('!', 1) = 1 then
                Result := Result.substring (2, Result.count)
                Result.to_lower
            else
                Result := Result.as_lower
            end
        ensure
            instance_free: class
        end

CLIENT_CLASS

    relationship_from_secondary_type_equal (a_type: like relationships.item.secondary_type): detachable like relationships.item
            -- Returns first instance of found relationship secondary type which equals given one
        do
            across
                relationships as l_rel
            until
                Result /= Void
            loop
--              if attached (a_type / l_rel.item.secondary_type) then -- Don't want conformance but equality

--              if attached (a_type.is_equal (l_rel.item.secondary_type)) then -- tried but as is_equal needs a like Current => Catcall
--              if attached (a_type.equal (a_type, l_rel.item.secondary_type)) then -- Catcall because b signature is like a
                if {SIT_UTIL}.class_name_lowercase (a_type).is_equal({SIT_UTIL}.class_name_lowercase (l_rel.item.secondary_type)) then
                    Result := l_rel.item
                end
            end
            check
                not_found_relationship: Result /= Void
            end
        end

Solution

  • Conformance property is antisymmetric, i.e. if A → B and B → A, then A = B. Therefore, two types are equal is they conform to each other:

        a_type.conforms_to (l_rel.item.secondary_type) and
        l_rel.item.secondary_type.conforms_to (a_type)
    

    (Although, conforms_to compares types of objects and not objects themselves, the expression above is still OK, because due to conformance rules A = B if and only if TYPE [A] = TYPE [B] when A and B are types themselves.)

    If one of the types is attached and another one is detachable, you still may want to compare them as equal. In this case, the following code could be used:

        is_conforming (a_type, l_rel.item.secondary_type) and
        is_conforming (l_rel.item.secondary_type, a_type)
    

    where the comparison predicate ignores the attachment mark:

    is_conforming (t1, t2: TYPE [detachable ANY]): BOOLEAN
      do
        Result :=
          ({REFLECTOR}.type_of_type ({REFLECTOR}.detachable_type (t1.type_id))).conforms_to
          ({REFLECTOR}.type_of_type ({REFLECTOR}.detachable_type (t2.type_id)))
      end