#2268 Long tutorial on fantom actors

tomcl Mon 21 Apr 2014

I've written a 8 page standalone tutorial on how to use Fantom actors. I found this surprisingly tricky to get right and I'm still not certain that the final section detailing UI interaction using Desktop.callAsync is correct. This section needs to be expanded but I'd appreciate any corrections! If you don't want to wade through 8 pages the final section I'm less confident about (Section 6.3) is only 1/2 page.

Chapter 6 in this document (download PDF from GIT repo): https://github.com/tomcl/fantom-tutorial

SlimerDude Tue 22 Apr 2014

Hi Tom, I've just had a quick skim (it looks good!) and the following minor details caught my eye:

  • The Actor model is not particulary an Erlang construct.
  • In the examples I would probably contract message to msg and not mess!
  • Duration.fromStr("0.1sec") can be written as a Fantom literal --> 100ms
  • In sec 1.3...

    ... interact with the GUI by posting a (const) callback ...

    ...it's actually an immutable callback.

  • The second paragraph in sec 1.3 could probably be simplifed by saying (something like) all callbacks running in the UI thread have access to mutable state held in Actor.locals().

tomcl Tue 22 Apr 2014

Thanks. I'll do this.

I'm a bit confused about immutable. I'd use it to mean guaranteed constant (though in Fantom's case there is an escape hatch of course via unsafe or Actor.locals).

But there is also its use to mean something that can be made immutable by copying (as a List). I don't like this usage much.

I think I need to explain this - when I understand it.

So my best guess now is: messages must be (modulo trapdoor) immutsble = constant, but not compile-time constant since can be created dynamically with toImmutable.

The other thing I'm still confused about is Actor.locals. I thought I understood it was actor-local but two things confuse:

(1) the Desktop.callAync callback executed as part of the UI, not on the thread of the actor that called it - it has the status of a message so the event queue behaves like an actor queue, yet it has access to Actor.locals entries written in the actor constructor. I don't understand the precise semantics here. Which entries are visible to which threads? Can entries written in the actor after construction be shared with the UI? If so why? Is this specific to the thread in which an actor is created? In that case would two different actors created in the same thread share Actor.locals?

(2) More generally what is the visibility of actor.locals entries. What happens if there are name clashed.

Basically I need a much more prcise semantics of this construct than is given in the standard doc. Or maybe I'm just not understanding something obvious...

SlimerDude Tue 22 Apr 2014

See the Func doc for the definition of an immutable func.

yet it has access to ... entries written in the actor constructor.

Yep. That's because const objects are, by definition, thread safe. So all immutable functions can access fields and methods on const objects.

What happens if there are name clashed.

The entry gets overwritten. Actor.locals is just a plain Map afterall. That's why I wrote ThreadStash:

A wrapper around Actor.locals ensuring a unique namespace per instance. this means you don't have to worry about name clashes.

brian Tue 22 Apr 2014

This is excellent write-up (especially considering you were new to the topic!)

I agree with @slimerdude's comments

The Desktop.callAsync doesn't really have anything to do with Actor's per se. That is a construct to work with the SWT toolkit which requires everything UI related to be single threaded. But since you need to deal with the issue safely in Fantom, we use the same rules/techniques in that API as we do concurrent APIs.

I'm a bit confused about immutable. I'd use it to mean guaranteed constant (though in Fantom's case there is an escape hatch of course via unsafe or Actor.locals).

Immutable is used specifically to mean that the object can't be changed. Object of a const classes are one type of immutable objects. But there are others (such as result of List.toImmutable, etc). So think of const class objects as a subset of what defines immutable objects.

More generally what is the visibility of actor.locals entries. What happens if there are name clashed.

As @slimerdude says, its just a simple name/value map. It is basically (and implemented as such) as nothing more than a java ThreadLocal - if you look at the Java code:

public static Map locals() { return (Map)locals.get(); }
private static final ThreadLocal locals = new ThreadLocal()
{
  protected Object initialValue()
  {
    return new Map(Sys.StrType, Sys.ObjType.toNullable());
  }
};

tomcl Wed 23 Apr 2014

OK - so let me try to summarise, please correct me if wrong!

As I work through the semantics here I realise there are a number of issues I still am not certain about.

The issue is that we have actors, Java threads, and physical resources on which threads can run.

The Java thread to physical resource mapping is as in java - I won't worry.

The actor instance to Java thread mapping is what concerns me.

Actor.locals comprises a actor-instance-unique set of Maps.

Every actor instance is bound to a unique Java thread which may or may not swap physical resources (CPUs) when executing.

A given actor instance is guaranteed always to stay on the same Java thread. Is this true?

At actor instance creation time the ActorPool decides (arbitrarily) which thread to bind an actor instance to. Actors therefore share a thread with some number of other actors when the number of alive actor instances exceeds the number of ActorPool threads. This cannot be changed, so worst case many actors might be forced to run on a single thread when all other hardware resources are idle. However Java threads can be guaranteed to carry at most one actor instance if number of ActorPool threads > number of actor instances alive at any time. Is this true?.

At actor creation time the new actor instance is bound to a Java thread probably different from the creating thread. Its Actor.locals Map is however always new and so a given Java thread may carry more than one Actor.locals.

In the clock example the actor method update must access the Actor.locals Map for its actor thread. So although Actor.locals looks static, in reality any reference to it captures data specific to the actor instance in which the reference is made. The clock update method captures Actor.locals from its actor thread, when passed to Desktop.callAsync and run as a callback under the main thread it still references this Actor.locals. However at actor creation time the UI widget to be operated on was stored there - possible because the actor was created in the UI thread.

In summary: Actor.locals is a guaranteed actor instance-specific field of an actor instance.

I now don't understand name clashes in Actor.locals? (Previously I thought Actor.locals was Java thread specific with actors sharing a thread also sharing Actor.locals Map. But that would introduce a whole load of unnecessary problems).

SlimerDude Wed 23 Apr 2014

Hi Tom, I'm glad you're pushing these questions, for I too have the same uncertainty regarding the relationship between Actor execution and Java threads.

In the end I just trusted Brain to have done the right thing, for everything seems to work as intended! :) Then again, I tend to create a new ActorPool for each Actor so that simplifies things.

A given actor instance is guaranteed always to stay on the same Java thread. Is this true?

Good question! Something I was never sure about, but it seems to be the case.

At actor instance creation time...

Yep, that paragraph sounds correct.

...a given Java thread may carry more than one Actor.locals.

A concern of mine also, but I'm not sure. To avoid cross Actor contamination, I would hope Actor.locals() is tied to the Actor instance and not the Java thread... but given Actor.locals() is just a ThreadLocal it looks like it might not be...?

Actor.locals is a guaranteed actor instance-specific field of an actor instance.

Fingers crossed, yes!

brian Wed 23 Apr 2014

Think of an Actor as only a unit of work guaranteed to process messages serially. Actors are scheduled onto thread pools and given time slices to process up to 100 messages before yielding the thread to another actor in the pool.

The Actor.locals is not just an ThreadLocal - its travels with the actor (along with Locale.cur) as its assigned to a thread for message processing. See the first two lines in Actor.java _work().

I would suggest if you really want to understand how actors map to Java you read the source code for Actor.java. Its only 300 lines of code. It works in conjunction with Scheduler.java and ThreadPool.java - the entire framework is less than a 1000 lines of code to read.

SlimerDude Wed 23 Apr 2014

See the first two lines in Actor.java _work().

Ah, the missing link! Cheers. When poking around this morning, I was too focused on ThreadPool.java and ActorPool.java.

tomcl Wed 23 Apr 2014

Great!

So - having looked at actor.java....

(and BTW I don't really think this is a good way to document the Actor class semantics, though obviously it is accurate!)

Actor instances carry guaranteed private copies of Actor.locals hash. This together with locale info is stored in a context object that holds the actor instance and its private data. Note that Actor.locals is constant (though its contents are not) whereas the locale info is read/write in the context and can be mutated by the actor.

Actor instances are scheduled onto Java threads (with a copy of their private context) for a time slice of 1 - 100 messages - terminating when there are no more messages to process. Note that this scheduling has message granularity.

Conflict between actor instances for keys in Actors.local cannot exist. There is something in the standard documentation (http://fantom.org/doc/docLang/Actors.html under Actor Locals) that does not quite make sense to me and perhaps has caused some confusion:

Actor locals is a string/object map which works like a thread local - a unique map is used for every actor. To prevent naming collisions, you should prefix your map keys with your pod name

Thus a unique map is used for every Actor instance and I'm not yet understanding what collision could matter that prefixing a pod name to the key would solve. In fact there don't seem to be any collisions full stop.

So I like actors better now. There is no leaky semantics from the implementation other than that necessary and not harmful. But think they could be documented a bit more, which I will do informally in the above tutorial.

brian Wed 23 Apr 2014

Yes they should definitely have solid documentation outside of the source :) That is why your tutorial will be great.

You are correct that every actor instance has its own copy of the Actor.locals. But in the context of that Actor instance its still effectively a global variable which means that different modules may write values into the map. So what I mean by collisions is that two pods such as alpha and beta shouldn't write a key into the map using something generic like "user" - because they might conflict. It would better to use a key such as "alpha.user" and "beta.user".

That said, in practice I find most actor code is fairly local and doesn't make calls out to libraries. But I think if you are designing a reusable library and are going to stash variables into Actor.locals then you should prefix it with your pod name.

tomcl Wed 23 Apr 2014

Sections 5.3,5.4 are the revised/new actor stuff. I maybe need to go through a modified clock example in some detail as well to make 5.3 make more sense.

http://wikisend.com/download/349498/concurrent.pdf

Learning Fantom so far the things that needed better explanation were:

  • It-blocks - easy when understood - impenetrable when you first see them. A shame because they are for me one of the nicest features of Fantom.
  • Concurrency
  • The exact way that static and dynamic typing is used
  • mixins & (sort of) multiple inheritance. Though these are pretty straightforward.

The type part is still not written...

ahhatem Sun 4 May 2014

Hi tomcl,

I think this is the wrong file...

Thanks for the good work!

tomcl Sun 4 May 2014

Thanks for that. I think Wikisend has a 7 day limit on files and (amazingly) it must recirculate urls so that you can end up with a random other file. I have to say I would not post anything confidential to these free data sharing sites.

I've updated the OP with the latest tutorial, posted I hope on a site without a short time limit.

My problem now is the tools section. It is clear (to me) that F4 is the best IDE for newcomers - and maybe for others - but xored have more or less stopped supporting it.

For anyone actually using Fantom for real work consider this: without an attractive path for casual users to try out the system, with working tools, it is not likely the user community will grow, and without a decent programming ecosystem the language will be less good for all.

Brian & Andy have done an excellent job with the web site and command line tools, and it is great that the language stays stable enough to use. But a capable shrink-wrapped IDE is also needed, as is a bit more in the way of documentation. The problem I found from the language reference is that there was in some areas not quite enough tutorial stuff and as a newbie you had to go hunting all over the web site just to have a solid understanding of the language semantics.

Mengu Thu 8 May 2014

hi @tomcl

what if you created a repository in git -or any other vcs for your taste- for this fantom tutorial and the future tutorials and host them on github -or bitbucket- where they will never cease to exist?

SlimerDude Thu 8 May 2014

Hi Tom,

Yeah, I too was wondering what you had planned to do with your tutorial?

tomcl Thu 8 May 2014

I'm planning to do that. The source is written in lyx (sort of mangled latex) and I'd like it versioned in a way that lyx understands, which I have not yet worked out how to do but I certainly will do so. Once there it can be corrected by others (lyx does provide merge and compare functionality I think).

I'm using lyx because it is more productive than latex and you can't get high quality and consistent handling of structure from word etc without more care than I normally give.

BTW it is now nearly at a stage where all the things I know need to be in it are added - but there are a few place where I need examples and when writing them will maybe self-correct conceptual errors. So probably a few weeks before I do this, unless anyone wants to do a serious correction job in which case I can send lyx source right away.

lyx - free and easy to install - will self-install latex if you need - http://www.lyx.org

tomcl Thu 8 May 2014

It looks like I can do lyx -(standard export)-> latex -(pandoc)-> rst

But then what would I do with the pretty embedded tikz pics?

:)

Here is the lyx source if anyone wants to try... http://www.fileswap.com/dl/9Ew9M7x9Vn/

tomcl Sun 11 May 2014

https://github.com/tomcl/fantom-tutorial

Please use this to read or edit the tutorial!

To edit it you will need to download Lyx (shrink-wrapped with dependencies) and then altering/adding text should be as easy as in a word processor.

Lyx is great - an improvement on latex for those who have never used it, and for those who know it well.

SlimerDude Sun 11 May 2014

Lyx looks to be the structured WYSIWYG editor I've always wanted! (The 200Mb download is a bit steep though!? Wow!)

So..., thinking ahead, does Lyx have any Save as... HTML option?

tomcl Sun 11 May 2014

Remember - Lyx is a front-end for latex and so it will download a tex distribution. The Lyx part is only about 30M on top of that.

Lyx will export to HTML. I checked it out. The Lyx stuff is fine - just a few line breaks around inserted program listings look different but I'm sure that is fixable. It looks fairly well hyperlinked (e.g. from contents).

However I embed Tikz pictures (written in a source language that specifies modes and arrows) in Lyx. These not surprisingly don't get converted.

I think I need to redo these as external Tikz files imported into the Lyx document. Then they can be separately converted to PDFs and probably will export to HTML better.

There is a Tex package to do this - at the moment I'm using the built-in Lyx way of handling the tikz stuff.

I also need to rejig the examples so they are real Fantom files in a source directory separate from the main document. That will mean they can be edited and compiled and picked up automatically in the edited form.

Finally it seems Lyx does not understand git 1.8 - that does not matter except that I'd like to version the document with the git version info.

Login or Signup to reply.