Idioms and Design Patterns
Using Promises as locks
You can use promises to lock references:
val counter = ref 1 fun incr () = let val p = Promise.promise () val s = Ref.exchange (counter, Promise.future p) in Promise.fulfill (p, s + 1) end val t1 = spawn incr () val t2 = spawn incr () (* wait for both threads to be terminated *) val _ = Future.await t1 val _ = Future.await t2 val _ = assert (!counter == 3)
Note that this is precisely what Ref.modify does. So incr could also be implemented as
fun incr () = Ref.modify (fn i => i+1) counter
But the idiom is still useful in more complex situations.
Common problems and Workarounds
Cannot save anything
I feel pretty stupid asking this but I cannot save files. The menu-entry for doing so is gray. The shortcuts do not work either. I am running Alice 1.4 on Kubuntu 12.04. What am I doing wrong?
- Julian [01.07.2012] Nevermind, I have been using the interpreter and not the editor. Editor opens when you generate a new file, but not when you open Alice. Maybe worth changing if more people have trouble with that?
spawn swallowed my exception!
You have written something like this:
fun f () = raise Fail "my exception" fun foo () = spawn f (); print "thread created" val _ = foo ()
But mysteriously you never actually see that exception.
What happened? As you probably know spawn creates a future. This future becomes failed as soon as the exception is raised. This STOPS the exception, until someone forces the future evaluate. But in this case the future is tossed away by the ; operator and therefore the exception is gone forever.
So there are two possibilities. You must either use the value returned by the thread, or if you are just interested in the exceptions for debugging purposes (such as the Assert exception) use Ctrl.ispawn from "x-alice:/lib/utility/Ctrl":
import structure Ctrl from "x-alice:/lib/utility/Ctrl" fun f () = raise Fail "my exception" fun foo () = Ctrl.ispawn (_file_, _line_) f (); print "thread created" val _ = foo ()
Which will terminate your application with a debugging message whenever an uncaught exception occurs.
But anyway, since the utility lib is not official and may change any time it is currently preferable to use your own version of ispawn. One possible definition is:
fun ispawn label f x = let fun crashWith e = (TextIO.output (TextIO.stdErr, label ^ ": uncaught exception " ^ exnName e ^ "\n"); OS.Process.exit OS.Process.failure) in ignore (spawn f a handle e => crashWith e) end
It is used like:
ispawn "task08_15" f ()
Moving from Oz to Alice
For reference documentation about how the implementation of Resolvers, Component Managers etc. in Alice differs from Mozart, see the Alice Manual.
StacksForAlice: An example for structures and signatures in SML. By Joachim Niehren, 15 Januar 2003.
New Developments in ML
(Sorry, don't know if the Wiki is even the right place to put this)
exceptions perhaps of internal interest?
Thanks for the link. Yes, we are aware of that paper. It surely is interesting, but we did not consider to implement it yet, because for now, we do not want to deviate from SML in (too) incompatible ways.
Is there a way to add some additional information to a failed assertion? somthing like
assert myAssertionExp onFail myAssertionFailedMessage
No, but the Assert exception carries file name and line number of the respective assertion, which should be enough to identify its origin. If really necessary, you could catch it and use this information to map it to a message, but admittedly, that would be a pretty fragile hack.