2012-08-18

signals

7.27: adda/cstr/signals:
7.30: intro:
. pyqt signals are a system of inter-object communication;
any object can emit a signal
to convey that some event has occurred;
and, any other object may connect a signal handler
to be launched whenever a particular object
raises a particular signal .
. signals can return any sort of record,
and the corresponding signal handlers
are expected to declare their parameter's type
to be the same type as the signal's returned record .
. pyqt sees signals as launching slots
and then the act of connecting a signal handler
is filling such a slot with a subprogram .
. there can be multiple connections to a slot,
so the slot is often filled with multiple handlers .

7.10: adda/cstr/signals (like exceptions but don't propagate):
. signals are meant to support python's
use of exceptions for the EAFP idiom:
"(it's easier to ask forgiveness than permission).
. eg, it has a substring finder
that returns the target's index,
but if the target wasn't found
then it throws an exception .
. exceptions are in contrast to routines;
signals are an alternative way to
return data from a routine without having to
return control to the caller;
or, it can indicate whether the return is valid .
. exception and signals both use an if/case
but the key word is (on) instead of (?):
eg, on sig: handler;
on sig -- example of case-stmt syntax .
   # val1: hndl-1;;;
   # val2: hndl-2;
   #;
--
python's EAFP (Easier to ask for forgiveness than permission.):
    This common Python coding style
    assumes the existence of valid keys or attributes
    and catches exceptions if the assumption proves false.
    This clean and fast style is characterized by
    the presence of many try and except statements.
    The technique contrasts with the LBYL style
    common to many other languages such as C.
python's LBYL (Look before you leap):
    . explicitly tests for pre-conditions
    before making calls or lookups.
    This style contrasts with the EAFP approach
    and is characterized by the presence of
    many if statements.
7.26:
. is there an efficient  way to implement
pyqt's signals and slots?
. how do we track which obj' launched a signal?
. can we ensure each obj' has an id
by locking it in one place
so that the address is the id?
7.27:
. the state space I see so far:
{ does the obj emit signals or not? }
x { does obj`id come from address being fixed
or from having an id# stored within value of self?}

. if we copy an obj, does that include its
signal connections?
signaling is an obj- vs value-based attribute;
(ie, if a var x = 2 is in a signal connection
we care about changes to x,
not about changes to any vars of value 2 );
so, in addition to copy-obj,
there should be a separate ability to
copy an obj's signaling connections .

. there can also be separate connection directions:
direction# out(obj emits signals):
[7.30:
. when an obj' emits signals,
that shows up at the notification center as
for obj#eg --(our example)
  for signal#1 do slot#eg-1
  for signal#2 do slot#eg-2 ...
so if we want our copy's signaling
to have the same effect as the originals's,
then the copy's slots should each point at
the corresponding original's slots .]
direction# in(obj listens for signal):
[7.30:
. when we say an obj listens for a signal,
we mean it was the one that
ordered a signal connection
based on its own interests;
whereas a copy of that obj
may not have the same interests
(from being in a different context, etc);
however,
we could design relative connections:
the listener who makes this connection
is identifying itself to the notification center;
and all the slots are filled with relative methods:
(ie, the connection means:
when that signal happens,
ask the listener to do this method to itself).
. now when wanting to copy an obj's connections#in
we simply ask the notifier for them:
give me this obj's connections,
and copy them but with me as the listener .
. that would cover some the typical cases,
and then to deal with special situations,
an obj's documentation would simply indicate
that the connection copies are complex,
and could perhaps provide functions for
how to personalize the relevant slots .]

. the typical reason for signals
is to let the gui view inform the app model
of when some widget state has changed;
so the typical signal is ChangedValue;
but, even a rom-obj has a reason to emit
at least one signal:
when the obj is being read . [7.30:
. actually there can be many reason's;
because, there are many possible requests
(ie, by which method was the obj accessed).
. if we are tracking who's making the request,
then we could also listen for particular clients .]

. if we want any obj to be watchable
this costs the whole system either {time, space}:
# quick ways that use more space:
. before the exec does anything with an obj,
it needs to check the obj's signal bit
for whether its emitting or not
(that's quick but costs space) .
[7.30: why doesn't the obj just
control its own signaling
and then sending it messages would
auto'ly raise these signals?
because sometimes we want info
that the obj' didn't intend on giving us;
in that case, we set its signal bit,
and that reminds the exec to
check with the notification center
for what is being watched about
interactions that occur with this obj .]
# compact ways that cost more time:
. the alternative is to save space by
asking the notifications operator
whether the given address is registered as
being watched (being an emitter of signals) .

. it would save a lot of resources if obj's were
watchable only if declared to be watchable?
but then we are constantly checking type:
is this a watchable type?
[7.30: no, the first assuption is right:
by declaring an obj as watchable,
we can at least confine costs to
just those obj's that are typed watchable;
because, the code in the exec that was
checking the signal bit of every obj,
can now be put inside every method
of just the watchable-typed obj's .]

. lets explore an example, numbers:
I don't want to watch every number
but a class should be able to declare itself as
both watchable and serving as a number .
. when a type adopts number's interface,
number's type mgt has to ask it for things
and then, being a type that also adopted
the signaling interface
it would emit signals it had declared, [7.30:
and also check with the notification center
for any new thing it might need to report .]

. by supporting oop everywhere [7.31:
(or at least everywhere we might need
signaling dynamically)]
we can get signaling by swapping out components
for similar types that also do signaling;
this can be automated too:
. any time there's a type defined,
we are auto-generating a
corresponding signaling .type;
and if we need the extra signaling service,
we just swap-out its type tag
to point to its signaling subclass .

. so signaling is indeed using up a bit,
but the bit is in the type tag, not the obj's data;
eg, a signed type tag means a signaling type .
[. earlier we had seen how a signal bit is not needed,
but if obj's can change signaling behavior dynamically,
then the type tag has to reflect that change .
. only by knowing whether an obj' is a signaling type
can the exec know whether it makes sense to
request that the obj be watched .
. it would work like this:
the listener wants to put a watch on a target,
so it requests that of the notification center;
and, at that time the center checks the target's type
to see whether it has adopted the signaling interface .
. if it hasn't, then it simply changes its type tag
which is then going to reroute all messages
to the twin type that does do signaling;
ie, every method in the signaling type mgt
expects it's being watched
and keeps the notification center informed .]

[7.30:
. a signaling type is communicating like so:
whenever it enters a method (after being called)
it checks with the notification center
for the current set of listener needs:
given what the center advises,
the signaling type can set 2 internal truth vars:
# watchMods -- should I signal modifications?
# watchReads -- should I signal each access? .
. the center can get data during this check-in
like who the method's caller is,
which method was called,
and what the obj's id is . [8.11:
. it's making this call:
( watchMods, watchReads)`notify(myId, thisMethod, caller);
and that's how the notifications center
is setting (watchMods, watchReads)
depending on the conditions of
(myId, thisMethod, caller) .]
. it can also know a list of what is
readable or writable by the current method,
and knowing that could tell the center
whether read or write signals could be interesting .
. here, for example,
is how modifications might be sensed:
the compiler checks for places where
an obj's instance vars are getting modified
(where they're assigned a value
or given to an out-mode param )
and at each such place
it stores a hash of the current value,
then after the assignment
it compares that with a new hash;
if they differ, then it sets a modBit;
finally, at the end of a method's procedure,
it raises a modHappened signal
if modBit and watchMods are both true .]

