Intro to Microsoft COM for Smalltalkers

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
49 messages Options
123
Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

kilon.alios
of course Pharo has an event queue, we call them announcements. That implies however that you want the code to execute as soon as something else happens. If you don't , fork and delay should be enough. With fork you dont need to wait for othet tasks to finish to execute your code, it will just put it to a thread and execute it concurently. If you want the code to run as soon as other tasks finish then of course you dont use fork.

On Mon, Oct 3, 2016 at 10:56 AM CodeDmitry <[hidden email]> wrote:
a JavaScript timeout is a function that takes a block and a period of time,
and after  this period of time, puts the block at the end of the event
queue, to be executed as soon as the runtime is done performing the tasks in
front of it.

I am not sure if Pharo has an event queue, so it's a bit harder to do
it(since without one you can't ensure only one thing happens at a time, and
strange things can happen).

That said, in simplest terms, imagine writing a clock app for Pharo, which
updates time every second, in JS this would be done by setting an interval
that ticks every 1000ms, and each time places the callback function(block)
at the end of the event queue.

Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ



--
View this message in context: http://forum.world.st/Intro-to-Microsoft-COM-for-Smalltalkers-tp4917738p4917835.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Denis Kudriashov
In reply to this post by CodeDmitry
Hi.

2016-10-03 9:49 GMT+02:00 CodeDmitry <[hidden email]>:
a JavaScript timeout is a function that takes a block and a period of time,
and after  this period of time, puts the block at the end of the event
queue, to be executed as soon as the runtime is done performing the tasks in
front of it.

I am not sure if Pharo has an event queue, so it's a bit harder to do
it(since without one you can't ensure only one thing happens at a time, and
strange things can happen).

That said, in simplest terms, imagine writing a clock app for Pharo, which
updates time every second, in JS this would be done by setting an interval
that ticks every 1000ms, and each time places the callback function(block)
at the end of the event queue.

In Pharo we have cheap green threads. You can write this:
["your code". 
1 seconds wait.] fork.

Also look at project TaskIt https://github.com/sbragagnolo/taskit. It provides many high level scheduling capabilities.

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

CodeDmitry
This post was updated on .
In reply to this post by kilon.alios
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Denis Kudriashov
And if this just for a graphical clock, a morph with step should be doing the trick.
stepTime can be set as well.

Phil

On Mon, Oct 3, 2016 at 10:09 AM, Denis Kudriashov <[hidden email]> wrote:
Hi.

2016-10-03 9:49 GMT+02:00 CodeDmitry <[hidden email]>:
a JavaScript timeout is a function that takes a block and a period of time,
and after  this period of time, puts the block at the end of the event
queue, to be executed as soon as the runtime is done performing the tasks in
front of it.

I am not sure if Pharo has an event queue, so it's a bit harder to do
it(since without one you can't ensure only one thing happens at a time, and
strange things can happen).

That said, in simplest terms, imagine writing a clock app for Pharo, which
updates time every second, in JS this would be done by setting an interval
that ticks every 1000ms, and each time places the callback function(block)
at the end of the event queue.

In Pharo we have cheap green threads. You can write this:
["your code". 
1 seconds wait.] fork.

Also look at project TaskIt https://github.com/sbragagnolo/taskit. It provides many high level scheduling capabilities.


Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Ben Coman
In reply to this post by CodeDmitry
On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:

> a JavaScript timeout is a function that takes a block and a period of time,
> and after  this period of time, puts the block at the end of the event
> queue, to be executed as soon as the runtime is done performing the tasks in
> front of it.
>
> I am not sure if Pharo has an event queue, so it's a bit harder to do
> it(since without one you can't ensure only one thing happens at a time, and
> strange things can happen).
>
> That said, in simplest terms, imagine writing a clock app for Pharo, which
> updates time every second, in JS this would be done by setting an interval
> that ticks every 1000ms, and each time places the callback function(block)
> at the end of the event queue.
>
> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ

Pharo has a single threaded VM, but multiple green threads can run concurrently.
The closest to the event loop you are thinking of most likely the
Morphic UI Process
which you can see using World > Tools > Process Browser.  When you execute code
from Playground it runs in that Process (note what Smalltalk
historically (circa 1970s?) has
called a Process is today more commonly know as a Green Thread)

If you select Morphic UI Process  you will see its call stack on the
right, where an interesting method is WorldState>>doOneCycleFor:
You can gain some insight by turning on auto-update in the Process
Browser, then open a Browser on WorldState>>doOneCycleFor:
and put "self haltOnce" at the top, then enable it via...
Pharo 5: World > System > Enable halt/inspect once.
Pharo 6: World > Debugging > Enable all break/inspect once.

You will see in the Process Browser that a new Morphic UI Process is
spawned, and the original Morphic UI Process call stack now has
#debugProcess at the top
and a debug window appears that you can step through.  Note, since two
UI loops are executing here, the image may lock up, but usually its
fine so hey! live on the edge!

In #runStepMethodsIn: you'll see "queue := self class
deferredUIMessages" for which you enqueue items like this...
http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html

After processing the deferred UI messages, each Morph's #step method
is processed by #runLocalStepMethodsIn:
refer... http://wiki.squeak.org/squeak/2096

The display is then rendered by #displayWorldSafely: calling...
--> #displayWorld
--> #displayWorld:submorphs:
which then is a lot to trace through, but depending on the graphics
back end eventually ends up calling...
Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
or...
AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
#drawOnAthensCanvas:


So, for a regular timed UI animation, you would define your custom
morph's #step and #stepTime methods,
and for lower level stuff you would fork like Dennis suggests.

cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Ben Coman
On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:

> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>> a JavaScript timeout is a function that takes a block and a period of time,
>> and after  this period of time, puts the block at the end of the event
>> queue, to be executed as soon as the runtime is done performing the tasks in
>> front of it.
>>
>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>> it(since without one you can't ensure only one thing happens at a time, and
>> strange things can happen).
>>
>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>> updates time every second, in JS this would be done by setting an interval
>> that ticks every 1000ms, and each time places the callback function(block)
>> at the end of the event queue.
>>
>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>
> Pharo has a single threaded VM, but multiple green threads can run concurrently.
> The closest to the event loop you are thinking of most likely the
> Morphic UI Process
> which you can see using World > Tools > Process Browser.  When you execute code
> from Playground it runs in that Process (note what Smalltalk
> historically (circa 1970s?) has
> called a Process is today more commonly know as a Green Thread)
>
> If you select Morphic UI Process  you will see its call stack on the
> right, where an interesting method is WorldState>>doOneCycleFor:
> You can gain some insight by turning on auto-update in the Process
> Browser, then open a Browser on WorldState>>doOneCycleFor:
> and put "self haltOnce" at the top, then enable it via...
> Pharo 5: World > System > Enable halt/inspect once.
> Pharo 6: World > Debugging > Enable all break/inspect once.
>
> You will see in the Process Browser that a new Morphic UI Process is
> spawned, and the original Morphic UI Process call stack now has
> #debugProcess at the top
> and a debug window appears that you can step through.  Note, since two
> UI loops are executing here, the image may lock up, but usually its
> fine so hey! live on the edge!


I meant to ask the list about a bug I hit doing this....

Putting a "self haltOnce" here...

  WorldState>>doOneCycleNowFor: aWorld
    DisplayScreen checkForNewScreenSize.
    self haltOnce.
    "process user input events"
    LastCycleTime := Time millisecondClockValue.
    self handsDo: [:h |
        self activeHand: h.
        h processEvents.
        self activeHand: nil.
    ].
    self activeHand: self hands first.
    aWorld runStepMethods. "there are currently some variations here"
    self displayWorldSafely: aWorld.


When stepping over "self activeHand: nil."
another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
in GLMPagerPanePreviewMorph(Morph)>>delete

  self activeHand
     releaseKeyboardFocus: self;
     releaseMouseFocus: self.


This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
but alternatively I wonder if the "self activeHand: nil" is really needed?
It seems redundant since activeHand is set at the top of the loop and
immediately after exiting the loop.
Eliminating it would reduce the propagation of #ifNil: anti-pattern.

https://pharo.fogbugz.com/default.asp?19169

cheers -ben

>
> In #runStepMethodsIn: you'll see "queue := self class
> deferredUIMessages" for which you enqueue items like this...
> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>
> After processing the deferred UI messages, each Morph's #step method
> is processed by #runLocalStepMethodsIn:
> refer... http://wiki.squeak.org/squeak/2096
>
> The display is then rendered by #displayWorldSafely: calling...
> --> #displayWorld
> --> #displayWorld:submorphs:
> which then is a lot to trace through, but depending on the graphics
> back end eventually ends up calling...
> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
> or...
> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
> #drawOnAthensCanvas:
>
>
> So, for a regular timed UI animation, you would define your custom
> morph's #step and #stepTime methods,
> and for lower level stuff you would fork like Dennis suggests.
>
> cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Ben Coman
On Mon, Oct 3, 2016 at 6:25 PM, Ben Coman <[hidden email]> wrote:

> On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:
>> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>>> a JavaScript timeout is a function that takes a block and a period of time,
>>> and after  this period of time, puts the block at the end of the event
>>> queue, to be executed as soon as the runtime is done performing the tasks in
>>> front of it.
>>>
>>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>>> it(since without one you can't ensure only one thing happens at a time, and
>>> strange things can happen).
>>>
>>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>>> updates time every second, in JS this would be done by setting an interval
>>> that ticks every 1000ms, and each time places the callback function(block)
>>> at the end of the event queue.
>>>
>>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>>
>> Pharo has a single threaded VM, but multiple green threads can run concurrently.
>> The closest to the event loop you are thinking of most likely the
>> Morphic UI Process
>> which you can see using World > Tools > Process Browser.  When you execute code
>> from Playground it runs in that Process (note what Smalltalk
>> historically (circa 1970s?) has
>> called a Process is today more commonly know as a Green Thread)
>>
>> If you select Morphic UI Process  you will see its call stack on the
>> right, where an interesting method is WorldState>>doOneCycleFor:
>> You can gain some insight by turning on auto-update in the Process
>> Browser, then open a Browser on WorldState>>doOneCycleFor:
>> and put "self haltOnce" at the top, then enable it via...
>> Pharo 5: World > System > Enable halt/inspect once.
>> Pharo 6: World > Debugging > Enable all break/inspect once.
>>
>> You will see in the Process Browser that a new Morphic UI Process is
>> spawned, and the original Morphic UI Process call stack now has
>> #debugProcess at the top
>> and a debug window appears that you can step through.  Note, since two
>> UI loops are executing here, the image may lock up, but usually its
>> fine so hey! live on the edge!
>
>
> I meant to ask the list about a bug I hit doing this....
>
> Putting a "self haltOnce" here...
>
>   WorldState>>doOneCycleNowFor: aWorld
>     DisplayScreen checkForNewScreenSize.
>     self haltOnce.
>     "process user input events"
>     LastCycleTime := Time millisecondClockValue.
>     self handsDo: [:h |
>         self activeHand: h.
>         h processEvents.
>         self activeHand: nil.
>     ].
>     self activeHand: self hands first.


A further curiousity occurs to me.  With this being executed 20 times
a second or more, how can the active hand ever be anything other than
the primary hand?
Why isn't the active hand stored, all hands cycled through processing
events, then the active hand restored??

cheers -ben


