Dynamic scoping (was: Proposal: Squeak-E = Squeak x Kernel-E)

Stephen Pair spair at acm.org
Tue Jan 28 04:39:56 UTC 2003


Actually, thread-local storage was the original motivation for
RuntimeEnvironments (although I hadn't considered allowing pool
variables to be declared in that way).  It quickly became apparent that
tls and dynamic scoping is really the same thing.  Thread local storage
implies that the storage is associated with the thread, and that's the
main reason that RuntimeEnvironments currently reside in Process.
However, I think we do need something that is stack based because we
really cannot see what lies ahead in terms of processes and scheduling
(Continuations is a great example in this regard; the debugger is yet
another).  Putting things directly into Process or keying them off of
Process can make the solution unnecessarily brittle.

Currently, my basic argument is that while we should use the context
stack to access the dynamic context, the dynamic varaible stack and the
call/return context stack should not be inter-twined because the
call/return mechanism can restrict what you are able to with dynamic
variable binding.  I'll give two examples:

A) You want to set some dynamic variable for everything that follows
temporally (including forked processes)

B) You want a called context's dynamic bindings to not be affected by
direct manipulation of the dynamic bindings in a calling context (if you
do a simple parent traversal based on the context stack, you cannot
achieve that effect).  This is paricularly important for continuations
because contexts can be copied and have multiple activations...unless
the continuation framework is careful about copying dynamic bindings
when it copies the stack, you can get yourself into a mess here.

I could also imagine a VM that might do away with Process and schedules
contexts independently.  Instead of #fork, you might have an
asynchronous message send bytecode.  The question in such a system is
how do you maintain dyanmic context (and exception handlers are a form
of dynamic context) during such asynchronous message sends?  For example
(assuming that async means send asynchronously):

----
SomeClass>>someMethod

	[self async doSomething] on: Error do: [ :ex | self
handleException ].

----

Would you expect the handler to get evaluated if an exception happened
in #doSomething?  Even if #doSomething is happening asynchronously?
This would roughly equate to:

----
SomeClass>>someMethod

	[[self doSomething] fork] on: Error do: [ :ex | self
handleException ].
----

Which of course would not handle an error that occurs in
#doSomething...but should it?  If so, then you can't rely on the context
stack alone to provide you with the exception handler contexts because
handler context may go out of scope as processing handling context
proceeds in parallel with the processing of #doSomething.

I wonder if there has been anything written in past on this specific
case?  Ignoring the implementation and limitations of current exception
handling systems, wouldn't it make sense for these exception handlers be
in effect even in the presence of a forked process?

- Stephen