7.28: syntax: signal connection:
. the signal connection should be done with
this syntax:
on obj`signal: [listener's signal handler] .

7.28: syntax: signal launch:
. how do we launch a signal?
. since signals are much like like exceptions
we might do a (raise signal);
. but that is rather wordy for such a routine task;
shouldn't we just have to mention a signal
the same we mention a function to call it?
ie, it should treat it like a function because [7.31:
its affect on program flow is
more like a function than an exception .]
. despite concerns about wordiness,
exceptions should still use the raise-keyword
-- just like the return-keyword is used --
to make it obvious that the program flow
is terminating .

7.28: syntax: signal declarations and connection statements:
. if you say( s(x.t).signal )
to declare a signal,
and then say( on s: body; )
to connect that signal to an action;
then in the body,
x.t will be available for reading .

7.28: handler parameter specifications:
. the parameters of the pyqt signal are
not your typical function params;
rather, they indicate what objects
will be implicitely available to the handler . [7.31:
. the signal declaration may seem more intuitive
if it is explained that it is mirroring
the way the signal's handler
either should be declared
or will be implicitely declared
within the block that will be doing the handling .
(what's actually happening is that
the signal actually is as defined:
the act of signaling
is calling the notification center
and passing it data or addresses;
finally, it is the notification center
that is running the handler's code
within the context of the signal's inputs .]
. logically it seems
the handler's param's should be optional;
because, what if the handler
has no need for them ?
given the proposed syntax, that point is moot:
. they are merely implicit in the handler
so it's not that the handler is declaring them;
rather, any function used as the handler
is using the implicit params in the on`body
as actual parameters to whatever param's
the handler happened to have declared .

