eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'QuerySignal':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: QuerySignal


Inheritance:

   Object
   |
   +--Signal
      |
      +--QuerySignal

Package:
stx:libbasic
Category:
Kernel-Exceptions
Version:
rev: 1.54 date: 2024/03/26 11:36:18
user: cg
file: QuerySignal.st directory: libbasic
module: stx stc-classLibrary: libbasic

Description:


Notice: 
    Signals have been replaced by class based Exceptions.
    They are provided for compatibility, but new code should use Exceptions
    (in this case: Query)

QuerySignals are like signals, except that they are not accepted
by handlers for ordinary signals.
I.e. a signal handler for a normal signal will not handle a query
signal. Thus, these bypass anySignal handlers.

However, if unhandled, no error is raised, instead they are simply ignored
and nil is returned from the raise
(as opposed to normal signals, which raise an unhandled signal exception).
QuerySignals are also ignored, if a handler exists, but rejects.

Their main use is to implement upQueries via signals, that work even 
if intermediate errorSignal handlers are present 
(which is not possible with ordinary signals, since errorSignal handlers 
 would catch those signals).

Code deep down in the calling hierarchy can post such an up-Query to ask
for some information or to pass some information upward. 

For example, the activityNotification mechanism is built on top of this:
everyone can send such a notification which is either handled by someone
up in the hierarchy (to show it in the windows info area) or simply
ignored.

Using QuerySignals for this (instead of regular Signals) helps in documenting
the intended usage of those signals.

Another use of querySignals is to provide additional information to
deeply nested methods, which is only required in the uncommon case;
or if another parameter is required by some method, which was not planned
for in the beginning, and you do not want to hand this value (via an
additional argument) through all intermediate levels.
A highly elegant solution to this problem is to provide a handler somewhere
at the top of the calling hierarchy, and raise an upQuery from whereever
that value is required.
A concrete application can be found in the windowGroup-lastEvent
queries. If anyone is interested in the windowEvent which was responible for 
being invoked, all he needs to do is to raise the lastEventQuerySignal, 
which returns that event.
No intermediate methods are required to know anything about that.
Another example is found in the way Metaclass asks for the nameSpace
when new classes are to be installed. A Browser may simply answer such
a query and provide a namespace (no need to pass that information down
the calling chain).

A final note (to C++ and Java fans):
    such upQueries are only possible, if the exception handling mechanism
    does not automatically unwind the stack for the handler invokation.
    Since the handler must be able to proceed the execution and return
    a value to the raiser ....
    ... another demonstration of why ST's exception mechanisms are superior.

copyright

COPYRIGHT (c) 1995 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

Instance protocol:

answering queries
o  answer: someAnswer do: aBlock
evaluate the argument, aBlock.
If the receiver is queried during evaluation, answer and proceed with someAnswer.
This is a wrapper for #handle:do: for lazy typists; no new functionality.

Usage example(s):

     |q|

     q := QuerySignal new.

     q answer:true do:[
        Transcript showCR:'query answers: ' , (q query printString).
     ]

Usage example(s):

     |q|

     q := QuerySignal new.

     q answer:false do:[
        Transcript showCR:'first query answers: ' , (q query printString).
        q answer:true do:[
            Transcript showCR:'second query answers: ' , (q query printString).
        ]
     ]

exception creation
o  newException
answer a new exception object for this signal

initialization
o  defaultAnswer: someValue
define the query's defaultAnswer to be someValue.
This is the same as defining an appropriate handlerBlock.

Usage example(s):

     QuerySignal new query
     (QuerySignal new defaultAnswer:true) query 
     (QuerySignal new defaultAnswer:false) query

Usage example(s):

     |sig rslt|

     sig := QuerySignal new.
     sig defaultAnswer:false.
     rslt := sig query.
     Transcript showCR:rslt.

Usage example(s):

     |sig rslt|

     sig := QuerySignal new.
     sig defaultAnswer:false.
     sig answer:true 
     do:[
         rslt := sig query
     ].
     Transcript showCR:rslt.