>     aWorld runStepMethods. "there are currently some variations here"
>     self displayWorldSafely: aWorld.
>
>
> When stepping over "self activeHand: nil."
> another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
> in GLMPagerPanePreviewMorph(Morph)>>delete
>
>   self activeHand
>      releaseKeyboardFocus: self;
>      releaseMouseFocus: self.
>
>
> This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
> but alternatively I wonder if the "self activeHand: nil" is really needed?
> It seems redundant since activeHand is set at the top of the loop and
> immediately after exiting the loop.
> Eliminating it would reduce the propagation of #ifNil: anti-pattern.
>
> https://pharo.fogbugz.com/default.asp?19169
>
> cheers -ben
>
>>
>> In #runStepMethodsIn: you'll see "queue := self class
>> deferredUIMessages" for which you enqueue items like this...
>> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>>
>> After processing the deferred UI messages, each Morph's #step method
>> is processed by #runLocalStepMethodsIn:
>> refer... http://wiki.squeak.org/squeak/2096
>>
>> The display is then rendered by #displayWorldSafely: calling...
>> --> #displayWorld
>> --> #displayWorld:submorphs:
>> which then is a lot to trace through, but depending on the graphics
>> back end eventually ends up calling...
>> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
>> or...
>> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
>> #drawOnAthensCanvas:
>>
>>
>> So, for a regular timed UI animation, you would define your custom
>> morph's #step and #stepTime methods,
>> and for lower level stuff you would fork like Dennis suggests.
>>
>> cheers -ben

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Denis Kudriashov
Hi Ben.

2016-10-03 12:37 GMT+02:00 Ben Coman <[hidden email]>:
A further curiousity occurs to me.  With this being executed 20 times
a second or more, how can the active hand ever be anything other than
the primary hand?
Why isn't the active hand stored, all hands cycled through processing
events, then the active hand restored??

Previous version of method was also with nil at the end:

self handsDo: [:h |
ActiveHand := h.
h processEvents.
ActiveHand := nil
].

Could you try your test on previous version of Pharo?

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Ben Coman
UIManager>>#defer: aBlock can be useful too.

defer: aBlock
" Evaluate the given Block in the UI thread as soon as there is nothing scheduled. Evaluate immediately when there is no UI"
aBlock value



For some fun, check also GrowlMorph

10 timesRepeat: [
(GrowlMorph openWithLabel: 'The time' contents: DateAndTime now)
" vanishDelay: 1000;
resetVanishTimer".
World doOneCycle ].


inspect how vanishDelay: works, so that you can get the same kind of thing as a JS

setTimeout(function(){ alert("Hello"); }, 3000);

Phil



On Mon, Oct 3, 2016 at 12:08 PM, Ben Coman <[hidden email]> wrote:

>
> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
> > a JavaScript timeout is a function that takes a block and a period of time,
> > and after  this period of time, puts the block at the end of the event
> > queue, to be executed as soon as the runtime is done performing the tasks in
> > front of it.
> >
> > I am not sure if Pharo has an event queue, so it's a bit harder to do
> > it(since without one you can't ensure only one thing happens at a time, and
> > strange things can happen).
> >
> > That said, in simplest terms, imagine writing a clock app for Pharo, which
> > updates time every second, in JS this would be done by setting an interval
> > that ticks every 1000ms, and each time places the callback function(block)
> > at the end of the event queue.
> >
> > Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>
> Pharo has a single threaded VM, but multiple green threads can run concurrently.
> The closest to the event loop you are thinking of most likely the
> Morphic UI Process
> which you can see using World > Tools > Process Browser.  When you execute code
> from Playground it runs in that Process (note what Smalltalk
> historically (circa 1970s?) has
> called a Process is today more commonly know as a Green Thread)
>
> If you select Morphic UI Process  you will see its call stack on the
> right, where an interesting method is WorldState>>doOneCycleFor:
> You can gain some insight by turning on auto-update in the Process
> Browser, then open a Browser on WorldState>>doOneCycleFor:
> and put "self haltOnce" at the top, then enable it via...
> Pharo 5: World > System > Enable halt/inspect once.
> Pharo 6: World > Debugging > Enable all break/inspect once.
>
> You will see in the Process Browser that a new Morphic UI Process is
> spawned, and the original Morphic UI Process call stack now has
> #debugProcess at the top
> and a debug window appears that you can step through.  Note, since two
> UI loops are executing here, the image may lock up, but usually its
> fine so hey! live on the edge!
>
> In #runStepMethodsIn: you'll see "queue := self class
> deferredUIMessages" for which you enqueue items like this...
> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>
> After processing the deferred UI messages, each Morph's #step method
> is processed by #runLocalStepMethodsIn:
> refer... http://wiki.squeak.org/squeak/2096
>
> The display is then rendered by #displayWorldSafely: calling...
> --> #displayWorld
> --> #displayWorld:submorphs:
> which then is a lot to trace through, but depending on the graphics
> back end eventually ends up calling...
> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
> or...
> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
> #drawOnAthensCanvas:
>
>
> So, for a regular timed UI animation, you would define your custom
> morph's #step and #stepTime methods,
> and for lower level stuff you would fork like Dennis suggests.
>
> cheers -ben
>
>
Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Denis Kudriashov
There has been some serious refactoring occuring in these specific bowels of the beast.

Phil

On Mon, Oct 3, 2016 at 1:08 PM, Denis Kudriashov <[hidden email]> wrote:
Hi Ben.

2016-10-03 12:37 GMT+02:00 Ben Coman <[hidden email]>:
A further curiousity occurs to me.  With this being executed 20 times
a second or more, how can the active hand ever be anything other than
the primary hand?
Why isn't the active hand stored, all hands cycled through processing
events, then the active hand restored??

Previous version of method was also with nil at the end:

