Logging, Notifications and DynamicVariables (was: Re: [squeak-dev] The Trunk: Collections-cmm.538.mcz)

Chris Muller ma.chris.m at gmail.com
Wed Oct 2 16:34:23 UTC 2013


On Tue, Oct 1, 2013 at 10:22 PM, Levente Uzonyi <leves at elte.hu> wrote:
> On Tue, 1 Oct 2013, Chris Muller wrote:
>
>> In the context of Smalltalk-80, I can understand logging straight to
>> Transcript and using Transcript-specific functions (e.g., endEntry).
>> Today, I consider referencing Transcript directly to be bad-form,
>> simply because it tightly binds code to a particular UI.
>>
>> I prefer to signal Notifications to let the what-is-logged remain
>> independent of the where-its-logged.
>
>
> Notifications kill performance. Here's a small comparison of using no
> logging at all, using Notifications for logging, and using a
> ProcessLocalVariable for logging:

This is very interesting, thanks a lot for the code examples.  I did
not know about ProcessSpecificVariable; it reminds me of the
DynamicBindings external package.  Although these code examples appear
to not be using DynamicVariable quite correctly (i.e., DynamicVariable
class>>#value:during: does not accept an argument to its block); I
understand the concept you're presenting -- that a Dictionary lookup
is faster than a stack-walking Notification.

It's always good to remember the costs of using Notifications.  I do
think to generically say, "they kill performance" is a little
misleading, though, since no one is going to log inside of a
tight-loop.  If they did, they're gonna have bloated logs and
performance issues anyway.  I think logging should be used sparingly,
focusing on high-value messages; such as once at the start of
long-running process, or the details of an exceptional circumstance.
Used that way, performance is not affected.

Performance being equal leaves us to consider the aesthetic quality of
each approach.  I want logging code to have as little (visual) impact
on reading a method as possible.  Here I think Notifications are
better because they avoid the ifNotNil: conditional construct.

Additionally, with the built-in hierarchical structure of
Notifications, package-local logging is easily accomplished.
Attempting this with ProcessLocalVariable approach might require more
"lattice" in the signaling code, such as:

    MagmaLinkChange signal: 'Link changed'

vs.

    ProcessLocalVariable ifNotNil: [ : logger | logger log: 'Link
changed' atLevel: MagmaLinkChange ]

And, actually, this example (MagmaLinkChange) not only logs but
carries additional state on which the system must act.  Having a
single global handle all logging would not be able to handle some of
these one-off cases.

Like everywhere in engineering, I guess the optimal balance of
trade-offs must be assessed for every situation.

--- snipped the code examples ---

>>> always "Transcript" or "self". Replacing #endEntry with #flush won't hurt
>>> in
>>> most cases.
>>
>>
>> "Most" cases, or all?  I was intending to change all of MY sends of
>> endEntry to flush (if any), is there a caveat?
>>
>
> Yes. Replacing #endEntry with #flush in Transcript >> #flush would lead to
> infinite recursion. In some methods the receiver of #endEntry is a
> Transcripter, which doesn't have its own implementation of #flush. Without
> that it would break.

Ha, ok!  Funny man!   :)


More information about the Squeak-dev mailing list