DOG proposal

Research: This page describes research about Eiffel, not the actual language specification.

Introduction

This solution prevents catcalls by prohibiting polymorphic calls to features which are the source of potential catcalls.

Syntax

A new keyword "cat" (subject to change) is introduced. It can be applied in front of features and type declarations.

feature
  cat f (a: ANY)
      -- Such a feature is called a cat-feature
    local
      l: cat DOG -- Such a type is called a cat-type
    do
    end

Features and types with the "cat" keyword will be referred to from now on as cat-features and cat-types.

Semantics

In order to be able to redefine argument types of features covariantly and restrict the export status a feature has to be marked with the "cat" keyword. Such features can only be called on types which are declared with the "cat" keyword as well. The semantics of the "cat" keyword is that it is a monomorphic type. This is contrary to ordinary declarations which remain polymorphic. By allowing calls to "cat" features only on monomorphic types the compiler knows exactly which signature to check against. As the type cannot possibly change at runtime because of monomorphism of a cat-type the problem is avoided.

Conformance rules

The conformance stays the same but has one special case more: No type conforms to a cat-type except the same cat-type.

a: A
b: B
ca: cat A
cb: cat B
  -- Conform and therefore valid
a := a
a := b
a := ca
a := cb
b := b
b := cb
ca := ca
cb := cb
  -- Invalid (not all mentioned)
ca := a  -- `a' could be attached to an object of type `B'
ca := b  -- `ca' is monomorphic

Examples

See the introduction to examples for information about the classes used but we give enhanced versions for some classes:

class ANIMAL
feature
  cat eat (f: FOOD) do end
  cat sleep do end
end

This is needed so that the (covariant) redefinition of the argument types of these features or the restriction of the export status is valid.

Cats and dogs

local

 a: ANIMAL
 ca: cat ANIMAL
 c: CAT
 cc: cat CAT
 d: DOG
 cd: cat DOG
 f: FOOD
 cf: CAT_FOOD

do

   -- Invalid calls, both features are marked as cat.
 a.eat (f)
 a.sleep
 c.eat (cf)
   -- In order to be valid their target has to be of cat-type.
 ca.eat (f)
 ca.eat (cf)
 ca.sleep

end

Generics

Generics are not that obvious and clear defined in the article. However there is always one save solution.

local
  a: ANIMAL
  ca: cat ANIMAL
  la: LIST [ANIMAL]
  lca: LIST [cat ANIMAL]
  cla: cat LIST [ANIMAL]
  clca: cat LIST [cat ANIMAL]
  cllca: LINKED_LIST [cat ANIMAL]
do
    -- Invalid:
  lca := la  -- ANIMAL is not cat: The list could contain polymorphic animals
  lca := cla -- This is again because ANIMAL is not cat: Same reason as above.
  clca := lca -- This time it is because we assign to a cat LIST.
  clca := cla -- Here it is again because ANIMAL is not cat.
  clca := llca -- LINKED_LIST is not of cat-type.
    -- Invalid: Attachment to cat-type
  ca := la.item (1) -- The result is not cat-type while the target of the assignment is.
 
    -- Valid:
  la := lca
  la := cla
  la := clca
  lca := clca
  cla := clca
  lca := llca -- The list can still be used polymorphic
    -- Valid: Attachement to non cat-type
  a := la.item (1)
  a := lca.item (1)
  a := cla.item (1)
  a := clca.item (1)
    -- Valid: Attachement to cat-type
  ca := lca.item (1)
  ca := clca.item (1)
end

Issues

Lacks support for generics

The solution is not suited to prohibit catcalls occurring in the context of generics. If you assumes that each feature of a generic containing the formal as an argument is implicit cat you can only call them on cat lists:

feature
  list: LIST [ANY]
    local
      ll: cat LINKED_LIST [DOG]
    do
      create ll
      ll.extend (create {DOG})
    end
 
  not_so_nice
    local
      l: cat LIST [DOG]
      ll: cat LINKED_LIST [DOG]
    do
        -- You cannot write algorithms which fill lists implementation independent.
      -- INVALID: l := ll
        l.extend (create {DOG})
    end

This is because the base type of a generic has two kind of generic features: The ordinary ones like `is_equal' or other special features and then the ones who carry the formal as an argument. The difference is that a feature like `is_equal' changes its signature from LIST [A] to LINKED_LIST [A] but `put' does not.

Programmer needs foresight

This solution requires the programmer to think ahead. If a feature of a library is not marked as "cat" it becomes really difficult to change it later. This is not only because the owner of library is somebody else but also because it would invalidate probably a lot of existing code.

Conclusion

This solution is targeted to ordinary types. However, it can easily be paired with another solution specific for generics. They might even look the same or use partly the same keywords and form a good solution in symbiosis.