Eagle: Re-implementing Tcl in C#

MC's notes on Joe Mistachkin's Tcl2008 talk regarding his re-implementation of Tcl in C#.

JJM -- The full paper and slides will also be available (soon) from the project web site. Also see Eagle

(I missed the first slide...)

Notable features:

  • Integrates with Common Language Runtime (CLR), Tcl/Tk, native libraries
  • NEW: Now runs on Mono 2.0 (not all features are 100% supported)
  • Supports interactive debugging, script cancellation; read-only variables, commands; interpreter-wide variable tracing; closures; Unicode (UCS-2)

Missing:

  • No Tk commands
  • No argument expansion syntax
  • No namespace support (UPDATE: Tcl 8.4 compliant namespace support available as of Beta 30, in mid-April 2014)
  • No binary, fblocked, fileevent, glob, history, memory, or trace commands (UPDATE: glob available as of Beta 31).
  • No registry or DDE commands
  • No asynchronous input/output
  • No http, msgcat, or tcltest packages (minimal subset of tcltest is now supported)
  • For the open command, command pipelines and serial ports are not supported
  • For the exec command, Unix-style input/output redirection and command pipelines are not supported

Compiles with Visual Studio 2005 or higher and/or .NET Framework 2.0 RTM or higher compiler. Ran a demo eagle console. "#show" special command to show output helpful for debugging

 % set x [object create -alias System.Int32]
 System#Int32#216
 % $x ToString
 0

Eagle, being managed code, has access to all the .NET Framework. Joe ran a demo that used .NET calls to instantiate a Windows form.

Within Eagle: [tcl find] finds installed versions of Tcl. [tcl load] can load them. Eagle can load Tcl via a .dll; then package require Tk. Thus Tk and WinForms can be mixed. Xaml forms (i.e. WPF) may also be used. WinForms event bindings are handled in a similar fashion to Tk.

Calling foreign functions:

 set z [library declare -functionname GetUserNameA -returntype Boolean -paramatertypes [list intptr uint32&] -charset ansi -module ...]

Eagle takes a different approach to some things than Tcl. Semantically compatible at the script level. Radically different underneath the hood. No interp->result. Interpreters in Eagle have no thread affinity; can be used from any thread.

Question from the chat: "How easy is it to embed Eagle into a C# application?" Answer: examples of doing that come with the distribution. Walked through a simple example.

Question: What is the benefit of rewriting versus wrapping? Answer: Requirement was to implement the scripting language totally in 100% managed mode code.

Downloadable from http://eagle.to/


One question was "are the items above listed as missing a matter of limited resources in writing the code, or a limit of the environment" and the answer was that many of the items on the missing list are just a matter of not having enough time yet to write the code. However, it was my understanding from the reply that there are issues relating to tcl's namespace concept that would be quite difficult to implement.


JMN " Interpreters in Eagle have no thread affinity; can be used from any thread." That's radically different for sure.. but is it really 'under the hood'?; it sounds like a complete rearrangement of the Tcl scripting thread model. Does it mean that code can concurrently run in one interpreter and access global and namespace variables unsafely? 'Single thread per interp' along with 'send' and 'Thread Shared Variables' are one of the joys of Tcl threading that make it robust and conceptually elegant. I don't understand what throwing that away buys you. Presumably it will mean that multithreaded programs designed for Tcl or Eagle will be non-trivial to port to the other.

JJM Interpreters in Eagle are (or should be) fully thread-safe and may be used from any thread. In some scenarios, an Interpreter object may even be used by multiple threads at the same time.

JMN "In some scenarios, an Interpreter object may even be used by multiple threads at the same time." you say that like it's a good thing.

So far you seem to be confirming my fears above. It's an evisceration of the Tcl standard threading model - which I suspect will result in threaded programs that are even more difficult to reason about - or at the very least, are unlikely to be interchangeable.

JJM I guess I don't see the problem with having multiple threads using a given interpreter at the same time. All access to shared state is properly synchronized and each thread has its own script call stack and current call frame. Also, even with all of the features I have added to Eagle (or modified from Tcl), it still retains a very high degree of compatibility with Tcl (minus the things mentioned in the "missing features" mentioned above).

JMN To me, it's a litle like adding more doorways to a maze.. you're making more paths from corridor to corridor and more possible pathways overall - but at some point you defeat the purpose of the structure entirely and although the maze has more routes - it's now pointlessly simple to navigate. In programming too, it's the walls that provide the power to build meaningful structure... be they namespaces, encapsulation via objects or whatever. I suppose to some extent it may be a matter of taste - and despite my above complaint, I find the structure-violating power of 'upvar' and 'uplevel' for example, to be sharp but incredibly useful tools. If by default, Eagle's threading is essentially as per Tcl - with the thread-per-interp limit requiring explicit and deliberate violation - then I guess it could be workable in some cases. A library could use this to do suprising things and make for some pretty nasty timing-dependent anomalies that are hard to debug if you didn't realize it was doing this sort of thing.

JJM My basic view is that nobody is forced to use more than one thread for a given interpreter. My goal was to add protection in case they actually attempt to do so (since an Eagle script can execute arbitrary .NET Framework methods, including Thread.Start).