Version 17 of Erlang Idioms for Tcl

Updated 2005-12-12 11:53:21

Erlang is very cool. It's functional (declarative too), supports massive concurrency and promotes a number of programming idioms I find myself applying to Tcl. You don't have to emulate it via syntactical FP sugar (Lambda in Tcl, List Comprehension, etc). The idioms are rich and Tcl is up to the task! Tcl (with Threads) can do COP too ;-)

My network servers (coded in Tcl) are starting to model the way Erlang/OTP does things.

(Some of the items below are FP idioms, not just Erlang)

Some of the simple idioms:

  • Minimize side effects -- Try writing Tcl apps without global or namespace variables. Pass state as proc parameters (localize your errors). E.g. Rewrite fileevent/after handlers to accumulate state...
  • Concurrency interaction through message passing -- The Tcl thread package does this beautifully.
  • Controllers/Monitors -- Layer your app with processes/threads that do logic, monitor the threads that do the logic, manage the threads that monitor the threads that do the logic ... etc
  • Handle errors in a higher layer -- Interesting... Don't waste valuable processing time wrapping catch { } around everything. Handle it in a separate (controlling) thread that is signaled with the error.
  • Threads/processes should do only one thing, etc.
  • Message Receivers in Erlang: Queue messages received and use pattern matching to select the ones you are interested in.

Some things you can't really do well (or at all) in Tcl:

  • Guarded Function Clauses

Could you elaborate upon this, please?

lexfiend: To illustrate, in:

 factorial(0) -> 1;
 factorial(N) when N > 0 ->
   N * factorial(N - 1).

the expression N > 0 guards the function clause factorial(N) -> N * factorial(N-1) (the reserved word when introduces the guard). It essentially says "Don't evaluate this function clause if the guard expression fails". It basically translates to an if test, so I assume Todd's commenting about it being difficult to similarly express such things in Tcl.

  • Tail Recursion instead of iteration (KBK 2003-05-23 Tail call optimization has come up as a topic before.)
  • lexfiend Massive concurrency: Erlang spawns VM threads rather than OS threads, so applications using literally thousands of threads (actually processes, since they don't share data) are both amazingly performant and not unheard of.

If one had a copious amount of time, one could adapt Erlang/OTP to Tcl. That would be very nice...

-- Todd Coram

Although I have seen variations upon this elsewhere (Tail call optimization), this continues to amuse me: Factorial Using Event Loop.


Erlang makes extensive use of dictionaries (like Tcl arrays). It has a fast and scalable implementation but Scott Lystig Fritchie discovered a way to incorporate something called Judy Arrays into Erlang. His paper http://www.snookles.com/scott/publications/pli2003-slf.pdf compares different implementations of hashes for Erlang.

-- Todd Coram


NEM Erlang is a nice language. Guarded functions aren't too difficult to do (I'm sure this is probably on the wiki somewhere already):

 proc func {name args} {
    set params [lrange $args 0 end-1]
    set body   "when [list [lindex $args end]]"
    proc $name $params $body
 }
 proc when cases {
    foreach {cond -> action} $cases {
        if {$cond eq "otherwise"} {
            return [uplevel 1 [list expr $action]]
        } elseif {[uplevel 1 [list expr $cond]]} {
            return [uplevel 1 [list expr $action]]
        }
    }
    error "undefined case"
 }
 func factorial n {
    {$n == 0}   -> { 1 }
    {$n >  0}   -> { $n * [factorial [expr {$n - 1}]] }
 }
 puts [factorial 0]
 puts [factorial 5]
 puts [factorial -1] ;# Error case

It's not exactly like the Erlang (no pattern matching, etc) but you could make it nearer if you really want. You can also do more to "compile" the proc down to something sensible at definition time -- the version above delays processing to runtime, for neatness mainly.

Emulating Erlang's processes would be a neat trick; perhaps something useable could be built over the event loop (i.e., a lightweight process==proc type solution, rather than something more heavyweight). lexfiend: I believe Factorial Using Event Loop describes the basic methodology for that.


[ Category Concept ]