apply

apply , a built-in Tcl command introduced in version 8.5 , applies a value as a routine, passing to it any provided arguments.

See Also

proc
uplevel
If we had no proc
Vogel spiral
uses apply as the script for bind

Documentation

official reference

Synopsis

apply routine ?arg1 arg2 …?

Description

routine is a list that matches this description:

args body ?namespace?

apply applies the routine in the given namespace, passing any additional arguments as arguments to that routine. If no namspace is provided the global namespace is used.

In contrast with proc, apply does not require that the routine be named or that it be located in a particular namespace. Since routine is a value, it can be stored in a variable and/or passed as a word in another command.

Examples

KPV: I've always found the "basic" example with namespaces, etc. too complicated. Here's my bare-bones sample code:

# Simple example: first argument is a duple of argument list and command to apply, remaining arguments get assigned to the variable list
apply {{var1 var2 var3}
    {puts "inside a lambda with var1: $var1 var2: $var2 var3: $var3"}
    } X Y Z

A basic example:

namespace eval ns1 {
    variable var1 1
    variable var2 2
}

namespace eval ns2 {
    variable var1 3
    variable var2 4
}

apply {{x args} {
    foreach arg $args {
        lappend vals [set [namespace current]::$arg]
    }
    ::tcl::mathop::+ $x {*}$vals
} ns1} 3 var1 var2 
# -> 6

apply {{x args} {
    foreach arg $args {
        lappend vals [set [namespace current]::$arg]
    }
    ::tcl::mathop::+ $x {*}$vals
} ns2} 3 var1 var2 
# -> 10
proc map {lambda list} {
    set result {}
    foreach item $list {
        lappend result [apply $lambda $item]
    }
    return $result
}
map {x {return [string length $x]:$x}} {a bb ccc dddd}
     → 1:a 2:bb 3:ccc 4:dddd
map {x {expr {$x**2 + 3*$x - 2}}} {-4 -3 -2 -1 0 1 2 3 4}
     → 2 -2 -4 -4 -2 2 8 16 26

Implementations for 8.4 and before

see TIP 194 , which also gives an illustrative implementation in pure-Tcl.

proc apply {fun args} {
    set len [llength $fun]
    if {($len < 2) || ($len > 3)} {
        error "can't interpret \"$fun\" as anonymous function"
    }
    lassign $fun argList body ns
    set name ::$ns::[getGloballyUniqueName]
    set body0 {
        rename [lindex [info level 0] 0] {} 
    }
    proc $name $argList ${body0}$body
    set code [catch {uplevel 1 $name $args} res opt]
    return -options $opt $res
}

RS wonders, however, how the following simpler take is insufficient:

proc nsapply {fun args} {
   foreach {argl body ns} $fun break
   namespace eval $ns [list foreach $argl $args break]
   namespace eval $ns $body
}

A footnote to this: the above code messes so hard with wish's namespace eval handling that it needs to be shut down with Task Manager (Tcl/Tk 8.6.1 on Windows 7). It does work in tclsh.

Testing:

% nsapply {x {expr $x*$x}} 5
25
% nsapply {{x y} {expr hypot($x,$y)} foo} 3 4
5.0

NEM: The difference is that in your version parameters are persistent namespace variables, rather than local to the procedure. Consider:

% interp alias {} test1 {} nsapply {x {expr {$x * $x}}}
test1
% interp alias {} test2 {} nsapply {x {set y [test1 12]; return $x}}
test2
% test2 "Hello!"
12

Which isn't what you want, I expect.

RS: Indeed. In fact, I didn't want namespaces at all :) - just because the other version had them... I started with this:

proc apply {fun args} {
    foreach {argl body} $fun break
    foreach $argl $args break
    eval $body
}

Bryan Oakley: I don't like the syntax. Why is the function itself a list? What is wrong with a syntax that lets me use it like this:

button .b -command [apply arglist body arg1 arg2 ...]

... if you need a namespace it could be:

button .b -command [apply arglist body -namespace foo arg1 arg2]

... and if you want "-namespace" to not be treated as part of the apply command but rather one of the extra arguments you could do:

button .b -command [apply arglist body -- -namespace foo arg1 arg2]

MS replied in Re: 8.5 "apply" command (was Re: TK: question about "-command" usage with "{}" and double quoter) Miguel Sofer, 2006-03-29, that structure is required in order to be able to cache a bytecompiled body and avoid recompilation at each step. The anonymous function carries all the info necessary for compilation {argList body namespace} in a single Tcl_Obj.

