Note: Switched this page to read-only, due to massive spamming. Please mail email@example.com if you want to edit the page.
What do you want to see in Alice? And why don't we implement it today?
Do you simply mean (a) extra syntactic support a la Haskell's do notation? Or do you propose (b) making Alice ML a pure language with monadic IO and state?
We have thought about the former, but it isn't obvious how to make it nice without type classes providing overloading. Answer (b) would result in a completely different language, so although interesting, certainly is not on the agenda for Alice ML.
Preconditions and postconditions on functions (arbitrary boolean expressions).
A failed precondition should raise an exception in the caller (since it didn't provide the right parameters to the function), a failed postcondition should raise an exception in the callee.
Some assertions would be checkable at compile time, others at run time, others not at all.
The assertion language might need primitives that aren't part of the normal language. Primitives that test for various relationships between types come to mind (type equality, sub-type property). Another, less obvious kind of postcondition would be big-Oh complexities on space or time usage.
Assertions should go not only on functions but also on ADTs.
There are additional places where assertions would be helpful, but preconditions and postconditions have additional benefits besides being bug probes:
Assertions give programmers an extremely concise way to document important limitations of their functions. (For this reason, even uncheckable assertions have a lot of value.)
They also improve quality: a function that is "dirty", i.e. works only in a rather narrow and irregular part of parameter space, needs a large precondition to describe the parameter space where it is valid.
One of the incentives of dirty programming is having to write less code (i.e. cutting corners); however, if shortening the function's body means lengthening the list of preconditions, dirty programming becomes less attractive.
A precondition transfers responsibility for a failure to the caller. This makes writing preconditions attractive, so they get indeed written.
Postconditions are irrelevant for most functions (the function's body is also its postconditions).
However, for code that has degrees of freedom in its implementation (e.g. tree implementations), postconditions can distinguish important properties (such as the tree being sorted) from unimportant ones (whether it's a red-black tree, a B* tree, or some other kind of tree).
List comprehensions we could do if enough users consider them desirable.
An optional object-oriented layer
Objects won't happen. Experience with Ocaml suggests that they are of limited use in an ML-like language, but produce a lot of complexity and conceptual duplication. Moreover, SML already has lightweight records, and Alice ML has packages.
Our alternative take is to introduce (statically typed) first-class modules sooner or later, as a complement to the (dynamically typed) packages. They more or less subsume objects, but integrate much better with the existing language.
While the VM supports finalization, it is not yet available to the user. A possible approach might be to introduce a type
type 'a finalized
for finalized objects of type 'a. This comes with two operations (probably all living in the Store module:
val finalized : ('a -> unit) -> 'a -> 'a finalized val object : 'a finalized -> 'a
A value of type t finalized is finalized - when it becomes garbage, the finalization function is applied to the wrapped object in a fresh thread.
Note that the finalization function may revive the wrapped object of type t (e.g. by storing it in some global reference), but not the finalized object, because it has no reference to it. Hence, for every object of type 'a finalized, the respective finalization function is called at most once. However, the finalization function can easily construct a new finalized object, if a finalizer shall again be attached to the revived object.
Clearly, this scheme provides no automatic guarantee that the wrapped object does not outlive its finalization wrapper. The idea is that finalization types are hidden via type abstraction, so that clients cannot extract the object and have live references to it independent of the wrapper. As long as the implementation of the abstraction handles the object suitably, it won't outlive its wrapper.
This scheme would probably be easy enough to implement, but unless there really is demand for it we are too lazy to do it :-).
-- Andreas Rossberg
The problem with the C++ model and RAII is that it only "works" because C++ is a severely limited and unsafe language ;-). In a higher-order language with proper lexical closure going out of scope by no means implies "ref-count of zero". Actually, this is not even true in C++, thanks to pointers, but C++ pretends anyway and will just bless you with dangling pointers in case you get jaunty. Obviously, you cannot afford that in a safe language.
I'm afraid that the only safe way to detect a ref-count of zero is by garbage collection - after all, that's the very purpose of garbage collection. Hence finalization can only be triggered safely by the garbage collector (obviously, allowing the programmer to call destructors explicitly is not safe either). Of course, that implies that finalization is not the right tool for certain tasks, but that is indeed well-known (and one reason why we are not in a hurry to provide it). In cases where it is not you can, however, resort to higher-order abstractions that free resources immediately after use.
-- Andreas 2006-05-30
[deleted old text that is superseded by explanation.] (JonS: thank you for the explanation, I understand what is going on now. I guess in the end it would be nice to have some "standard" pattern like "using/dispose" in C# rather than what I see in Java where everybody has a different way of doing the same thing. http://www.bobcongdon.net/blog/2006/02/using-using.html)
Pickling with Transformations
We need a way to create values which do not get pickled. I'm thinking of something like this
signature TRANSIENT = sig type 'a transient val transient : 'a -> 'a transient type 'a status = ALIVE of 'a | DEAD val status : 'a transient -> 'a status (* and maybe some convenient access functions *) exception Dead val valOf : 'a transient -> 'a (* Dead *) exception Alive val revive : 'a transient -> 'a -> unit (* Alive *) (* not absolutely necessary but otherwise one would almost always need an reference *) end
Of course some builtin magic similar to futures would be nice but I believe that's too much a change of the language for something which probably will not be used by the average alice programmer.
Rationale: (Why does one need transients?) To be able to write code which caches recomputable but probably very big structures without worrying about the size of the whole thing when transmitted or stored.
-- Benedikt Grundmann
Here is a slightly simpler and more regular interface (I also avoid the Java-esque terminology "transient" because that means something completely different in the Alice world):
structure Cache : sig type 'a cache val cache : unit -> 'a cache val fill : 'a cache * 'a -> unit val clear : 'a cache -> unit val content : 'a cache -> 'a option end
That is, a cache is essentially like a ref that may be empty and is always pickled as empty.
However, this is just a special case of a more general idea: an abstraction for creating types whose representation gets transformed in a user-defined way upon pickling/unpickling. Here is a possible interface:
functor MkTransform ( type internal type external val externalize : internal -> external val internalize : external -> internal ) : sig type trans val trans : internal -> trans val rep : trans -> internal end
This abstraction corresponds to a mechanism available in the SEAM pickling machinery anyway, and could easily express (monomorphic) caches. By making all signature types polymorphic, it could also support polymorphic transform types.
(Obsolete) Neither mechanism is implementable on top of the Mozart VM.
The exact semantics of the transform approach aren't obvious. In particular, how does the unpickler get access to the internalize functions? There seem to be 2 possibilities:
Transform values carry the in/ex functions.
Advantage: Pickles are still closed, and in/ex functions are always used consistently.
Problems: Precludes transformations accessing resources, which is pretty restrictive (but secure). Moreover, pickled functions may get larger than the space saved by using the abstraction.
Functor registers in/ex functions with the pickler under the name of the generated type. Values only carry that name.
Advantage: External representation is small, and transformations are not restricted.
Problems: (1) Unpickling can fail spuriously because of an unknown transform type (which may not even occur in the pickle's signature, a value in some closure suffices). (2) Would require applicative functors, which are not supported currently (otherwise there would be no way to share generated transform types between different sites, as soon as they actually have resourceful transformations; alternatively, we would have to give up any static guarantee that in/ex functions are consistent). (3) By exploiting resourceful transformation types, pickles can breach security.
-- Andreas Rossberg 2003-02-21 15:36:59, update 2006-05-17
A parse function operating on strings (not just over files)
Has been made available in Alice 1.2.
Alternative GUI toolkits
FLTK: A better GUI toolkit for Alice
Only because it is cross-platform and wicked fast. They are also doing OS-native themes in version 2 so you get apps that look native, not GTK-ish. Currently supports Win/Linux/Mac OS X and some OS/2 work underway. The license is modified LGPL which is more permissive than GTK+ LGPL, i.e., it permits static linkage and widget subclassing.
Quick answer: Any Toolkit that buys in so deeply into C++ features is practically doomed to be unusable for foreign language bindings. This also precludes wxWindows. It's not a coincidence that Gtk has become the most widely used GUI binding, since its designers conciously decided to create a plain C API for that very reason.
-- Andreas Rossberg 2003-02-21 15:39:34
The elj project ( http://elj.sf.net) has written a c wrapper of wxWindows as part of their wxEiffel library. This wrapper is also already used to create a haskell binding to wxWindows and could probably be used to create an Alice wrapper.
-- Benedikt Grundmann
Quick reply: I don't buy that, e.g. wxWindows has been interfaced to Perl, Python, etc. as has FLTK. And if you look at the Boost Python Library, it makes practically seamless interfaces between Python and C++. These things can be done even without SWIG, though SWIG is nice too, and even supports OCaml. I view GTK's C-ness as a weakness, let alone its lack of cross-platform support, its ugly looks, and its pure LGPL license.
Another toolkit is FOX ( http://www.fox-toolkit.org). Very fast, small and a very clever event handling system. I personally believe it's a lot better than FLTK and GTK. And I've already written small apps in all of these toolkits. Disadvantage uses C++ but it does so in a very conservative way and interfaces to Ruby, Python and Eiffel have been written. So it can be done.
-- Benedikt Grundmann
That very clever event handling system is why I stopped using FOX and moved over to FLTK and other kits. FOX drove me crazy. The drawing code is good, but FOX doesn't run on Macs, and the event model is _very_ bad news despite the copious advertising. Just forget about FOX 'targets' -- as soon as you use them, you are in for trouble, because the targets get messages you don't want them to get, and intercept messages you want propagated elsewhere. I found targets totally useless and was constantly fiddling with those event macro tables just like ugly old MFC.
I would like to throw in a vote for reviving the debugger. While I am very much enamoured with Alice ML and all it has to offer, my software engineering experience - such as it is - has led me to promise myself I would never use a system that lacks a debugger. -JonS.
Errors and Warnings
ML RISC Native Machine Code Back-end
"MLRISC is a customizable optimizing back-end written in Standard ML and has been successfully retargeted to multiple architectures. MLRISC deals elegantly with the special requirements imposed by the execution model of different high-level, typed languages, by allowing many components of the system to be customized to fit the source language semantics and runtime system requirements."
Lal George and Allen Leung are also on the SML/NJ development team. The spirit of MLRISC is similar to the Alice SEAM virtual machine project. It would be nice to see Alice compiled with ML RISC. That would buy Alice multiple processors for free.
We are, of course, aware of ML RISC, which definitely is nice work. However, as far as native code is concerned, Alice is based completely on just-in-time compilation, due to its platform independence philosophy. From what we can see, the ML RISC framework is not particularly suitable in this setting. Jitting requires a lean and fast code generator, rather than sophisticated optimizations.
-- Andreas Rossberg
Thank you Andreas, I did not know about the JIT aspect, just the VM. This is still the 'wish list' section, not 'wishes denied,' I hope. Perhaps one day Alice will offer both options, like O'Caml. Platform independence is well supported by MLRISC - more so than JIT techniques. (MLRISC accepts new targets as configuration files.) Native compilation would make Alice more attractive. Still, even without it, Alice is beautiful. Thank you for the excellent work.
I'd like to see support for OS X!
There is a Mozart package for OS X. To use Alice with it, you can use the binary tarball for Linux (see the Alice download page) and unpack it somewhere. Since components are platform independent it should work for OS X almost out of the box. The only thing you might need to adapt is the path to Mozart in bin/alicerun. Please let us know if you encounter problems.
Once the SEAM VM is stable enough we plan to have regular OS X packages.
-- Andreas Rossberg
Andreas, I unpacked the Unix tarball and as you said it works right away on OS X (10.3), as long as OZHOME is set and $OZHOME/bin is in the path. The inspector is nice on OS X, it even has native Aqua widgets, thanks to the native gtk port in Oz I suppose. Thanks for the help and the great work.
- Steve Harris
Runtime system : Debian testing
I'd like to be able to install something current on Debian testing. I've got Alice-Mozart (0.9) installed, but the more recent versions require a version of libgmp3 that isn't installable on my system. I've tried compiling from source, but that didn't succeed for the same reason. Thanks.
- Charles Hixson
A printable version of the manual would be nice to have. Unfortunately I still find reading black marks on dead trees to be the best way to acquire broad understanding of a language and its libraries.
- Carl H
Printable documentation really is a must. You've got the raw material. Transforming it into a good looking pdf or ps file would be exceptionally helpful.
- Reilly Hayes
It would be great if the windows remembered their last position and size, so I don't have to move and resize them every time I fire up Alice.
when I resize it to be shorter, the split bar can get lost.
I'd like the Inspect window to be available as part of the IDE window, rather than having to always be separate.
On my machine, when the input 'frame' is full, the text will wiggle and dance strangely as i type characters into the bottom line.
- Jon S.
I agree it would be nice to have the Inspector inside. Unfortunately, the Inspector was written before the Toplevel GUI, and hence would require significant work to retrofit into there. Moreover, the Inspector should still be usable independent from the Toplevel, e.g. as a debugging aid, so we'd need two versions (unfortunately, Gtk does not support something like docking and undocking windows).
The text wiggling I cannot reproduce and I am not sure what you mean by it. I see some color flashing whenever you insert something at the end of a buffer, is that it? This annoys me quite a bit myself, but after some tracing I came to the conclusion that it actually is a Gtk problem that I have no idea how to work around.
Size and position should be easy enough.
Thank you for the explanation! I can totally see Gtk being the culprit.
- Jon S.
Would it be possible to simplify the FFI? I am thinking in particular of Python ctypes ( http://python.net/crew/theller/ctypes/ ) or even some Common Lisp FFI implementations which do not require the user to write code in a foreign language. This would make interfacing with libraries such as OpenSSL a breeze.
That would certainly be nice. Incidentally, the Gtk binding to Alice actually uses a modified version of the Python meta description to generate most of its code. However, we found that the original format did not contain enough information for a typed language, so we had to amend it in ad-hoc ways. I am not sure how well this would scale to other forms of foreign bindings.