Changes between Version 5 and Version 6 of signals


Ignore:
Timestamp:
11/22/2010 02:51:01 PM (13 years ago)
Author:
marcel.taeumel
Comment:

TOC added; some format fixes; missing headlines added

Legend:

Unmodified
Added
Removed
Modified
  • signals

    v5 v6  
     1[[PageOutline(1-3)]]
     2
    13= Introduction =
    24
     
    68=== Object Dependents ===
    79
    8 Every object in Squeak has a list of dependent objects. You trigger an event with ''`#changed:`'' or ''`#changed:with:`'' and all dependents receive a ''`#update:`'' resp. ''`#update:with:`'' call. Dependents are managed using ''`#addDependent:`'' and ''`#removeDependent:`''.
     10Every object in Squeak has a list of dependent objects. You trigger an event with `#changed:` or `#changed:with:` and all dependents receive a `#update:` resp. `#update:with:` call. Dependents are managed using `#addDependent:` and `#removeDependent:`.
    911
    1012Squeak processes will not be considered and data structures have to secured to avoid synchronization problems. Using this mechanism, objects are connected completely and not only in special cases because there is no filtering possible.
    1113
    12 ''Note on performance issues:'' As you see in the benchmarks, setting up thousands of bindings is quite slow. Therefore you should subclass ''`Model`'' instead of ''`Object`'' if you want to write faster code. ''`Model`'' uses a custom implementation of ''dependents''. But it is not possible for Morphs because they subclass from ''`Object`'' directly.
     14''Note on performance issues:'' As you see in the benchmarks, setting up thousands of bindings is quite slow. Therefore you should subclass `Model` instead of `Object` if you want to write faster code. `Model` uses a custom implementation of ''dependents''. But it is not possible for Morphs because they subclass from `Object` directly.
    1315
    1416=== Object Events ===
     
    4749=== Morphic Callbacks ===
    4850
    49 Default mouse or keyboard input events can be connected using ''`#on:send:to:`''. This avoids the need to implement, e.g., ''`#mouseDown:`'', or ''`#keyStroke:`'' but messages with more readable names.
     51Default mouse or keyboard input events can be connected using `#on:send:to:`. This avoids the need to implement, e.g., `#mouseDown:`, or `#keyStroke:` but messages with more readable names.
    5052
    5153This approach is only limited to these standard events and cannot be used so create arbitrary connections.
     
    6971|| Events are defined for a specific class/subclass ||        ||   ||   ||   || ? || ● ||
    7072|| Bindings are at Event level ||                           ● || ● ||   || ● || ? || ● ||
    71 || Bindings are at Sender/Receiver level ||                   ||    || ● ||   || ? ||   ||
     73|| Bindings are at !Sender/Receiver level ||                   ||    || ● ||   || ? ||   ||
    7274|| Events are first-class objects ||                          || ● ||   ||   || ? ||   ||
    73 || Automatic truncation of arguments ||                     ● ||   ||   || ● || ? || ● ||
     75|| Automatic truncation of arguments ||                     ● ||   ||   || ● || ? || ● ||
    7476|| Explicit argument count check at binding-setup-time ||     ||   ||   ||   || ? || ● ||
    7577|| Explicit argument count check at event-trigger-time ||     || ● ||   ||   || ? ||   ||
     
    8082|| Event triggering can be limited to the sender ||           ||   ||   ||   || ? || ● ||
    8183|| Provides synchronisation mechansism for thread-safety ||   ||   ||   ||   || ? || ● ||
    82 || Explicit Event/Callback check at binding-setup-time ||     ||   ||   ||   || ? || ● ||
     84|| Explicit !Event/Callback check at binding-setup-time ||     ||   ||   ||   || ? || ● ||
    8385
    8486
     
    8991One sender was bound to 10000 receivers. Then one event was triggered and processed synchronously. The benchmark code is in the ''Signals'' package.
    9092
    91  ''Test-System:'' Core2Duo @ 2.54 GHz, 4096 MB DDR2 RAM, Windows 7 Professional, Squeak 4.1
     93 '''Test-System:''' Core2Duo @ 2.54 GHz, 4096 MB DDR2 RAM, Windows 7 Professional, Squeak 4.1
    9294
    9395||                        || Message[[br]]Sends || Announce-[[br]]ments || Object[[br]]Dependents     || Object[[br]]Events || Bindings || Signals ||
     
    9698
    9799
    98 === Terms ===
     100== Terms ==
    99101
    100102A ''signal'' is a method that can be called to trigger a callback. Then the signal will be ''emitted''.
     
    103105
    104106A ''connection'' is a pair of signal and callback. The pair is used to lookup all callbacks whenever a signal is emitted. A signal can have multiple connections.
     107
     108= How to Install =
    105109
    106110{{{
     
    109113|| [[Image(media/icons/custom:squeak_16.png, title="Recommended Squeak Version", nolink, right)]] || 4.1, 4.2 Alpha ||
    110114|| [[Image(media/icons/silk:application_home.png, title="Recommended Squeak VM Version", nolink, right)]] || 4.0.2 (Win), ? (Mac) ||
    111 || [[Image(media/icons/silk:cog.png, title="Recommended Cog VM Version", nolink, right)]] || ''not supported'' ||
     115|| [[Image(media/icons/silk:cog.png, title="Recommended Cog VM Version", nolink, right)]] || ''not tested with cog'' ||
    112116||'''Sources'''|| ||
    113 || [[Image(media/icons/silk:script_gear.png, title="Metacello Configuration", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/MetacelloRepository/YourConfiguration YourConfiguration] ||
     117|| [[Image(media/icons/silk:script_gear.png, title="Metacello Configuration", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/MetacelloRepository/ ConfigurationOfSignals] ||
    114118|| [[Image(media/icons/silk:database.png, title="Repository", nolink, right)]] || [http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/SwaUtilities/ SwaUtilities] ||
    115119
    116 || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || ''`Signals`'' ||
    117 || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || ''`SI-Wrapper`'' (optional) ||
    118 || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || ''`SI-OB-Morphic`'' (optional) ||
    119 || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || ''`SI-Reflection`'' (optional) ||
    120 || [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || ''`SI-Benchmarks`'' (optional) ||
    121 
    122 || [[Image(media/icons/silk:bullet_go.png, title="Dependents", nolink, right)]] || [http://www.squeaksource.com/OmniBrowser.html OmniBrowser] (optinal) ||
     120|| [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `Signals` ||
     121|| [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `SI-Wrapper` (optional) ||
     122|| [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `SI-OB-Morphic` (optional) ||
     123|| [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `SI-Reflection` (optional) ||
     124|| [[Image(media/icons/silk:package.png, title="Needed Packages from the Repository", nolink, right)]] || `SI-Benchmarks` (optional) ||
     125
     126|| [[Image(media/icons/silk:bullet_go.png, title="Dependents", nolink, right)]] || [http://www.squeaksource.com/OmniBrowser.html OmniBrowser] (optional) ||
    123127|| [[Image(media/icons/silk:bullet_go.png, title="Dependents", nolink, right)]] || [wiki:methodwrappers Method Wrappers] (optional) ||
    124128|| [[Image(media/icons/silk:bullet_go.png, title="Dependents", nolink, right)]] || [http://www.squeaksource.com/AXAnnouncements.html AXAnnouncements] (optional) ||
     
    130134Just load the ''Signals'' package from the Monticello HTTP repository.
    131135
    132 If you do not have OmniBrowser installed, just skip the ''SI-OB-Morphic'' package. You will not have a visual indicator in front of your method list in the code browser.
    133 
    134 There is some benchmark code in ''SI-Benchmarks'' that compares different callback mechanisms. If you do not have <code>AXAnnouncements</code> in your system, just ignore the warning on package loading.
    135 
    136 If you want to use ''wrapped signals'', you should have installed [[wiki:methodwrappers Method Wrappers]] first.
    137 
    138 After the installation has finished, start the TestRunner and run all tests you find in ''Signals-Tests''. They should all pass.
     136If you do not have `OmniBrowser` installed, just skip the ''SI-OB-Morphic'' package. You will not have a visual indicator in front of your method list in the code browser.
     137
     138There is some benchmark code in ''SI-Benchmarks'' that compares different callback mechanisms. If you do not have `AXAnnouncements` in your system, just ignore the warning on package loading.
     139
     140If you want to use ''wrapped signals'', you should have installed [wiki:methodwrappers Method Wrappers] first.
     141
     142After the installation has finished, start the Test-Runner and run all tests you find in ''Signals-Tests''. They should all pass.
    139143
    140144The ''Signals'' package contains several sub-packages:
    141145
    142  * ''`Signals-Core`'' ... main signals implementation
    143  * ''`Signals-Tests`'' ... tests for the core implementation
    144  * ''`SI-OB-Morphic`'' ... morphic extensions to OmniBrowser
    145  * ''`SI-Benchmarks`'' ... benchmmarks for Signals and other mechanisms, e.g., Announcements
    146  * ''`SI-Wrapper`'' ... turns each message into a signal using method wrappers
    147  * ''`SI-Reflection`'' ... search and browse signals in the image
     146 * `Signals-Core` ... main signals implementation
     147 * `Signals-Tests` ... tests for the core implementation
     148 * `SI-OB-Morphic` ... morphic extensions to `OmniBrowser`
     149 * `SI-Benchmarks` ... benchmmarks for Signals and other mechanisms, e.g., Announcements
     150 * `SI-Wrapper` ... turns each message into a signal using method wrappers
     151 * `SI-Reflection` ... search and browse signals in the image
    148152
    149153{{{
     
    163167}}}
    164168
    165 Each signal can have an arbitrary number of arguments. The emit-call triggers the callback. In this way, any method could be used as a signal. This could be very confusing for the developer, therefore it is not recommended. Calling ''`self emit`'' not inside a method context but a block context works as well.
     169Each signal can have an arbitrary number of arguments. The emit-call triggers the callback. In this way, any method could be used as a signal. This could be very confusing for the developer, therefore it is not recommended. Calling `self emit` not inside a method context but a block context works as well.
    166170
    167171Obviously, a signal is emitted by calling the method that is meant to be the signal:
     
    171175}}}
    172176
    173 You '''must not''' emit an object's signal from the outside. The following fails if not executed within the same instance as <code>myCounter</code>:
     177You '''must not''' emit an object's signal from the outside. The following fails if not executed within the same instance as `myCounter`:
    174178
    175179{{{
     
    206210== Basic Signal Processing ==
    207211
    208 In the simplest way, a signal is emitted from within the UI process of Squeak, e.g., in response to a Morphic <code>#mouseDown:</code> event:
     212In the simplest way, a signal is emitted from within the UI process of Squeak, e.g., in response to a Morphic `#mouseDown:` event:
    209213
    210214{{{
     
    250254}}}
    251255
    252 The automatic truncation can be used to avoid patterns like <code>#(1 2)</code> or <code>#()</code>. Arguments can be duplicated, i.e., <code>#(1 1)</code>.
     256The automatic truncation can be used to avoid patterns like `#(1 2)` or `#()`. Arguments can be duplicated, i.e., `#(1 1)`.
    253257
    254258== Disconnection ==
     
    304308Using a queue, an emitted signal causes the queue to be filled with the callbacks stored into blocks that have to be evaluated by a process frequently.
    305309
    306 The Squeak UI process has such a queue already that will be processed in the main world cycle frequently: ''`WorldState>>deferredUIMessages`''. Using this, basic connections from within the UI process will be queued if the signal is emitted from within any other process than the UI process automatically. Otherwise they are processed synchronously and blocking.
     310The Squeak UI process has such a queue already that will be processed in the main world cycle frequently: `WorldState>>deferredUIMessages`. Using this, basic connections from within the UI process will be queued if the signal is emitted from within any other process than the UI process automatically. Otherwise they are processed synchronously and blocking.
    307311
    308312Any queued connection can be blocking which means that the signal emitting process will be suspended until the callback waiting in the queue is processed:
     
    331335}}}
    332336
    333 This approach works with any queue. It is similar to ''`processEvents()`'' in the Qt Framework. In Squeak, the whole world can be kept responsive by calling ''`World>>doOneCycle`'' frequently.
     337This approach works with any queue. It is similar to `processEvents()` in the Qt Framework. In Squeak, the whole world can be kept responsive by calling `World>>doOneCycle` frequently.
    334338
    335339If you create a blocking connection and a signal is emitted with a queued callback to be processed in the same process, nothing will happen until the process is resumed from the outside. You should not do that.
     
    338342=== Waiting for Signals ===
    339343
    340 The ''`SignalSpy`'' can be used to wait for signals explicitly. Normally, it should be used in tests and not in the application itself:
     344The `SignalSpy` can be used to wait for signals explicitly. Normally, it should be used in tests and not in the application itself:
    341345
    342346{{{
     
    348352
    349353
    350 The signal spy catches all registered signals emitted from any process. Wait operations are blocking so be sure that the signals are emitted in another process. You can wait for a specific signal using: ''`#waitForSignal:`''.
    351 
    352 If you want to test for some properties of the next signal besides its name, use ''`#waitForNextSignalSatisfying:`'':
     354The signal spy catches all registered signals emitted from any process. Wait operations are blocking so be sure that the signals are emitted in another process. You can wait for a specific signal using: `#waitForSignal:`.
     355
     356If you want to test for some properties of the next signal besides its name, use `#waitForNextSignalSatisfying:`:
    353357
    354358{{{
     
    359363
    360364
    361 The structre stored by the <code>SignalSpy</code> is an array with two fields: signal name and signal arguments.
     365The structre stored by the `SignalSpy` is an array with two fields: signal name and signal arguments.
    362366
    363367== Awareness ==
     
    365369There is an extension to the OmniBrowser Framework that shows a small icon in front of signals in the message list:
    366370
    367 : [[Image:SignalsOmniBrowserMorphic.PNG]]
     371  [[Image(SignalsOmniBrowserMorphic.PNG, title="Signals have a custom icon in the message list.", nolink)]]
    368372
    369373Trying to load the Signals package into a Squeak image without OmniBrowser installed results in a warning that can be ignored safely.
     
    380384
    381385
    382 Unfortunately the signal emitting place, which is just a message send, and other message sends that are not callbacks will be found as well. To solve this problem, some reflective methods were added to ''`SystemNavigation`'' to allow browsing for connections and signal sends:
     386Unfortunately the signal emitting place, which is just a message send, and other message sends that are not callbacks will be found as well. To solve this problem, some reflective methods were added to `SystemNavigation` to allow browsing for connections and signal sends:
    383387
    384388{{{
     
    431435
    432436
    433 Such a method can benefit from its signature if there is an instance variable named ''`nameEdit`'' which sends the signal ''`#textChanged:`''. Automatic connections can be created from such patterns after the referenced instance variables were initialized:
     437Such a method can benefit from its signature if there is an instance variable named `nameEdit` which sends the signal `#textChanged:`. Automatic connections can be created from such patterns after the referenced instance variables were initialized:
    434438
    435439{{{
     
    466470
    467471
    468 To avoid this, it is possible to use '''any arbitrary message''' as a signal as long has the sub-package ''Signals-Wrapper'' is installed which needs the package/project [[wiki:methodwrappers Method Wrappers]] as well:
     472To avoid this, it is possible to use '''any arbitrary message''' as a signal as long has the sub-package ''SI-Wrapper'' is installed which needs the package/project [wiki:methodwrappers Method Wrappers] as well:
    469473
    470474{{{
     
    478482=== Advanced Patterns ===
    479483
    480 It is possible to access the sender of a signal itself and use it as an argument for the receiver. This is achieved with a ''`0`'' in the pattern and can reduce the number of needed methods because the control flow may consider the sender, e.g. different actions are triggered and show themselves on a log:
     484It is possible to access the sender of a signal itself and use it as an argument for the receiver. This is achieved with a `0` in the pattern and can reduce the number of needed methods because the control flow may consider the sender, e.g. different actions are triggered and show themselves on a log:
    481485
    482486{{{
     
    515519}}}
    516520
    517 Patterns can mix index references to the sender's arguments and default values: ''`#(2 1 =foobar)`''. As you see, the magic happens just because of the escape symbol ''`#=`''. Every value that comes after it, will be treated as itsself and not as an index reference.
     521Patterns can mix index references to the sender's arguments and default values: `#(2 1 =foobar)`. As you see, the magic happens just because of the escape symbol `#=`. Every value that comes after it, will be treated as itsself and not as an index reference.
    518522
    519523'''Hint:''' If you store an object into a pattern, the garbage collector will collect that object if it is not referenced somewhere else. In that case, ''nil'' will be supplied as argument.
     
    523527== General Implementation Approach ==
    524528
    525 * one central repository ''`SignalConnectionsRepository`'' stores all connections in the system
    526 * "''`self emit`''" looks into the call-stack to retrieve arguments and do other checks
    527 * the repository uses ''weak'' data structures to not interfere with the garbage collector
     529 * one central repository `SignalConnectionsRepository` stores all connections in the system
     530 * `self emit` looks into the call-stack to retrieve arguments and do other checks
     531 * the repository uses ''weak'' data structures to not interfere with the garbage collector
    528532
    529533== Next Possible Steps ==
     
    531535 * ''arguments processor'' to transform arguments before doing the callback
    532536 * detect recursions on connection level to prevent endless loops, e.g., count and reset a number in each connection
    533  * TestRunner coverage testing is broken because signals will not be emitted in the correct context and fail
     537 * Test-Runner coverage testing is broken because signals will not be emitted in the correct context and fail
    534538
    535539