Note also that this makes it easier to have

set anon [list argList body]
button .b -command  [list apply $anon arg1 arg2]
button .b1 -command [list apply $anon arg3 arg4]

and have both buttons share the anonymous function - including the bytecompiled structures.

NEM: It's also pretty easy to create a constructor function (which apply is not):

proc func {params body args} {
    set ns [uplevel 1 namespace current]
    linsert $args 0 ::apply [list $params $body $ns]
}
button .b -command [func arglist body arg1 arg2 ...]
# etc...

I personally use a constructor proc that snapshots the lexical closure into a dict:

proc func args {
    set ns      [uplevel 1 namespace current]
    set env     [uplevel 1 capture]
    set params  [linsert [lrange $args 0 end-1] 0 __env__]
    set body    [list dict with __env__ [lindex $args end]]
    return [list ::apply [list $params $body $ns] $env]
}
proc capture {} {
    set env [dict create]
    foreach name [uplevel 1 info locals] {
        upvar 1 $name var
        catch {dict set env $name $var} ;# no arrays
    }
    return $env
}

Which I can then use like:

proc person {name age} {func key {set $key}}
proc ask {object args} {uplevel 1 $object $args}
set neil [person {Neil Madden} 25]
puts "Neil's age is [ask $neil age]"

I've also on occasion used a further variation that wraps the body in a call to expr. I'll leave -namespace as an exercise for the reader.


Also, in the days before Tcl 8.5:

What: apply

 Where: http://www.glinx.com/%7Ehclsmith/plugin.html  ???
 Description: Version of the apply procedure as discussed on
        news:comp.lang.tcl during February, 1997.
        Versions of Tcl C and scripting routines as well as a
        lisp-backquote-like proc are available.  Now supports Tcl 8.x.
 Updated: 09/1999
 Contact: mailto:[email protected] (Hume Smith)

NEM wonders if the c.l.t discussion mentioned is Feature request: 'apply' command , comp.lang.tcl, 1997-01-26. If so, then the apply mentioned there seems more related to {*} than to our current apply command. Or perhaps a version of this:

proc old-apply {cmd args} { uplevel 1 $cmd $args }

WHD: The Tcl 8.5 man page has this example:

proc map {lambda list} {
    set result {}
    foreach item $list {
        lappend result [apply $lambda $item]
    }
    return $result
}

# Returns {1:a 2:bb 3:cc 4:dddd}
map {x {return [string length $x]:$x}} {a bb ccc dddd}

This strikes me as really bad style: it means that map can only be used with "lambdas"; you can't use normal commands unless you cast them as lambdas. So what would be better?

It is already common style to pass command prefixes as callbacks. "The cmd argument is a command prefix to which two additional arguments will be added..." Suppose we wrote map like this instead:

proc map {prefix list} {
    set result {}
    foreach item $list {
        lappend result [{*}$prefix $item]
    }
    return $result
}

Then we can write

# Returns {1:a 2:bb 3:cc 4:dddd}
map {apply {x {return [string length $x]:$x}}} {a bb ccc dddd}

But we can also write

# Returns {1 2 3 4}
map {string length} {a bb cc dddd}

An apply expression then becomes just another kind of command prefix.

NEM: This is indeed good style, as is always using a constructor function rather than a literal:

proc lambda {params body args} {
    set ns [uplevel 1 namespace current]
    list ::apply [list $params $body $ns] {*}$args
}
map [lambda x ...] $xs

Lars H: The virtue of "constructor function rather than literal" is highly debatable, IMO. Capturing the namespace context is good, but since that constructor function recreates the lambda Tcl_Obj every time it is called, the above has the severe drawback that the same lambda is going to get recompiled over and over again. A literal lambda persists, so it is only compiled once.

NEM: What's that phrase about premature optimisation? Byte-code compilation is fast and if you are constructing a lambda inside a tight loop then simply move it out. Not properly encapsulating code because of some weird obsession with eliminating a few microseconds is just wrong.

Lars H: Is this a fear of complex literal data I see? Or just a reaction on having one's style put under scrutiny? Claims that one style is "always" good deserve to be critized. The "simply move it out" approach hurts other goals for good code, such as keeping related things together, so why should one always take precendence over the other?