> -----Original Message-----
> From: squeak-dev-bounces at lists.squeakfoundation.org 
> [mailto:squeak-dev-bounces at lists.squeakfoundation.org] On 
> Behalf Of David Simmons
> Sent: Monday, January 27, 2003 7:01 PM
> To: 'The general-purpose Squeak developers list'
> Subject: RE: Dynamic scoping (was: Proposal: Squeak-E = 
> Squeak x Kernel-E)
> 
> 
> Oops, my bad. I forgot to add the "tls" 
> (thread-local-storage) qualifier to the <X> shared-field declaration.
> 
> Class name: MyContextCollection
>     shared-fields: tls X; "obviously choosing a better name here"
> 
> > {
> >     Method [
> >     withContextDo: valuable
> > 	  X := {self, X}.
> >         "optionally, various exception guards could go here
> >          to handle resolution via exceptions, etc"
> >        ^valuable finally: [X := X[2]].
> >     ]
> >     Method [
> >     resolve: expr
> >         |tuple| := X.
> >         [tuple] whileNotNil: [
> >             tuple[1].internalQuery(expr) !? [:r| ^r].
> >             tuple := tuple[2].
> >         ].
> > 	 ^nil. "indicate failure"
> >     ]
> > }
> 
> -- Dave S. [SmallScript Corp]
> 
> ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> SmallScript for the AOS & .NET Platforms 
> David.Simmons at SmallScript.com http://www.smallscript.org
> 
> 
> > -----Original Message-----
> > From: David Simmons [mailto:david.simmons at smallscript.com]
> > Sent: Monday, January 27, 2003 3:57 PM
> > To: 'The general-purpose Squeak developers list'
> > Subject: RE: Dynamic scoping (was: Proposal: Squeak-E = Squeak x 
> > Kernel-E)
> > 
> > Have you considered something like:
> > 
> > a) thread (st-process) local pool (shared) variable
> > 
> > 	X
> > 
> > b) MyContextCollection
> >    withContextDo: valuable
> > 	  X := Array with: self with: X.
> >        ^valuable ensure: "finally:" [
> > 		X := X at: 2.
> >         ].
> > 
> > This assumes a mechanism for supporting per/process (thread-local) 
> > shared variables.
> > 
> > In SmallScript this could be written as:
> > 
> > Class name: MyContextCollection
> >     shared-fields: X "obviously choosing a better name here" {
> >     Method [
> >     withContextDo: valuable
> > 	  X := {self, X}.
> >         "optionally, various exception guards could go here
> >          to handle resolution via exceptions, etc"
> >        ^valuable finally: [X := X[2]].
> >     ]
> >     Method [
> >     resolve: expr
> >         |tuple| := X.
> >         [tuple] whileNotNil: [
> >             tuple[1].internalQuery(expr) !? [:r| ^r].
> >             tuple := tuple[2].
> >         ].
> > 	 ^nil. "indicate failure"
> >     ]
> > }
> > 
> > -- Dave S.
> > 
> > ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> > SmallScript for the AOS & .NET Platforms 
> David.Simmons at SmallScript.com
> > http://www.smallscript.org
> > 
> > > -----Original Message-----
> > > From: squeak-dev-bounces at lists.squeakfoundation.org 
> > > [mailto:squeak-dev- bounces at lists.squeakfoundation.org] 
> On Behalf Of 
> > > Stephen Pair
> > > Sent: Monday, January 27, 2003 1:03 PM
> > > To: 'The general-purpose Squeak developers list'
> > > Subject: RE: Dynamic scoping (was: Proposal: Squeak-E = 
> Squeak x Kernel-
> > E)
> > >
> > > What is not clear about those semantics?  Since the transcript 
> > > output occurs before setting the value, the correct output is:
> > >
> > > 0
> > > 0
> > >
> > > Originally, I wanted the ability set a value for all subsequent 
> > > operations that occur in a process...however, to accomplish that 
> > > *and* use the stack for maintaining scope enclosures 
> would be quite 
> > > convoluted (if at all possible).  And, it's also not 
> clear to me at 
> > > this point whether or not I really need that ability.
> > >
> > > - Stephen
> > >
> > > > -----Original Message-----
> > > > From: squeak-dev-bounces at lists.squeakfoundation.org
> > > > [mailto:squeak-dev-bounces at lists.squeakfoundation.org] 
> On Behalf 
> > > > Of Avi Bryant
> > > > Sent: Monday, January 27, 2003 3:29 PM
> > > > To: The general-purpose Squeak developers list
> > > > Subject: RE: Dynamic scoping (was: Proposal: Squeak-E = 
> Squeak x 
> > > > Kernel-E)
> > > >
> > > >
> > > >
> > > > On Mon, 27 Jan 2003, Stephen Pair wrote:
> > > >
> > > > > Actually, I rather like the #dynamicValue pattern.  Why not
> > > > this then:
> > > > >
> > > > > ----
> > > > > DynamicContext clamp: [
> > > > > 	#foo dynamicValue: 42.
> > > > > 	self assert: #foo dynamicValue = 42
> > > > > ].
> > > > >
> > > > > self assert: #foo dynamicValue isNil
> > > > > ----
> > > > >
> > > > > With the above, if you need to set several values, you
> > > > don't need to
> > > > > enclose your code in several blocks.
> > > >
> > > > True, but I find the semantics less clear. Say I capture a 
> > > > continuation just before the call to #dynamicValue:, 
> and then come 
> > > > back to it:
> > > >
> > > > |k|
> > > >
> > > > #foo dynamicValue: 0.
> > > > DynamicContext clamp: [
> > > >   k := Continuation current.
> > > >   Transcript cr; show: #foo dynamicValue.
> > > >   #foo dynamicValue: 42.
> > > > ]
> > > >
> > > > k ifNotNil: [k value].
> > > >
> > > > Does this show
> > > >
> > > > 0
> > > > 0
> > > >
> > > > or
> > > >
> > > > 0
> > > > 42
> > > >
> > > > on the Transcript?
> > > >
> > > > If you want to be able to set multiple bindings at 
> once, I would 
> > > > suggest
> > > >
> > > > DynamicContext bindAll: {#foo -> 42} during: [...]
> > > >
> > > >
> > > >
> > > >
> > > >
> > >
> > 
> 
> 
> 
> 



More information about the Squeak-dev mailing list