ppt - Chair of Software Engineering

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