As for the "premature optimisation": It's not so much the time for recompilation that concerns me (even though this is obviously low-hanging fruit), but rather that the object is being created again and again — the use of a constructor function to produce a constant. For one, it is tantamount to shimmering, which IMHO is best avoided from the start rather than eliminated in a clean-up phase. Second, it can at times (although probably not in this case) be a severe memory bloat to recreate a Tcl_Obj rather than sharing one that already exists. Sure, the constructor function can use memoizing to counter that, but this introduces the problem of life-cycle management, and complicates the code. The literal constant is just so much easier!

The general argument for constructor functions — that less code need to be modified if the underlying representation changes — is hardly relevant for apply lambdas, so advocating their use here can itself be considered an act of premature optimisation. ;-)

MS thinks that this is a whole different kettle of fish. Depending on the app, and how much memory management may be needed or acceptable, the optimal may be literals (live "forever", shared), simple constructor (garbage collected, not shared), memoizing constructors (live until explicitly freed, shared), some kind of fancy memoizing constructors (could eg free lambdas that were not used in the last X seconds, shared), ...

WHD: If we had true compile-time macros, a la Lisp or Scheme, could we possibly have it both ways? If lambda, as described above, were a macro, you'd only pay the compilation penalty once.

NEM: You don't really need macros. A sufficiently smart byte-compiler could inline the lambda constructor into the body it appears in. I doubt very much whether the performance gain is at all worth it, though -- we're talking about a constant-time operation (assuming the body of the lambda is not changing on each iteration, in which case a literal would be no help) that generally takes <10us by my measurements. As Miguel points out, what is right for your app might be a trade-off. As Lars even acknowledges, a constructor function is free to memoize, effectively transforming itself into the literal version. Literals also live forever, so they have no particular advantage over memoizing. "Encapsulation is good" is one of the few really solid ideas from software engineering. Even for lambdas this encapsulation is a good idea: e.g. you can add enter/exit tracing to all lambdas easily, or bundle some extra state, or perhaps wrap the lambda in a coroutine or thread so that long-running computations can be transparently handed off without blocking execution. Other advantages are that you avoid many cases of overquoting by having implicit list-quoting, avoid ever generating a string rep, can wrap the body in an expr or dict with to get custom behaviours, etc, etc, etc. Literals bad functions good!


RS 2008-10-15: Has it been discussed that apply might also accept command names, i.e. non-lambdas? Such that

apply $f $x $y 

would then work with

set f {{a b} {expr {sqrt($a*$a+$b*$b)}}}

as well as

set f tcl::mathfunc::hypot

? - In fact, it's already in recent Tcl sources - dgp pointed me to tclProc.c, search for JOE_EXTENSION.

Combining with [interp alias]

AMG: [interp alias] and [apply] may be used together as an alternative to [proc]:

proc name params code
interp alias {} name apply {params code}

At first glance, this seems like a waste; just use [proc], right? Yet, consider creating the alias in a slave interpreter. Normally it's necessary to create procs in the current interpreter to handle aliased commands from slave interpreters, but the procs clutter the current interpreter and are callable from the current interpreter despite it sometimes being meaningless or dangerous to do so. [apply] bypasses the named proc requirement by binding the alias directly to the code, with a parameter list and optional namespace, of course.

set slave [interp create]
$slave alias add apply {{x y} {expr {$x + $y}}}
$slave eval {add 2 2}

Avoid local variable creation

HaO 2012-07-18:

apply may also be used to get just a frame for local variables.

AMG: Put another way, [apply] gives you a temporary scope, after which all local variables are cleaned up.

Example

A module is placed in the namespace ns and requires one-time init code. The local variables of the init code should not be set as namespace global.

Solution with global commands

namespace eval ::ns {
    # Module variable to initialize from some calculations
    variable moduleVar 1
    # Module initialisation
    # variable should be local but is global due to global scope
    set counter 500
    # do some calculation to find initial value
    incr counter $counter
    # and initialize module variable with result
    set moduleVar $counter
    # unset local variable
    unset counter
}

Set local variables must be manually unset.

Solution with one-time init proc

namespace eval ::ns {
    variable moduleVar 1
}
# Module initialisation
proc ns::init {} {
    variable moduleVar
    # locale variable
    set counter 500
    incr counter $counter
    set moduleVar $counter
}
ns::init
rename ns::init {} 

The init-proc must be manually called and deleted

Solution with apply

namespace eval ::ns {
    variable moduleVar 1
}
# Module initialisation
apply {{} {
    variable moduleVar
    set counter 500
    incr counter $counter
    set moduleVar $counter
} ns}

