1
Introduction to Programming
Tuples and Agents
Exercise Session
1 and 2 December 2008
Chair of Software Engineering
This week
Tuples
Agents
Observer Pattern (revisited)
Chair of Software Engineering
2
Tuples
A tuple of type TUPLE [A, B, C] is a sequence of at
least three values, first of type A, second of type B,
third of type C.
In this case possible tuple values that conform are:
[a1, b1, c1], [a1, b1, c1, x1],...
where ai is of type A, bi of type B, ci of type C and
xi of some type X
Tuple types (for any types A, B, C, ... ):
TUPLE
TUPLE [A]
TUPLE [A, B]
TUPLE [A, B, C]
...
Chair of Software Engineering
Labeled Tuples
Tuples may be declared with labeled arguments:
tuple: TUPLE [food: STRING; quantity: INTEGER]
Same as an unlabeled tuple:
TUPLE [STRING, INTEGER]
but provides easier (and safer!) access to its
elements:
May use
io.print (tuple.food)
instead of
io.print (tuple.item(1))
Chair of Software Engineering
Labeled vs. unlabeled tuples
tuple_safety_test
local
t1: TUPLE [STRING, INTEGER]
t2: TUPLE [food: STRING; quantity: INTEGER]
s : STRING
do
t1 := [“chicken”, 66]
t2 := [“chicken”, 66]
s := t1.item(1)
s := t2.item(1)
s := t2.food
end
Chair of Software Engineering
Tuple type inheritance
TUPLE
TUPLE [A]
TUPLE [A, B]
Chair of Software Engineering
Tuple conformance
tuple_conformance
local
t0: TUPLE
t2: TUPLE [INTEGER, INTEGER]
do
Not necessary in this
create t2
case
t2 := [10, 20]
Implicit creation
t0 := t2
print (t0.item (1).out + "%N")
Compiles, but
print (t0.item (3).out)
precondition violation at
runtime
end
Chair of Software Engineering
What are agents in Eiffel?
Objects that represent operations
Can be seen as operation wrappers
Similar to delegates in C#, closures in Java,
functors in C++
Chair of Software Engineering
Agent definition
Every agent has an associated routine, the one
that the agent wraps and is able to invoke
To get an agent, use the agent keyword
e.g. an_agent := agent my_routine
This is called agent definition
What’s the type of an_agent?
Chair of Software Engineering
EiffelBase classes representing agents
call
PROCEDURE
ROUTINE
deferred
effective
FUNCTION
PREDICATE
Chair of Software Engineering
item
Open and closed agent arguments
An agent can have both “closed” and “open” arguments:
closed arguments set at agent definition time
open arguments set at agent call time.
To keep an argument open, replace it by a question mark
u := agent a0.f (a1, a2, a3) -- All closed
w := agent a0.f (a1, a2, ?)
x := agent a0.f (a1, ?, a3)
y := agent a0.f (a1, ?, ?)
z := agent a0.f (?, ?, ?) -- All open
Chair of Software Engineering
Agent calls
An agent invokes its routine using feature “call”
f (x1: T1; x2: T2; x3: T3) -- defined in class C with
-- a0: C; a1: T1; a2: T2; a3: T3
u := agent a0.f (a1, a2, a3)
u.call ([])
v := agent a0.f (a1, a2, ?)
v.call ([a3])
w := agent a0.f (a1, ?, a3)
w.call ([a2])
x := agent a0.f (a1, ?, ?)
x.call ([a2, a3])
y := agent a0.f (?, ?, ?)
y.call ([a1, a2, a3])
Chair of Software Engineering
Agent declaration
p: PROCEDURE [ANY, TUPLE]
-- Agent representing a procedure belonging to a
-- class that conforms to ANY. At least 0 open
-- arguments
q: PROCEDURE [C, TUPLE [X, Y, Z]]
-- Agent representing a procedure belonging to a
--class that conforms to C. At least 3 open arguments
f: FUNCTION [ANY, TUPLE [X, Y], RES]
-- Agent representing a function belonging to a class
-- that conforms to ANY. At least 2 open arguments,
-- result of type RES
Chair of Software Engineering
Example
class
ANIMAL
create make
feature {NONE} -- Initialization
make (s: STRING)
-- Create a new animal with name `s'.
do
name := s
end
feature -- Access
name: STRING
feature -- Basic operations
eat (food: STRING; quantity: INTEGER)
-- Eat `quantity' of `food'.
do
print (name + " eats " + quantity.out + " " + food + ".%N")
end
... See next page
end
Chair of Software Engineering
Eating with an agent
Fill in the blanks, so that when eat_wrapper is called on
an animal called “Mew”, the text “Mew eats 5 grass” is printed.
class ANIMAL
... (same as before)
eat_wrapper
-- Call `eat' with an agent.
local
a: PROCEDURE [ANIMAL, TUPLE [STRING, INTEGER]]
do
a := agent eat (?,?)
a.call (["grass", 5])
end
end
Chair of Software Engineering
Eating with an agent (2)
Fill in the blanks again, so that the text “Mew eats 5
grass” is printed.
class C
feature
r
local
a: ANIMAL
an_agent: PROCEDURE [ANIMAL, TUPLE [STRING, INTEGER]]
do
create a.make (“Mew")
an_agent :=
agent a.eat
an_agent.call (["grass", 5])
end
end
Chair of Software Engineering
Eating with an agent (3)
class C
feature
r
local
a: ANIMAL
an_agent: PROCEDURE [ANIMAL, TUPLE]
do
create a.make (“Mew")
an_agent := agent a.eat (“grass”, 5)
an_agent. call ([])
end
end
Chair of Software Engineering
Eating with an agent (4)
class C
feature
f
do
r (“grass”, 5)
end
r (s: STRING; i: INTEGER)
local
an_agent: PROCEDURE [ANIMAL, TUPLE [STRING, INTEGER]]
a: ANIMAL
do
create a.make (“Mew")
an_agent := agent a.eat (?, ?)
an_agent. call ([s, i])
end
end
Chair of Software Engineering
Open targets
It is also possible to leave the target of an
agent call open, to increase flexibility
This is done at agent definition
an_agent := {MY_TYPE} agent my_routine
MY_TYPE is the type to which my_routine
belongs
Chair of Software Engineering
Eating with an agent (5)
class C
feature
f
local
a: ANIMAL
do
create a.make (“Mew”)
r (a, “grass”, 5)
end
r (a: ANIMAL; s: STRING; i: INTEGER)
local
an_agent: PROCEDURE [ANIMAL, TUPLE [ANIMAL, STRING, INTEGER]]
do
an_agent := agent {ANIMAL}.eat (?, ?)
an_agent. call ([a, s, i])
end
end
Chair of Software Engineering
Why do we need agents anyway?
Suppose that depending on a certain event
that may happen, you have to call one
routine out of many
Suppose you don’t know exactly which
routine to invoke, because you have to (or
want to) leave the choice to your clients
Chair of Software Engineering
Another example
Consider you are designing a GUI.
When a button in the GUI is pressed, several other
classes may be interested in this event.
However, you shouldn’t hard-code in the BUTTON
class which routines of which classes will be called
when the button is pressed.
Rather, you should let any classes interested in
this event register one of their routines to be
called when the button is pressed.
These routines will be passed to the BUTTON class
as agents and will be called when the button is
pressed.
And this brings us to the Publish-Subscribe
Pattern…
Chair of Software Engineering
The Publish-Subscribe Pattern
*
PUBLISHER
attach
detach
trigger
23
update*
*
SUBSCRIBER
subscribed: LIST […]
subscribe+
unsubscribe+
…
PUB_2
…
+
PUB_1
* Deferred (abstract)
+ Effective (implemented)
Chair of Software Engineering
+
update+
SUB_1
SUB_2
Inherits from
Client (uses)
The Publish-Subscribe pattern
Publisher keeps a list of observers:
subscribed: LINKED_LIST [SUBSCRIBER]
To register itself, an observer may execute
subscribe (some_publisher)
where subscribe is defined in SUBSCRIBER:
subscribe (p: PUBLISHER)
-- Make current object observe p.
require
publisher_exists: p /= Void
do
p.attach (Current)
end
Chair of Software Engineering
Attaching an subscriber
In class PUBLISHER:
attach (s: SUBSCRIBER)
-- Register s as subscriber to current publisher.
require
subscriber_exists: s /= Void
do
.
subscribed extend (s)
end
The invariant of PUBLISHER includes the clause
subscribed /= Void
(List subscribed is created by creation procedures of PUBLISHER)
Chair of Software Engineering
Triggering an event
trigger
-- Ask all observers to
-- react to current event.
do
from
subscribed.start
until
subscribed.after
loop
subscribed.item.update
subscribed.forth
end
end
*
PUBLISHER
GUI_CLASS
attach
detach
*
SUBSCRIBER
APP_CLASS
Each descendant of SUBSCRIBER defines its own version
of update
Chair of Software Engineering
update*
update+
Limitations of the pattern
27
Each publisher object knows about its observers
There is only one update procedure in SUBSCRIBER:
At most one operation
Not reusable — must be coded anew for each
application
Chair of Software Engineering
Exercise
28
Write a program that handles a GUI with 2 buttons.
When the first button is pressed, a counter gets
increased, while when the second button is pressed,
the same counter gets decreased. The value of the
counter is printed in both cases to the console.
Provide 2 solutions, one that does not use the agents
and one that uses them.
Discuss the differences
Chair of Software Engineering
Backup slides
Chair of Software Engineering
29
Exercise: a news agency
Consider you must create an application which
allows a news agency to dispatch news to various
papers, radio and TV stations, etc.
How would you design and implement this
application?
Chair of Software Engineering
Exercise
You are given a working program with
1 effective publisher: BUTTON
3 effective subscribers: PRINTER, COUNTER, and
RANDOM_NUM
subscribers react on (simulated) button clicks
Your task is to
merge 3 subscribers into one class: BUTTON_LISTENER
keep update features separate (rename them)
pass the renamed update features as agents to publisher
Chair of Software Engineering
31
© Copyright 2026 Paperzz