self handsDo: [:h |
ActiveHand := h.
h processEvents.
ActiveHand := nil
].

Could you try your test on previous version of Pharo?


Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Ben Coman
A good trick is to use raw Display output.

Display getCanvas 
drawString: 'hello'
from: 1
to: 5
autoBoundAt: 0 @ 0
font: nil
color: Color black.



On Mon, Oct 3, 2016 at 12:25 PM, Ben Coman <[hidden email]> wrote:
On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:
> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>> a JavaScript timeout is a function that takes a block and a period of time,
>> and after  this period of time, puts the block at the end of the event
>> queue, to be executed as soon as the runtime is done performing the tasks in
>> front of it.
>>
>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>> it(since without one you can't ensure only one thing happens at a time, and
>> strange things can happen).
>>
>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>> updates time every second, in JS this would be done by setting an interval
>> that ticks every 1000ms, and each time places the callback function(block)
>> at the end of the event queue.
>>
>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>
> Pharo has a single threaded VM, but multiple green threads can run concurrently.
> The closest to the event loop you are thinking of most likely the
> Morphic UI Process
> which you can see using World > Tools > Process Browser.  When you execute code
> from Playground it runs in that Process (note what Smalltalk
> historically (circa 1970s?) has
> called a Process is today more commonly know as a Green Thread)
>
> If you select Morphic UI Process  you will see its call stack on the
> right, where an interesting method is WorldState>>doOneCycleFor:
> You can gain some insight by turning on auto-update in the Process
> Browser, then open a Browser on WorldState>>doOneCycleFor:
> and put "self haltOnce" at the top, then enable it via...
> Pharo 5: World > System > Enable halt/inspect once.
> Pharo 6: World > Debugging > Enable all break/inspect once.
>
> You will see in the Process Browser that a new Morphic UI Process is
> spawned, and the original Morphic UI Process call stack now has
> #debugProcess at the top
> and a debug window appears that you can step through.  Note, since two
> UI loops are executing here, the image may lock up, but usually its
> fine so hey! live on the edge!


I meant to ask the list about a bug I hit doing this....

Putting a "self haltOnce" here...

  WorldState>>doOneCycleNowFor: aWorld
    DisplayScreen checkForNewScreenSize.
    self haltOnce.
    "process user input events"
    LastCycleTime := Time millisecondClockValue.
    self handsDo: [:h |
        self activeHand: h.
        h processEvents.
        self activeHand: nil.
    ].
    self activeHand: self hands first.
    aWorld runStepMethods. "there are currently some variations here"
    self displayWorldSafely: aWorld.


When stepping over "self activeHand: nil."
another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
in GLMPagerPanePreviewMorph(Morph)>>delete

  self activeHand
     releaseKeyboardFocus: self;
     releaseMouseFocus: self.


This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
but alternatively I wonder if the "self activeHand: nil" is really needed?
It seems redundant since activeHand is set at the top of the loop and
immediately after exiting the loop.
Eliminating it would reduce the propagation of #ifNil: anti-pattern.

https://pharo.fogbugz.com/default.asp?19169

cheers -ben

>
> In #runStepMethodsIn: you'll see "queue := self class
> deferredUIMessages" for which you enqueue items like this...
> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>
> After processing the deferred UI messages, each Morph's #step method
> is processed by #runLocalStepMethodsIn:
> refer... http://wiki.squeak.org/squeak/2096
>
> The display is then rendered by #displayWorldSafely: calling...
> --> #displayWorld
> --> #displayWorld:submorphs:
> which then is a lot to trace through, but depending on the graphics
> back end eventually ends up calling...
> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
> or...
> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
> #drawOnAthensCanvas:
>
>
> So, for a regular timed UI animation, you would define your custom
> morph's #step and #stepTime methods,
> and for lower level stuff you would fork like Dennis suggests.
>
> cheers -ben



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Ben Coman
Here is some interesting event loop stuff from Tcl.


I wish we had some easy Tk UI building things in Pharo.

Spec is okay but not intuitive. As it is the only thing that exposes the myriad of various Morphs we have and shields us (somewhat) from the underlying details, we have to use it, but its explorability is really detrimental to the livecoding side of Pharo.

Phil

On Mon, Oct 3, 2016 at 12:25 PM, Ben Coman <[hidden email]> wrote:
On Mon, Oct 3, 2016 at 6:08 PM, Ben Coman <[hidden email]> wrote:
> On Mon, Oct 3, 2016 at 3:49 PM, CodeDmitry <[hidden email]> wrote:
>> a JavaScript timeout is a function that takes a block and a period of time,
>> and after  this period of time, puts the block at the end of the event
>> queue, to be executed as soon as the runtime is done performing the tasks in
>> front of it.
>>
>> I am not sure if Pharo has an event queue, so it's a bit harder to do
>> it(since without one you can't ensure only one thing happens at a time, and
>> strange things can happen).
>>
>> That said, in simplest terms, imagine writing a clock app for Pharo, which
>> updates time every second, in JS this would be done by setting an interval
>> that ticks every 1000ms, and each time places the callback function(block)
>> at the end of the event queue.
>>
>> Related: https://www.youtube.com/watch?time_continue=1&v=8aGhZQkoFbQ
>
> Pharo has a single threaded VM, but multiple green threads can run concurrently.
> The closest to the event loop you are thinking of most likely the
> Morphic UI Process
> which you can see using World > Tools > Process Browser.  When you execute code
> from Playground it runs in that Process (note what Smalltalk
> historically (circa 1970s?) has
> called a Process is today more commonly know as a Green Thread)
>
> If you select Morphic UI Process  you will see its call stack on the
> right, where an interesting method is WorldState>>doOneCycleFor:
> You can gain some insight by turning on auto-update in the Process
> Browser, then open a Browser on WorldState>>doOneCycleFor:
> and put "self haltOnce" at the top, then enable it via...
> Pharo 5: World > System > Enable halt/inspect once.
> Pharo 6: World > Debugging > Enable all break/inspect once.
>
> You will see in the Process Browser that a new Morphic UI Process is
> spawned, and the original Morphic UI Process call stack now has
> #debugProcess at the top
> and a debug window appears that you can step through.  Note, since two
> UI loops are executing here, the image may lock up, but usually its
> fine so hey! live on the edge!


