Essence# was released to the public almost 2 months ago. Since that time, the following features and capabilities have been added: Exceptions, Collections, Traits, Announcements and .Net Events, passing blocks as parameters to .Net methods where the corresponding parameter is a .Net delegate, and defining Essence# classes that represent .Net generic type definitions.
And now the ‘Acts’ release of Essence# introduces support for Threads, (asynchronous) Tasks, Semaphores, Monitors and Mutexes, the ability to call .Net methods that use “out” or “ref” parameters, the ability to convert Essence# arrays into .Net arrays (with any .Net type as the element type,) the ability to create such arrays, and the ability to construct closed generic types from open generic type definitions, and create instances of those types. And it fixes various bugs.
The Acts release can be downloaded from the Essence# site on CodePlex (which gets you the installer.) Alternatively, the code for the run time system (written in C#) can be obtained from theEssence# CodePlex site using Git, and the code for the Essence# Standard Library can be obtained from GitHub. And the example scripts can also be downloaded from the Scripts repository on GitHub.
The Essence# Development Plan
Before getting into the details of the new features and capabilities introduced in this release, I should explain the overall development plan:
The highest priority goes to making the compiler and the run time system work correctly. The next priority is adding whatever features to the compiler and/or the run-time system may be required to a) have a fully-functional programming language that conforms to the ANSI Smalltalk standard to the extent that that’s possible on .Net, and b) to enable the maximal degree of interoperability with .Net that is possible without compromising support for the language’s conformance to the ANSI Smalltalk standard. Next to lowest priority is adding whatever classes or methods to the Essence# Standard Library may be required in order to conform to the ANSI Smalltalk standard. And everything and anything else has the lowest priority.
Essence# will stay in alpha until both the language and the standard class library provide full ANSI Smalltalk compatibility, to the extent that that’s possible on .Net. It will remain in beta until Essence# code a) can be compiled to .DLLs and .EXEs, and b) can be debugged using the Visual Studio debugger. The second requirement depends on the first–debugging with Visual Studio is simply not possible using the type of (CLR) methods that the Essence# compiler currently generates (which .Net calls “dynamic methods.”)
Typically, when support for new feature domains is added to Essence# (e.g, exceptions, collections, events, threads, files/streams, etc.,) the first step will be releasing Essence# classes that simply wrap the native .Net classes for that feature domain. In some cases, nothing more will be needed. But in most cases, in order to provide ANSI Smalltalk conformance, it will be necessary (in later releases) to add more classes and methods to the Essence# Standard Library that provide an ANSI Smalltalk facade over the native .Net classes.
Completing the task of adding Essence# classes that wrap (directly represent) the native .Net classes that are needed to complete the planned feature set of the Esssence# Standard Library has priority over implementing Essence# classes that adapt those classes so that they provide an API that conforms to the ANSI Smalltalk standard. That’s why this release does only the former, and not the latter (with some minor exceptions.) It’s also why the same will be true for the next major feature domain: Streams and files.
Using the Essence# Concurrency Classes
This release implements Essence# classes that represent (“wrap”) many of the core .Net classes for multitasking and concurrency that are defined in the .Net System.Threading namespace, such as Thread, Monitor, WaitHandle, EventWaitHandle, SemaphoreSlim, Mutex, SpinLock, SpinWait, ReaderWriterLockSlim and ThreadPool. It also implements Essence# classes that represent (“wrap”) many of the classes defined in the .Net System.Threading.Tasks namespace, such as Task, TaskScheduler and Parallel.
The new classes reside in the Essence# Standard Library in the namespaces CLR.System.Threading and CLR.System.Threading.Tasks. In a few cases, the Essence# class name is not the same as the .Net class name. Examples: CLR.System.Threading.Semaphore -> System.Threading.SemaphoreSlim, CLR.System.Threading.ReaderWriterLock -> System.Threading.ReaderWriterLockSlim.
Note that these new classes are not defined–and therefore not visible–in the default system namespace (“Smalltalk.”)
Also note that, in some cases, the new classes represent (“wrap”) .Net generic type definitions (“open generic types,”) which means one cannot create instances of such types. To create instances, it is first necessary to construct a “closed generic type” by supplying a generic type argument that corresponds to each of the generic type parameters of the generic type definition. This version of the Essence# Standard Library also includes Essence# classes that do just that for the .Net classes Task`1 (“Task<>” using C# syntax), TaskCompletionSource`1 (“TaskCompletionSource<>” using C# syntax) and ThreadLocal`1 (“ThreadLocal<>” using C# syntax.) Those classes wrap generic types that are constructed by supplying System.Object as the generic type argument to the base generic type definition. They reside in the namespace Smalltalk.Multitasking, and are named Smalltalk.Multitasking.Task (which represents the .Net type Task<System.Object>), Smalltalk.Multitasking.TaskCompletionSource (which represents the .Net type TaskCompletionSource<System.Object>) and Smalltalk.Multitasking.ThreadLocal (which represents the .Net type ThreadLocal<System.Object>).
You should also know that an Essence# class that represents any closed generic type inherits from the Essence# class that represents the corresponding open generic type definition. So the class Smalltalk.Set–which represents the .Net type System.Collections.Generic.HashSet<Object>)–inherits from the Essence# class that represents the .Net type System.Collections.Generic.HashSet<>, and Smalltalk.Multitasking.Task inherits from the Essence# class that represents the .Net type System.Threading.Tasks.Task<> (using C# syntax for the type names.)
If you browse the Essence# code that implements the new classes, what you won’t see is an Essence# method that corresponds to every method and property of the corresponding .Net type. They are there nonetheless, and you can call them in spite of the fact that you don’t see the method definitions in the Essence# code. And that’s true of any and all Essence# classes that represent (“wrap”) a .Net type. If the .Net type represented by an Essence# class has a property or method named “Start,” you can invoke the method or get the value of the property by sending the message #start (or #Start, if you prefer) to an instance of the .Net type, even though there is no such method defined in the Essence# code.
Generally, a method will only be defined in Essence# code when the corresponding .Net method requires 2 or more parameters, or when the type has constructors that require any arguments. Normally, methods in Essence# code only need to be explicitly defined to access a .Net property, or to invoke a .Net method with less than 2 parameters, when it is desired to use a different name for the Essence# message than the one defined by .Net (perhaps because the message selector traditionally used in Smalltalk for the operation with the same semantics is different.)
However, if the class is a native Essence# class which does not “wrap” a .Net type, then almost all methods not inlined by the compiler (or not added dynamically by sending a message such as #addMethod: to the class) must be explicitly defined, with a very small number of exceptions (currently, those would be #doesNotUnderstand:, #ensure:, #ifCurtailed: and #on:do:). The compiler inlines many of the same messages as would be the case in other Smalltalk implementations.
You can print out a list of all the methods defined by an Essence# class (including those that come from traits, or are inherited from its superclasses) by using the ES command line program to run code on the command line (e.g, using the Windows CommandPrompt) such as the following, which will print out the names of all the methods of class Array:
Array allSelectorsDo: [:selector | System.Console writeLine: selector]
Example Of Thread Usage
The methods #newProcess, #newProcessAt:, #fork and #forkAt: have been added to class Block as an initial stab at giving blocks standard behavior with respect to threads (“processes.”) Here’s an example of using blocks to start threads, and of using CLR.System.Threading.Semaphore to schedule threads:
| semaphore| semaphore := CLR.System.Threading.Semaphore new. [semaphore wait. System.Console writeLine: 'Thread one reporting'] fork. [System.Console writeLine: 'Thread two reporting'. semaphore signal] fork.
The #fork message creates a Thread from the block that is its receiver, and starts it running. The first thread immediately begins waiting on the semaphore. The second thread writes out a message to the console, and then signals the semaphore, which causes the first thread to stop waiting on the semaphore and write out its own message to the console.
And that’s it for now. I’ll publish more posts over the next week that describe and explain the other new features and capabilities, such as calling .Net methods that require “out” or “ref” parameters.