7.28: the optional sender reference:
. in an on-signal body, due to this syntax:
( on obj`signal: body )
-- where obj is the one raising the signal --
another symbol available to the body
is the particular raiser, obj
(pyqt refers to the signaling obj as the sender;
however, the sender's verb for sending is emit).
[7.31:
. in pyqt, only oop-type obj's can be senders
(the syntax is self`emit(signal, param))
but I'm thinking it makes sense for subprograms too,
in several situations:
# sender irrelevant:
. we might be listening for a program event
and not care who the sender is;
eg, a signal may indicate a keyboard event
and we may want to simulate such an event .
. if we say (on someType`signal ...),
we could handle a given signal the same
regardless of which obj it came from,
as long as the signaler was of that type;
and, if we said (on `signal ...)
then we'd be interested in the activities of
any obj from any type that supports that signal .
# subprograms are people too!:
. even if we do want to know which entity is sender,
a subprogram can be considered such an entity;
because, their stack record is their obj,
and they can cause events of interest to
another subprogram or oop-type object .
--
. a subprogram can be thought of as
an obj in which the only method is initialize:
. for most obj's, initialization (including creation)
is launched by a declaration,
while the subprogram's creation and init
are done by a call to what amounts to
the subprogram's type mgt:
the code that is shared by
all the instances of the subprogram .
. for most obj's, finalization and disposal
are launched by the disposal of the parent obj:
the entity that requested the declaration;
whereas a subrogram requests its own disposal .]

7.28: the optional sender reference/tasking:

. so, signals are sent and received by both
oop-types and subprograms;
hows it work for tasks or task types?
well, if adda is doing oop the right way
-- with strong encapsulation --
then why can't all obj's be tasks? [8.11:
ie, if we know signaling works for oop,
then we know works for tasking ]

. review of what tasking is:
each task is a virtual processor
that is implemented by a separate core;
and, any var that is loaned to a task
can only be accessed by one core at a time .
[8.11: (keep in mind for the following
that the main reason for it
is building an exec and compiler system
that will save the coder from having to remember
all the details of safe multi-threaded coding) .]

. the way oop works with tasking means that
if a subprogram, sub, has access to native types
(ie, the types that our cpu actually supports,
like integers, floats, and truth)
then sub has to ensure that there are
no sharing of that object between threads; [8.11:
eg, if a task or obj is given
write-access to one of sub's vars,
then sub can't access that var again
until the task is done making that assignment .
. for non-native types (ie, oop types)
we are not concerned with assignments;
because, the oop obj
is owned only by its oop mgt;
so, say that we have several threads with
write access to the same oop-type obj;
what they actually have is nothing but
permission to call the obj's oop mgt,
and ask it do the writing for them;
so, even if we have all these writings at once,
the obj's type mgt is simply queueing them,
and doing them one at a time .]
. for tasks or type mgt's that are
just reading a native type,
the simple way is to just give them a copy;
but what about native string?
such a copy could be expensive .
. well, there's no efficiency reason
for the cpu to be managing string anyway:
the few hotspots it needs to handle directly
are mainly numeric or truth vars;
. for the one native obj that is
taking the numeric's return,
the compiler can guarantee that the sub
-- with its command of multiple threads --
can't do anything else with that native obj
until that type mgt has finished writing to it . [8.11:
. the safe thing to do for native obj's
is never give their address to other tasks
unless it's for an operation who's termination
the sub can afford to wait for .]

. the only thing the main process can do while
waiting for type mgt to modify its native obj's
is feed other type mgts more jobs,
or operate on the remaining native obj's
that are not currently loaned to other threads
(eg, for loop control vars
incremented directly by the cpu).