queries
o  accepts: aSignalOrExceptionClass
return true, if the receiver accepts the argument, aSignal.
(i.e. the receiver is aSignal or a parent of it). False otherwise.

o  defaultAnswer

o  handlerForSignal: signal context: theContext originator: originator
answer the handler block for the signal from originator.
The block is retrieved from aContext.
Answer nil if the signal is not handled

o  handles: anException
return true, if the receiver handles the argument, anException.
(i.e. the receiver is anExceptions signal or a parent of it)

o  isQuery
return true, if this is a query - always return true here

o  isQuerySignal
return true, if this is a querySignal - always return true here

raising
o  query
raise the query - return the handler's value, or the default
value, if there is no handler.

o  queryWith: aParameter
raise the query passing a parameter
- return the handler's value, or the default value, if there is no handler.

o  raise
QuerySignals are proceedable by definition,
so they should be raised with #query or #raiseRequest

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  raiseRequest
raise the query - return the handler's value, or the default
value, if there is no handler.
Invoking the handler is exactly the functionality of Signal>>raiseRequest,
but we can do it faster here, by avoiding the creation of a full-blown
exception object in case we find an answer:do: context.


Examples:


an up-query from a deeply nested operation to a higher level:
  |querySignal zero|

  zero := 0.
  querySignal := QuerySignal new.
  querySignal handle:[:ex |
      Transcript showCR:'query'.
      ex proceedWith:true
  ] do:[
      'nesting'.
      [
          [
              Object errorSignal handle:[:ex |
                  Transcript showCR:'some error: ' , ex errorString.
                  ex proceed
              ] do:[
                  [
                      1 // zero.  'an error which is caught in the handler'.
                      (querySignal query) == true ifTrue:[
                          Transcript showCR:'query says: ok'.
                      ] ifFalse:[
                          Transcript showCR:'query says: no'
                      ]
                  ] value
              ]
          ] value
      ] value
  ]
for lazy typists, a more compact interface is also provided (which is also easier to read):
  |querySignal|

  querySignal := QuerySignal new.
  querySignal answer:true do:[
      'nesting'.
      [
          [
              (querySignal query) == true ifTrue:[
                  Transcript showCR:'query says: ok'.
              ] ifFalse:[
                  Transcript showCR:'query says: no'
              ]
          ] value
      ] value
  ]
an up-query from a deeply nested operation, for which there is no handler: (notice, this would not work with normal signals, which would raise another unhandled exception-exception; also notice the == check #raise's return value being true, instead of a simple ifTrue; this handles a nil-value from the unhandled query)
  |querySignal zero|

  zero := 0.
  querySignal := QuerySignal new.

  [
      'nesting'.
      [
          [
              Object errorSignal handle:[:ex |
                  Transcript showCR:'some error: ' , ex errorString.
                  ex proceed
              ] do:[
                  [
                      1 // zero.  'an error which is caught in the handler'.
                      (querySignal raise) == true ifTrue:[
                          Transcript showCR:'query says: ok'.
                      ] ifFalse:[
                          Transcript showCR:'query says: no'
                      ]
                  ] value
              ]
          ] value
      ] value
  ] value
counter-example, just to show that things would not work this way with regular signals:
  |signal|

  signal := Signal new.
  'nesting deeply'.
  [
      [
          [
              [
                  [
                      (signal raise) == true ifTrue:[
                          Transcript showCR:'query says: ok'.
                      ] ifFalse:[
                          Transcript showCR:'query says: no'
                      ]
                  ] value
              ] value
          ] value
      ] value
  ] value
except, by handling the unhandled exception (but we think, that querySignals are easier to use and better document the intent):
  |signal|

  signal := Signal new.
  'nesting deeply'.
  [
      [
          [
              [
                  [
                      Signal noHandlerSignal handle:[:ex |
                          ex proceedWith:nil
                      ] do:[
                          (signal raise) == true ifTrue:[
                              Transcript showCR:'query says: ok'.
                          ] ifFalse:[
                              Transcript showCR:'query says: no'
                          ]
                      ]
                  ] value
              ] value
          ] value
      ] value
  ] value


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Thu, 21 Nov 2024 10:44:46 GMT