Similar to the upper init-proc method but no delete necessary.

Default Namespace

PYK 2014-08-15: What was the rationale for making the default namespace the global namespace? My impression is that the vast majority of cases call for apply in the current namespace.

AMG: The anonymous procedure (lambda) needs to be bound somewhere. Even though it may seem desirable to behave like [proc] and bind the lambda to the namespace in which it was created, this is severely problematic.

It's hard to precisely define the meaning of "created" since the lambda value can be built up in pieces over time by code running in/bound to different namespaces. At what point does it become a lambda? The first time it can be parsed as such? The first time it can run without error? The first time it gets used as a lambda? That last choice is the Tcl answer, but of course the first [apply] can happen very late (if ever), quite possibly long after leaving the user-intended namespace.

This issue doesn't come up with [proc] because procs are indisputably created at a specific time and place: whenever/wherever [proc] is invoked.

In the minds of most users there's a big difference between creation and first use, but due to duck typing, the lambda isn't really "created" until used as such. Tcl smooths over the difference between user expectation and reality by rendering the difference moot by not having anything magical happen at "creation" time. This is the way of values. Procs are not values. Lambdas are.

Pretend that the above problem were solved. How would Tcl keep track of which namespace the lambda is bound to? It must be in the string representation itself, or else EIAS is violated. But this contradicts the notion of "default" by making it be explicit all the time (*). To have it both ways would imply that Tcl automatically adds it to the string representation. The last thing we want is for Tcl to "intelligently" rewrite your values according to its predictions about how you might end up using them. So no, can't do it that way.

What about having the lambda be bound to whichever namespace [apply] happens to be running in? The most obvious problem with this is the lambda would see different [variable]s depending on who runs it. This would make lambdas be little more than a glorified [eval], rather than a stable, self-contained, reusable unit.

In conclusion, making the default namespace be :: is the only reasonable approach, all other possibilities having been eliminated.

(*): You can always write a lambda constructor that returns a lambda bound to the current namespace, as NEM demonstrates earlier on this page.

Functional Composition

AMG: [apply] is brilliant for building up behaviors, even complex behaviors, from mixed-and-matched functional components.

proc pipeline {args} {
    set lambda {return -level 0}
    foreach arg $args {
        set lambda [list apply [dict get {
            toupper {{lambda input} {string toupper [{*}$lambda $input]}}
            tolower {{lambda input} {string tolower [{*}$lambda $input]}}
            totitle {{lambda input} {string totitle [{*}$lambda $input]}}
            prefix {{lambda pre input} {string cat $pre [{*}$lambda $input]}}
            suffix {{lambda suf input} {string cat [{*}$lambda $input] $suf}}
        } [lindex $arg 0]] $lambda {*}[lrange $arg 1 end]]
    }
    return $lambda
}
set command [pipeline toupper {suffix " world"} {prefix "xxx "}]
chan puts [{*}$command hello]
chan puts [{*}[pipeline toupper {suffix " world"} prefix] "xxx " hello]

This prints:

xxx HELLO world
xxx HELLO world

Recursive Invocation

AMG: Normal commands can call themselves without difficulty since they are named entities. For [apply], magic is required since lambdas are anonymous. One option is to store the lambda in a variable then pass it to the lambda so it can reference itself, but this barely counts since the "lambda" is given a name (albeit a scoped name, so this is still more flexible than procs). Instead, you can use {*}[lrange [info level 0] 0 1] in place of the command name. [info level 0] evaluates to the current command (apply) and its arguments, the first of which is the lambda. Alternately, use apply [lindex [info level 0] 1], which will have the same effect.

Here's a command that embeds a recursive helper lambda:

proc qsort {list} {
    apply {{a b} {
        if {$a < $b} {
            upvar 1 list list
            set p [lindex $list [expr {($a + $b) / 2}]]
            set i $a
            set j $b
            while {1} {
                while {[lindex $list $i] < $p} {incr i}
                while {[lindex $list $j] > $p} {incr j -1}
                if {$i < $j} {
                    set swap [lindex $list $i]
                    lset list $i [lindex $list $j]
                    lset list $j $swap
                    incr i
                    incr j -1
                } else {
                    {*}[lrange [info level 0] 0 1] $a $j
                    {*}[lrange [info level 0] 0 1] [expr {$j + 1}] $b
                    return
                }
            }
        }
    }} 0 [expr {[llength $list] - 1}]
    return $list
}