# Difference between revisions of "Catcall checkpoints"

These examples should be considered for all catcall solutions:

## faces of covariance

The following example shows the difference between generic covariance and non-generic covariance.

```class A [G]
feature
f (t: T) do end
put (g: G) do end
end

class B [G]
inherit A [G] redefine f end
feature
f (u: U) do end
end

local
a_any: A [ANY]
a_string: A [STRING]
b_any: B [ANY]
b_string: B [STRING]
t: T
do
a_any := a_string
a_any.put (5) -- catcall for generic feature
a_any.f (t) -- no catcall

a_any := b_any
a_any.put (5) -- no catcall
a_any.f (t) -- catcall for non-generic feature

a_any := b_string
a_any.put (5) -- catcall for generic feature
a_any.f (t) -- catcall for non-generic feature
end```

A safe and expressive solution should have a way to allow all valid cases and prohibit the invalid ones. This needs a way to address the generic and non-generic features indiviually.

## contravariance

```class SORTER [G]
feature
sort (a_list: LIST [G]; a_comparator: COMPARATOR [G])
do
-- Somewhere in the loop:
a_comparator.compare (l_string_1, l_string_2)
end
end

class EXAMPLE
feature
make
local
l_list: LIST [STRING]
l_string_sorter: SORTER [STRING]
l_any_comparator: COMPARATOR [ANY]
do
-- Should be allowed to sort the string list with an
-- ANY comparator
l_string_sorter.sort (l_list, l_any_comparator)
end
end```

Solutions which pass this test are likely to be expressive for agents as well.

### Agents

For agents, we will look at an example with the type `T` and a subtype `U`. We will see an agent declaration and then check which arguments that are allowed:

#### Calling agents

```local
an_agent: PROCEDURE [ANY, TUPLE [T]]
-- An agent which takes an argument of type T.
do
-- The following calls are currently valid and should remain valid.
an_agent.call ([T])
an_agent.call ([U])

an_agent.call ([T, ...])
an_agent.call ([U, ...])
end```

These basic cases mostly rely on the tuple conformance rules to work properly.

#### Assigning agents

To allow anything that is safe is more tricky. It requires the ability to model contravariance.

```local
an_agent: PROCEDURE [ANY, TUPLE [T]]
-- An agent which takes an argument of type T.
do
agent_empty := agent () do end --> PROCEDURE [ANY, TUPLE []]
agent_any := agent (a: ANY) do end --> PROCEDURE [ANY, TUPLE [ANY]]
agent_t := agent (t: T) do end --> PROCEDURE [ANY, TUPLE [T]]
agent_u := agent (u: U) do end --> PROCEDURE [ANY, TUPLE [U]]
agent_tt := agent (t: T; t2: T) do end --> PROCEDURE [ANY, TUPLE [T, T]]

-- This assignment is naturally allowed as they are the same type.
an_agent := agent_t

-- The following assignments are save but prohibited by the current implementation.
-- If they were allowed it would benefit event driven programming in Eiffel a lot.
-- As agents currently are modeled over the generic mechanism any solution which
-- solves the "comparator problem" is likely to pass here too.
an_agent := agent_empty
an_agent := agent_any

-- The following assignments are currently permitted. This is not the correct
-- behavior  as you could either create a catcall by passing a T argument to the
-- `agent_u' or pass the wrong number of arguments by passing a [T] tuple to the
-- `agent_tt'.
an_agent := agent_u
an_agent := agent_tt
end```