I meant to ask the list about a bug I hit doing this....

Putting a "self haltOnce" here...

  WorldState>>doOneCycleNowFor: aWorld
    DisplayScreen checkForNewScreenSize.
    self haltOnce.
    "process user input events"
    LastCycleTime := Time millisecondClockValue.
    self handsDo: [:h |
        self activeHand: h.
        h processEvents.
        self activeHand: nil.
    ].
    self activeHand: self hands first.
    aWorld runStepMethods. "there are currently some variations here"
    self displayWorldSafely: aWorld.


When stepping over "self activeHand: nil."
another debugger appears MNU: receiver of "releaseKeyboardFocus:" is nil
in GLMPagerPanePreviewMorph(Morph)>>delete

  self activeHand
     releaseKeyboardFocus: self;
     releaseMouseFocus: self.


This can obviously be fixed by wrapping "self activeHand" with an #ifNil:
but alternatively I wonder if the "self activeHand: nil" is really needed?
It seems redundant since activeHand is set at the top of the loop and
immediately after exiting the loop.
Eliminating it would reduce the propagation of #ifNil: anti-pattern.

https://pharo.fogbugz.com/default.asp?19169

cheers -ben

>
> In #runStepMethodsIn: you'll see "queue := self class
> deferredUIMessages" for which you enqueue items like this...
> http://forum.world.st/Issue-3562-in-pharo-Deferred-UI-messages-executed-slowly-td3228060.html
>
> After processing the deferred UI messages, each Morph's #step method
> is processed by #runLocalStepMethodsIn:
> refer... http://wiki.squeak.org/squeak/2096
>
> The display is then rendered by #displayWorldSafely: calling...
> --> #displayWorld
> --> #displayWorld:submorphs:
> which then is a lot to trace through, but depending on the graphics
> back end eventually ends up calling...
> Canvas>>fullDrawMorph:    which ultimately invokes one of many #drawOn:
> or...
> AthensCanvas>>fullDrawMorph:    which ultimately invokes one of many
> #drawOnAthensCanvas:
>
>
> So, for a regular timed UI animation, you would define your custom
> morph's #step and #stepTime methods,
> and for lower level stuff you would fork like Dennis suggests.
>
> cheers -ben



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Thibault Raffaillac
In reply to this post by CodeDmitry
I am not very fond of event loops in general, because they imply "many inputs, one output" (process all pending events, then update screen).
For Morphic this is fine, because it displays on one screen, refreshing at/around its frequency. But there might be other screens, or network-output, file-output, which have different refresh frequencies. Then you would want to process input events as they trigger rather than storing them in a queue, such that whichever output destination sees the most up-to-date state of the program.

Javascript has this cool function, requestAnimationFrame, which sets a one-time callback right before the next redraw. In essence it is an output event, allowing some form of reactive programming (no loop, only callbacks on input and output).
In Pharo we have InputEventFetcher>>registerHandler: which is great for getting input callbacks, but nothing for output :/
WorldState>>addDeferredUIMessage: is probably a closest match, yet it is bound to Morphic, preventing experiments on UI/video games.

Any alternatives?

Thibault

> Here is some interesting event loop stuff from Tcl.
>
> http://wiki.tcl.tk/2567
>
> I wish we had some easy Tk UI building things in Pharo.
>
> Spec is okay but not intuitive. As it is the only thing that exposes the
> myriad of various Morphs we have and shields us (somewhat) from the
> underlying details, we have to use it, but its explorability is really
> detrimental to the livecoding side of Pharo.
>
> Phil

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

Offray Vladimir Luna Cárdenas-2
In reply to this post by philippeback
Hi,


On 02/10/16 17:13, [hidden email] wrote:

[...]
> Use it whenever you can, it will force you to understand how to do
> real stuff with it properly.
>
> I do hackathons with it.
> https://hackernoon.com/hackapost-how-hackathons-can-be-the-best-learning-tool-under-the-sun-9c97e567e0a5
>

As complementary to the infrastructure, code standards,  libraries and
so on, a needed contribution, from the social dynamics perspective, are
hachathons and workshops. We're making them regularly here (link at [1],
in Spanish), with a critical data/code literacy approach. Last week we
have our 5th edition and this week we're going to make an agile 6th edition.

[1] http://mutabit.com/dataweek/

I found the Pharo community very open to contribution. The fast feedback
loop [2] is experienced here in a very visible way and most of the time
the community is welcoming (with notable few exceptions, "ad hominen"
attacks and poor argumentation, but also with a good self-correcting
feedback from the broader community).

[2]
http://www.slideshare.net/MarcusDenker/perfection-feedback-loops-or-why-worse-is-better-65540840

So is not a perfect place, as any other, but you'll find a way of
contributing that is considered worthy and encouraged and even supported
with economical resources from Pharo Association / Consorcium from time
to time.

Welcome here, you and your contribution ;-),

Offray

Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Thibault Raffaillac

On Mon, Oct 3, 2016 at 3:00 PM, Thibault Raffaillac <[hidden email]> wrote:
I am not very fond of event loops in general, because they imply "many inputs, one output" (process all pending events, then update screen).
For Morphic this is fine, because it displays on one screen, refreshing at/around its frequency. But there might be other screens, or network-output, file-output, which have different refresh frequencies. Then you would want to process input events as they trigger rather than storing them in a queue, such that whichever output destination sees the most up-to-date state of the program.

