Tip #288

Keith Vetter 2018-08-15: I've always liked Tip 288 -- Allow "args" Anywhere in Procedure Formal Arguments . But seeing how it was proposed back in 2006, I doubt it will ever get implemented.

That being said, I thought it would be fun to try my hand at providing a tcl-only version of this tip. Also, since I've been writing a lot of Python recently and am intrigued with @decorators, I'd thought I use that mechanism.

################################################################
#
# tip288 -- decorator to allow args anywhere in the argument list
# https://core.tcl.tk/tips/doc/trunk/tip/288.md
# see also: http://chiselapp.com/user/aspect/repository/tcl-hacks/finfo?name=modules/tip288-0.tm

proc @tip288 {p pname pargs lambda} {
    if {$p ne "proc"} { error "bad synax: $p != 'proc'"}
    set idx [lsearch $pargs "args"]
    if {$idx == -1 || $idx == [llength $pargs] - 1} {
        proc $pname $pargs $lambda
        return
    }
    set pre [lrange $pargs 0 $idx]
    set post [lrange $pargs $idx+1 end]
    set body "
        set args \[lreverse \[lassign \[lreverse \$args\] [lreverse $post]\]\]
        $lambda
    "
    proc $pname $pre $body
}

Here's some code to test it:

@tip288 \
proc test_@tip288_middle {a b args c d} {
    puts "a: '$a' b: '$b' c: '$c' d: '$d' =>  args: '$args'"
}

@tip288 \
proc test_@tip288_front {args a b c d} {
    puts "a: '$a' b: '$b' c: '$c' d: '$d' =>  args: '$args'"
}

@tip288 \
proc test_@tip288_end {a b c d args} {
    puts "a: '$a' b: '$b' c: '$c' d: '$d' =>  args: '$args'"
}

@tip288 \
proc test_@tip288_none {a b c d} {
    puts "a: '$a' b: '$b' c: '$c' d: '$d'"
}

test_@tip288_middle A B these are random arguments for testing C D
test_@tip288_front these are random arguments for testing A B C D
test_@tip288_end A B C D these are random arguments for testing
test_@tip288_none A B C D