DOG proposal
Research: This page describes research about Eiffel, not the actual language specification.
Contents
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.