One upfront queue with several workers is the way to do this fast and in a scalable way. Nothing new under the sun, Tuxedo has been doing this for eons, as is any decent TP framework. https://en.wikipedia.org/wiki/Tuxedo_(software) Most of this has been rehashed a lot of times bringing nothing new to the table.

Best closest thing for free would be RabbitMQ. Works fine. Even has an MQTT component, which makes it great for IoT.


Javascript has this cool function, requestAnimationFrame, which sets a one-time callback right before the next redraw. In essence it is an output event, allowing some form of reactive programming (no loop, only callbacks on input and output).

 
In Pharo we have InputEventFetcher>>registerHandler: which is great for getting input callbacks, but nothing for output :/
WorldState>>addDeferredUIMessage: is probably a closest match, yet it is bound to Morphic, preventing experiments on UI/video games.
Any alternatives?

This?

Maybe this (but not the same thing really)

For video games, well, the ususal update/render with framerate adjustment is the typical loop. 
If the render is too slow vs the expected one things are skipped, several updates for a render.
And user input is picked at one point during the update bit.
Not really the same as a windowed GUI.

Note that Windows has a queue per app these days (in 3.x days, it was a single queue for all of Windows, which is why things froze a lot. Same as current Pharo).


Note also that in Pharo, the InputEventFetcher etc is just the default way and one can have an image doing things otherwise. Display is the raw thing, primitives can do whatever, so if you feel like it, you can reinvent something fully different on the platform.



Thibault

> Here is some interesting event loop stuff from Tcl.
>
> http://wiki.tcl.tk/2567
>
> I wish we had some easy Tk UI building things in Pharo.
>
> Spec is okay but not intuitive. As it is the only thing that exposes the
> myriad of various Morphs we have and shields us (somewhat) from the
> underlying details, we have to use it, but its explorability is really
> detrimental to the livecoding side of Pharo.
>
> Phil



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
In reply to this post by Offray Vladimir Luna Cárdenas-2
Case in point, I am submitting a proposal here: https://devfest.be/blog/posts/cfp/

That's Google tech event here.

I proposed to showcase MDL in Pharo along with workshop. Let's see how it goes...

Phil

On Mon, Oct 3, 2016 at 4:43 PM, Offray Vladimir Luna Cárdenas <[hidden email]> wrote:
Hi,


On 02/10/16 17:13, [hidden email] wrote:

[...]
Use it whenever you can, it will force you to understand how to do real stuff with it properly.

I do hackathons with it. https://hackernoon.com/hackapost-how-hackathons-can-be-the-best-learning-tool-under-the-sun-9c97e567e0a5


As complementary to the infrastructure, code standards,  libraries and so on, a needed contribution, from the social dynamics perspective, are hachathons and workshops. We're making them regularly here (link at [1], in Spanish), with a critical data/code literacy approach. Last week we have our 5th edition and this week we're going to make an agile 6th edition.

[1] http://mutabit.com/dataweek/

I found the Pharo community very open to contribution. The fast feedback loop [2] is experienced here in a very visible way and most of the time the community is welcoming (with notable few exceptions, "ad hominen" attacks and poor argumentation, but also with a good self-correcting feedback from the broader community).

[2] http://www.slideshare.net/MarcusDenker/perfection-feedback-loops-or-why-worse-is-better-65540840

So is not a perfect place, as any other, but you'll find a way of contributing that is considered worthy and encouraged and even supported with economical resources from Pharo Association / Consorcium from time to time.

Welcome here, you and your contribution ;-),

Offray



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

CodeDmitry
This post was updated on .
In reply to this post by philippeback
CONTENTS DELETED
The author has deleted this message.
Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback


On Mon, Oct 3, 2016 at 6:47 PM, CodeDmitry <[hidden email]> wrote:
LOL (in GrowlMorph):
is: rect saneWithRespectTo: morphs

        ^(morphs anySatisfy: [ :morph | morph owner isNotNil and: [morph bounds
intersects: rect]]) not

for some reason I find this method name quite amusing :3

There are interesting things in there indeed. "Intention revealing" enough? 


Let me guess;

1. "World defer: aBlock." defers the event to be called as soon as
possible(not necessarily now).

Actually this works for any Morph in 5.0

Morph>>#defer: aValuable
"aValuable will be executed in the next UI rendering cycle"
self owner 
ifNotNil: [ self owner defer: aValuable] 
ifNil: [ UIManager default defer: aValuable ]

