## A.4 library(broadcast): Broadcast and receive event notifications

The `library(broadcast)` library was invented to realise GUI applications consisting of stand-alone components that use the Prolog database for storing the application data. Figure 12 illustrates the flow of information using this design

Figure 12 : Information-flow using broadcasting service

The broadcasting service provides two services. Using the `shout' service, an unknown number of agents may listen to the message and act. The broadcaster is not (directly) aware of the implications. Using the `request' service, listening agents are asked for an answer one-by-one and the broadcaster is allowed to reject answers using normal Prolog failure.

Shouting is often used to inform about changes made to a common database. Other messages can be ``save yourself'' or ``show this''.

Requesting is used to get information while the broadcaster is not aware who might be able to answer the question. For example ``who is showing X?''.

broadcast(+Term)
  Broadcast Term. There are no limitations to Term, though being a global service, it is good practice to use a descriptive and unique principal functor. All associated goals are started and regardless of their success or failure, broadcast/1 always succeeds. Exceptions are passed.
broadcast_request(+Term)
  Unlike broadcast/1, this predicate stops if an associated goal succeeds. Backtracking causes it to try other listeners. A broadcast request is used to fetch information without knowing the identity of the agent providing it. C.f. ``Is there someone who knows the age of John?'' could be asked using

              ...,
              broadcast_request(age_of('John', Age)),

  If there is an agent (listener) that registered an `age-of' service and knows about the age of `John' this question will be answered.

listen(+Template, :Goal)
  Register a listen channel. Whenever a term unifying Template is broadcasted, call Goal. The following example traps all broadcasted messages as a variable unifies to any message. It is commonly used to debug usage of the library.

      ?- listen(Term, (writeln(Term),fail)).
      ?- broadcast(hello(world)).
      hello(world)

      Yes

listen(+Listener, +Template, :Goal)
  Declare Listener as the owner of the channel. Unlike a channel opened using listen/2, channels that have an owner can terminate the channel. This is commonly used if an object is listening to broadcast messages. In the example below we define a `name-item' displaying the name of an identifier represented by the predicate name_of/2.

      :- pce_begin_class(name_item, text_item).

      variable(id,    any,    get, "Id visualised").

      initialise(NI, Id:any) :->
              name_of(Id, Name),
              send_super(NI, initialise, name, Name,
                         message(NI, set_name, @arg1)),
              send(NI, slot, id, Id),
              listen(NI, name_of(Id, Name),
                     send(NI, selection, Name)).

      unlink(NI) :->
              unlisten(NI),
              send_super(NI, unlink).

      set_name(NI, Name:name) :->
              get(NI, id, Id),
              retractall(name_of(Id, _)),
              assert(name_of(Id, Name)),
              broadcast(name_of(Id, Name)).

      :- pce_end_class.

unlisten(+Listener)
  Deregister all entries created with listen/3 whose Listener unify.
unlisten(+Listener, +Template)
  Deregister all entries created with listen/3 whose Listener and Template unify.
unlisten(+Listener, +Template, :Goal)
  Deregister all entries created with listen/3 whose Listener, Template and Goal unify.
listening(?Listener, ?Template, ?Goal)
  Examine the current listeners. This predicate is useful for debugging purposes.