Updated 2012-01-14 21:26:24 by dkf

Here's from a news:comp.lang.tcl posting from Mark Harrison, a beautifully simple code generator: (RS)

BTW, it's easy to set up a framework for classes and abstract data types (just look at how many class systems there are for Tcl). Here' some skeleton code. If they are still going on about "design patterns" then I want credit for the "recursively eval body" pattern. :-)
    proc class {namespace name body} {
        set methods [list]
        puts "namespace eval $namespace \{"

        # Easier to build the code and substitute in the name afterwards
        set dispatcher {    proc %N {{name ""} args} {
        variable _methodmap
        if {[info exist _methodmap($name)]} {
            return [uplevel 1 $_methodmap($name) $args]
        } elseif {[string length $name]} {
            variable _methods
            return -code error "bad option \"$name\": must be $_methods"
        } else {
            return -code error \
                    "wrong # args: should be \"%N option ?arg arg ...?\""
        }
    }}
        regsub -all %N $dispatcher [list $name] dispatcher
        puts $dispatcher
        puts {}
        eval $body
        puts {}
        set ml [linsert [join $methods ", "] end-1 "or"]
        puts "    [list variable _methods $ml]"
        puts {    variable _methodmap}
        set methodmap [list]
        foreach method $methods {
            lappend methodmap $method [list ${namespace}::_$method]
        }
        puts "    array set _methodmap [list $methodmap]"
        puts "\}"
    }
    proc variable {name} {
        puts "    variable $name ;# array indexed by name"
    }
    proc method {name arg body} {
        upvar 1 methods methods
        puts "    proc _$name {$arg} \{"
        puts "    $body"
        puts "    \}"
        lappend methods $name
    }

    # here's a test
    class struct stack {
        variable stacks
        method clear {} {}
        method peek {{count 1}} {}
        method pop {{count 1}} {}
        method push {arg1 args} {}
        method rotate {count steps} {}
        method size {} {}
    }

 Mark Harrison                     [email protected]
 AsiaInfo Computer Networks        http://www.markharrison.net
 Beijing / Santa Clara             http://usai.asiainfo.com:8080

DKF: Added a dispatcher including code to automagically generate the dispatcher's error messages. The dispatcher is nowhere near robust enough about errors yet (rewriting the error trace is interesting to get right...)