UIManager (MorphicUIManager) will do this at one point (track implementers 'til class side in WorldState)

defer: aValuable
"aValuable will be executed in the next UI rendering cycle"
self addDeferredUIMessage: aValuable.

This will stick it in a queue:

deferredUIMessages

^DeferredUIMessages ifNil: [DeferredUIMessages := WaitfreeQueue  new].

and then, there is interesting black magic going on 

runStepMethodsIn: aWorld
"Perform periodic activity inbetween event cycles"
| queue nextInQueue|
"If available dispatch some deferred UI Message"
queue := self class deferredUIMessages.

[(nextInQueue := queue nextOrNil) isNil]            "<<---------------- here all is happening -------"
whileFalse: [ nextInQueue value].

self runLocalStepMethodsIn: aWorld.                 "<<------------ step methods -----------------"

"The multi-threaded global Transcript needs to be updated periodically and synchronously with the UI."
Transcript stepGlobal.                                        "<<------------ and *this* is some black magic for Transcript ----"


Fun thing:

stepGlobal
" The superclass method Model>>step indicates a convention that might be used to interoperate 
synchronously with the UI-thread.  However when multiple Transcript windows are open, their 
PluggableTextMorphs share a single instance, from the global Transcript.  To avoid potential trouble, 
this method should not be named #step.  
As well, we need this method to execute even when no Transcript windows are open, so the stream 
continues to be reset periodically, otherwise it would grow indefinitely. So this method is invoked 
from WorldState>>runStepMethodsIn:. 
"

"Next three lines required temporarily to initialize instance variables added to existing instance"
deferredClear ifNil: [ deferredClear := false ].
deferredEndEntry ifNil: [ deferredEndEntry := false ].
stepContents ifNil: [ stepContents := '' ].
deferredClear ifTrue: 
[ deferredClear := false.  
stepContents := ''.
self changed: #clearText.
].
deferredEndEntry ifTrue: 
[ deferredEndEntry := false.  
self critical: 
[ stepContents := stream contents.
stream resetContents.
].
self changed: #appendEntry.
].

Just in case one was wondering how Transcript clear actually works, check this:

clear 
" Clear all characters by resetting the stream and voiding any previously flagged deferredEndEntry.
Redisplays the view by signalling for #step to send #changed: .
"
self 
critical: [ 
deferredClear := true.             "<------- magic! -------"
deferredEndEntry := false.     "<------- more magic!--------"
stream reset ]


Good luck to infer that from scratch.



  
2. "[Block] fork" is called immediatly, but on a new thread.

Yeah, use forkNamed: aString if you actually want to track the thing easily in the Process Browser.

 
3. "<number> <time unit> wait"  blocks the current thread for specific time
before continuing.

Right. 

Now rearrange it into:

[
    10 seconds wait.
    World defer: [
        Transcript show: 'Hello, World!'.
    ].
] fork.

Into

do: aBlock after: nanoTime
    [
        10 seconds wait.         "<------- you need to say something like nanoTime asNanoSeconds wait. But careful as Delay works up to milliseconds I think, so 5 asNanoseconds asSeconds will just be zero"
        World defer: aBlock.  "<-- OK, World is a WorldMorph, wich extends PasteUpMorph, the old World class in Pharo 3.x"
    ] fork.

I guess that all of this shows that there is some flexibility in Pharo async.

Check the Generator class for some brain twisting with fork.

Run 

Generator examplePrimes. 

for a start.

Phil 


--
View this message in context: http://forum.world.st/Intro-to-Microsoft-COM-for-Smalltalkers-tp4917738p4917913.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.



Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

philippeback
Also, check 

MorphicUIManager>>#spawnNewProcess

UIProcess := [
[World doOneCycle.  Processor yield.  false] whileFalse: [].
] newProcess priority: Processor userSchedulingPriority.
UIProcess name: 'Morphic UI Process'.
UIProcess resume

digging into doOneCycle, you'll find:

#doOneCycleFor: aWorld
"Do one cycle of the interaction loop. This method is called repeatedly when the world is running. This is a moderately private method; a better alternative is usually either to wait for events or to check the state of things from #step methods."

self interCyclePause: MinCycleLapse.
self doOneCycleNowFor: aWorld.


The interCyclePause is what make the UI timing alignment proper (notice serverMode) [and some Squeak remnant mention]:

interCyclePause: milliSecs
"delay enough that the previous cycle plus the amount of delay will equal milliSecs.  If the cycle is already expensive, then no delay occurs.  However, if the system is idly waiting for interaction from the user, the method will delay for a proportionally long time and cause the overall CPU usage of Squeak to be low.
If self serverMode returns true then, always do a complete delay of 50ms, independant of my argument. This prevents the freezing problem described in Mantis #6581"

| wait wait2 |
        "a very long assignment"
wait := self serverMode
    ifTrue: [ 50 ]
    ifFalse: 
[ wait2 := (lastCycleTime notNil and: [CanSurrenderToOS ~~ false]) 
        ifFalse: [ 0 ]
        ifTrue: [ lastCycleTime + milliSecs - Time millisecondClockValue ].
 
      self flag: 'Issue 14754 - wait2>millisecs is only True for clock rollover. Remove it once DelayScheduler based on microsecondClock - Ben Coman 19.01.2015'.  "<---- maybe we want this #flag: not to be called all the time "
      wait2 > milliSecs 
        ifTrue: [ 0 ]
        ifFalse: [ wait2 ]. 
].
wait > 0 ifTrue: [ (Delay forMilliseconds: wait) wait ].   "<------- wait is not #>>wait"

lastCycleTime := Time millisecondClockValue.
CanSurrenderToOS := true.

Now, yeah, how do get stuff to be painted on the  screen?

Like this:

displayWorld: aWorld submorphs: submorphs
"Update this world's display."

| deferredUpdateMode handsToDraw allDamage |

submorphs do: [:m | m fullBounds].  "force re-layout if needed"
self checkIfUpdateNeeded ifFalse: [^ self].  "display is already up-to-date"

deferredUpdateMode := self doDeferredUpdatingFor: aWorld.
deferredUpdateMode ifFalse: [self assuredCanvas].
canvas roundCornersOf: aWorld during:[ | worldDamageRects handDamageRects |
worldDamageRects := self drawWorld: aWorld submorphs: submorphs invalidAreasOn: canvas.  "repair world's damage on canvas"
"self handsDo:[:h| h noticeDamageRects: worldDamageRects]."
handsToDraw := self selectHandsToDrawForDamage: worldDamageRects.
handDamageRects := handsToDraw collect: [:h | h savePatchFrom: canvas].
allDamage := worldDamageRects, handDamageRects.

handsToDraw reverseDo: [:h | canvas fullDrawMorph: h].  "draw hands onto world canvas"
].
"*make this true to flash damaged areas for testing*"
self class debugShowDamage ifTrue: [aWorld flashRects: allDamage color: Color black].

canvas finish.
"quickly copy altered rects of canvas to Display:"
deferredUpdateMode
ifTrue: [self forceDamageToScreen: allDamage]
ifFalse: [canvas showAt: aWorld viewBox origin invalidRects: allDamage].
handsToDraw do: [:h | h restoreSavedPatchOn: canvas].  "restore world canvas under hands"
Display deferUpdates: false; forceDisplayUpdate.

The VM will take care of throwing the bits to the display in various ways.
Interesting to look how it is done for Windows, OSX, and Linux.

So you have about a full view now.

Timing wise, there is also some interaction with the VM occuring elsewhere.
Pharo is still polling deep inside.  epoll etc isn't there yet, hence the little idle CPU usage when doing nothing.

Good luck doing this UI trip with other platforms, not to mention change or instrument it the way you like.

Pharo is really cool for this as it helps in learning about a lot of things.

Want to do sockets? 
Do the high level stuff in Pharo and dig in the VM to see how it is done down under for a set of platforms.

Enjoy.

Phil

On Mon, Oct 3, 2016 at 8:02 PM, [hidden email] <[hidden email]> wrote:


On Mon, Oct 3, 2016 at 6:47 PM, CodeDmitry <[hidden email]> wrote:
LOL (in GrowlMorph):
is: rect saneWithRespectTo: morphs

        ^(morphs anySatisfy: [ :morph | morph owner isNotNil and: [morph bounds
intersects: rect]]) not

for some reason I find this method name quite amusing :3

There are interesting things in there indeed. "Intention revealing" enough? 


Let me guess;

1. "World defer: aBlock." defers the event to be called as soon as
possible(not necessarily now).

Actually this works for any Morph in 5.0

Morph>>#defer: aValuable
"aValuable will be executed in the next UI rendering cycle"
self owner 
ifNotNil: [ self owner defer: aValuable] 
ifNil: [ UIManager default defer: aValuable ]

UIManager (MorphicUIManager) will do this at one point (track implementers 'til class side in WorldState)

defer: aValuable
"aValuable will be executed in the next UI rendering cycle"
self addDeferredUIMessage: aValuable.

This will stick it in a queue:

deferredUIMessages

^DeferredUIMessages ifNil: [DeferredUIMessages := WaitfreeQueue  new].

and then, there is interesting black magic going on 

runStepMethodsIn: aWorld
"Perform periodic activity inbetween event cycles"
| queue nextInQueue|
"If available dispatch some deferred UI Message"
queue := self class deferredUIMessages.

[(nextInQueue := queue nextOrNil) isNil]            "<<---------------- here all is happening -------"
whileFalse: [ nextInQueue value].

self runLocalStepMethodsIn: aWorld.                 "<<------------ step methods -----------------"

"The multi-threaded global Transcript needs to be updated periodically and synchronously with the UI."
Transcript stepGlobal.                                        "<<------------ and *this* is some black magic for Transcript ----"


Fun thing:

stepGlobal
" The superclass method Model>>step indicates a convention that might be used to interoperate 
synchronously with the UI-thread.  However when multiple Transcript windows are open, their 
PluggableTextMorphs share a single instance, from the global Transcript.  To avoid potential trouble, 
this method should not be named #step.  
As well, we need this method to execute even when no Transcript windows are open, so the stream 
continues to be reset periodically, otherwise it would grow indefinitely. So this method is invoked 
from WorldState>>runStepMethodsIn:. 
"

"Next three lines required temporarily to initialize instance variables added to existing instance"
deferredClear ifNil: [ deferredClear := false ].
deferredEndEntry ifNil: [ deferredEndEntry := false ].
stepContents ifNil: [ stepContents := '' ].
deferredClear ifTrue: 
[ deferredClear := false.  
stepContents := ''.
self changed: #clearText.
].
deferredEndEntry ifTrue: 
[ deferredEndEntry := false.  
self critical: 
[ stepContents := stream contents.
stream resetContents.
].
self changed: #appendEntry.
].

Just in case one was wondering how Transcript clear actually works, check this:

clear 
" Clear all characters by resetting the stream and voiding any previously flagged deferredEndEntry.
Redisplays the view by signalling for #step to send #changed: .
"
self 
critical: [ 
deferredClear := true.             "<------- magic! -------"
deferredEndEntry := false.     "<------- more magic!--------"
stream reset ]


Good luck to infer that from scratch.



  
2. "[Block] fork" is called immediatly, but on a new thread.

Yeah, use forkNamed: aString if you actually want to track the thing easily in the Process Browser.

 
3. "<number> <time unit> wait"  blocks the current thread for specific time
before continuing.

Right. 

Now rearrange it into:

[
    10 seconds wait.
    World defer: [
        Transcript show: 'Hello, World!'.
    ].
] fork.

Into

do: aBlock after: nanoTime
    [
        10 seconds wait.         "<------- you need to say something like nanoTime asNanoSeconds wait. But careful as Delay works up to milliseconds I think, so 5 asNanoseconds asSeconds will just be zero"
        World defer: aBlock.  "<-- OK, World is a WorldMorph, wich extends PasteUpMorph, the old World class in Pharo 3.x"
    ] fork.

I guess that all of this shows that there is some flexibility in Pharo async.

Check the Generator class for some brain twisting with fork.

Run 

Generator examplePrimes. 

for a start.

Phil 


--
View this message in context: http://forum.world.st/Intro-to-Microsoft-COM-for-Smalltalkers-tp4917738p4917913.html
Sent from the Pharo Smalltalk Users mailing list archive at Nabble.com.




Reply | Threaded
Open this post in threaded view
|

Re: Intro to Microsoft COM for Smalltalkers

CodeDmitry
This post was updated on .
In reply to this post by philippeback
CONTENTS DELETED
The author has deleted this message.
123