7.30: mis: if the obj id should be on board...:
. when adopting signals,
if the obj id should be onboard
then it can be added by having the signaling types
being a subclass of Extensible ...
--[mis: it can't practically be onboard ]--
[8.11: nevertheless,
this idea could still be good for
an id that was specific to the notification center;
because, the obj id's I have devised
(where obj's belong to certain activation records
which in turn belong to certain processes)
involve a pathname that is slow to access,
unless the exec is already into
the given (process, act'rec);
so, when the signaler makes that call
-- `notify(myId, ...) --
it would be nice if myId was a 16bit integer
that the notifier could quickly recognize .]
. the extension is a ptr (or dope vector)
into a dyno-ivars dict [a symbol table for
dynamically allocated instance vars]
that lets you map names to values;
one name the notification center adds
is signalObjId .
mis:
. if a typedef predeclares some signals,
then it will have this as part of its ivars;
so, then asking for this ivar won't require
searching the dyno-ivars dict .
--[8.11:
. that assumes that signals need space;
but they are basically static functions;
the only space needed is for introspection,
where you want to find an obj's signals;
in that case, you ask its type mgt,
and if want dynamic signal info
then you ask the notification center .]

[obs:] 7.27: 1 bit can serve both read & write signaling:
. just 1 bit can serve both read & write signaling
by saying that if you want your type to signal readings
then you should include the readtime in your obj's data,
then signal that a latest access date has been modified .
[7.30:
... . but given the current design of the system,
there, is no need for this mechanism;
as the exec is no longer having to check a signal bit .]

[mis:] 5.18: adda/cstr/signals/how gui notifications work:

[@] an update of this is at
6.4: adda/gui notification systems .
and in turn, this file is an update of 6.4 .


how notification signals work:
. an obj x is gui'd by declaring it like so:
x.gui.t -- .gui is like a pointer type:
when something is passed x, in this example,
that thing was expecting x to be type t,
but anything expecting type t,
will also accept anything that returns type t,
including pointers, functions, and gui objects .

. also embedded is a pointer to the image in the gui list .[*]
. gui is recognized as a subclass of the notification type,
(todo prove notifications are a generalization of gui mgt),
*[5.31: do you really need a pointer?
it should work like qt's notification center,
where the obj's address is enough to map it to a
record in the notification db,
and that record has a pointer to the
image in the gui list .]

. how does gui mgt know which place in gui list
the updated obj is located?
. this is the same problem as a
subtree needing a ptr to its parent,
but in this case,
the subtree is being relocated quite frequently .
. at least the moves are limited to the top level?
the top level list is what switches a lot
as the display focus moves among windows .
. just go down the list looking for your obj,
however,
you often find not the object itself,
but a sublist containing the object .
todo: more qt studies may be helpful .

gui mgt uses a general notification system:
. an object of type notification has 2 parts:
# the needed obj
# some notification info .
. the notification record includes the id of
the object needing to be notified, eg, gui mgt,
and the info needed by the one being notified,
eg, the link to the image needed by gui mgt .

5.31: gui ptr vs type tag bits:

. an alt to the gui ptr is a bit set to indicate whether
modifications need to emit a signal to the notification center .
. another useful bit was const,
but even if several bits are needed
the gui ptr idea could save some space;
... but,
how is something supposed to know
whether it's a ptr, if the ptr is optional?
there has to be a definite header with a type tag
saying whether the obj is a value, ptr, const, etc .
(and any other notifications or capababilities).
. the only simple way to be efficient
is to type parameters to be non-obj's
and then unbox obj's going into those param's .

5.31: does every adda obj have an id or const address?:
. the notification center needs the obj's address
in order to know what slots to launch .

3 comments:

  1. 8.12: adda/oop/type.tag format:
    . a lot of space could be saved if
    every obj's type.tag size could be reduced;
    we could do a byte encoding for the most common types,
    and then some of that byte's bytecodes
    would be reserved as discriminants
    for indicating the tag's remaining format
    (eg, it's the next byte, word or long).
    . another way to use discriminant codes
    is to indicate the type's surtype
    (enum8, enum16, pointer, function, sequence, etc);
    [10.7: for instance,
    using 4 bits of the byte for the system types,
    1 bit for if there's a next byte,
    and 3 bits for the most common infratypes .]

    ReplyDelete
  2. 8.11: adda/signals/out-mode parameters:
    . when is it that a signal would need
    out-mode parameters? [8.21:
    . some terminology that would make more sense
    is to recognize that parameters belong to
    the signal's handler, not the signal itself;
    the signal is just passing some info to the handler,
    and the handler sees that info
    as its list of parameters .
    . if one of those param's is out.mode,
    that means every handler of this signal
    is modifying an object chosen by the signal
    -- and the chosen object could be
    internal to the signal's emitter .]
    . if there can be multiple connections to a signal,
    then we have multiple assignments being made
    to this out-mode parameter . [8.21:
    . the compiler must check to ensure
    that a signal handler's out.mode targets
    are always oop objects, not native types;
    because only oop objects are threadsafe;
    ie, all messages to an oop object
    are serialized by the obj's type mgt .
    . the way to understand this as datatyping
    is to see that native types don't support
    adda's safe pointers,
    so you can't take their address .]

    ReplyDelete
  3. 8.12: adda/cstr/signals/dealloc:
    . if signalers couldn't signal their dealloc,
    then for every act'rec* dealloc
    the notification center would need to
    check every signal entry for being
    a member of that act'rec -- too expensive!
    . the object that is emitting it needs to
    signal when it has reached end of life,
    at which time the notification center knows to
    deallocate that object's signal entry
    so that it can use that signaler id for something else .
    *: every obj belongs to some act'rec,
    which belongs to some process
    (these are part of every obj's pointer's full pathname).

    ReplyDelete