From: Fredderic on
On Mon, 09 Jun 2008 15:19:22 -0500,
"Gerald W. Lester" <Gerald.Lester(a)cox.net> wrote:

> George Peter Staplin wrote:
>> From what I see they don't get byte compiled. Tcl_EvalEx is used,
>> and it has no Tcl_Obj to use to cache the internal bytecode
>> representation.
> I think the reason has to do with the % substitution.

One thing that I did last time I wrote a Tk app, was to write myself a
small [wrap] function that takes the script you wish to bind, and sets
it up as a [proc] with a unique name (eg. tk-binding-NNN, where NNN is
an incrementing global counter). ie:

[wrap {s} { ... bind script here ... }]
might return: tk-binding-6 %s
proc tk-binding-6 {s} { ... bind script here ... }

You can also use [regexp] to extract a list of % substitution tokens,
[regsub] to change them into regular variable references (or you could
use [regexp -indices] and do it yourself), and [lsort -unique] to
produce the appropriate argument list. I did that in a separate
[wrap-auto] proc that in turn called the main [wrap] proc, since it
does occasionally get a little over-zealous. But it was good being
able to write your handler script right there, without having to worry
about it being beastly inefficient.


I've never looked into it any further than that, but it should be
possible to pass in the name of the object so that the wrap function
can destroy the procedure when the object itself gets destroyed. You
can also apply [catch] and re-throw wrapping (or something similar), to
get those [break]s through. (eg. return -level 0 -code {*}[tk-...])


Fredderic
From: Andreas Leitgeb on
Fredderic <my-name-here(a)excite.com> wrote:
> [wrap {s} { ... bind script here ... }]
> might return: tk-binding-6 %s
> proc tk-binding-6 {s} { ... bind script here ... }

My first thought was: "why not use lambdas?", but this was
quickly answered: "because they, too, would undergo %-substitution,
thus the gain would be void.

Most likely it's still better, to just place the code in a
well-named, explicitly created procedure, and call that from
bind :-)

From: Fredderic on
On 01 Jul 2008 07:29:31 GMT,
Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> wrote:

> Fredderic <my-name-here(a)excite.com> wrote:
>> [wrap {s} { ... bind script here ... }]
>> might return: tk-binding-6 %s
>> proc tk-binding-6 {s} { ... bind script here ... }
> My first thought was: "why not use lambdas?", but this was
> quickly answered: "because they, too, would undergo %-substitution,
> thus the gain would be void.

Yup... Basically no advantage at all. The [wrap] method pulls the
actual script out of Tk's sight entirely, constraining the
substitutions to the argument list to the newly-created proc.


That reminds me of that annoying lambdaExpr "feature" where the
byte-compiling is broken if you try to read the lambda's arguments
list... I've got a number of cases where I'd like to be able to do:

apply $lambda [dict mget $dict [lindex $lambda 0]]
(dict mget returns the values corresponding to a list of keys)


> Most likely it's still better, to just place the code in a
> well-named, explicitly created procedure, and call that from
> bind :-)

Yeah, but not nearly as much fun. ;) Seriously, for one-liners I'd do
it directly inline and accept the hit. For long handlers where you
can't see both ends on a standard 24-line terminal, I'd do it exactly
like that; define the proc and then use a bind line to attach it.
However, I find the [wrap] method perfect for 3-10 line scripts, where
you can take in the whole thing with a glance.

One way to avoid having to pass the widgets name, might actually be to
wrap the entire bind statement. I'm going by vague memory here, but
the second argument will usually be the widgets name, and the last
argument will be the script. So if you wrote the script in
lambda-form, your [wrap] command could lift that off and do what it
needs to do, lift off the second word to bind a destructor, and then
just [uplevel] the statement as provided (of course, substituting the
script lambda with the appropriate command).


Fredderic
From: miguel on
Fredderic wrote:
> That reminds me of that annoying lambdaExpr "feature" where the
> byte-compiling is broken if you try to read the lambda's arguments
> list... I've got a number of cases where I'd like to be able to do:
>
> apply $lambda [dict mget $dict [lindex $lambda 0]]
> (dict mget returns the values corresponding to a list of keys)

Mmhhh ... maybe let [info args] and [info body] inspect lambdas too? Or add a
[info lambda] that will return a copy of the lambda as list without shimmering
the original?

In the meantime: why don't you do that just once and cache it yourself, if you
are so worried?

if {![info exists arg($lambda)]} {set arg($lambda) [lindex $lambda 0]}
apply $lambda [dict mget $dict $arg($lambda)]

Another option is to create them with some redundancy

set lambda2 [list $lamArgs [list $lamArgs $lamBody]]
...
lassign $lambda2 lamArgs lambda
apply $lambda [dict mget $dict $lamArgs]
From: Robert Heller on
At Wed, 2 Jul 2008 04:28:29 +1000 Fredderic <my-name-here(a)excite.com> wrote:

>
> On 01 Jul 2008 07:29:31 GMT,
> Andreas Leitgeb <avl(a)gamma.logic.tuwien.ac.at> wrote:
>
> > Fredderic <my-name-here(a)excite.com> wrote:
> >> [wrap {s} { ... bind script here ... }]
> >> might return: tk-binding-6 %s
> >> proc tk-binding-6 {s} { ... bind script here ... }
> > My first thought was: "why not use lambdas?", but this was
> > quickly answered: "because they, too, would undergo %-substitution,
> > thus the gain would be void.
>
> Yup... Basically no advantage at all. The [wrap] method pulls the
> actual script out of Tk's sight entirely, constraining the
> substitutions to the argument list to the newly-created proc.
>
>
> That reminds me of that annoying lambdaExpr "feature" where the
> byte-compiling is broken if you try to read the lambda's arguments
> list... I've got a number of cases where I'd like to be able to do:
>
> apply $lambda [dict mget $dict [lindex $lambda 0]]
> (dict mget returns the values corresponding to a list of keys)
>
>
> > Most likely it's still better, to just place the code in a
> > well-named, explicitly created procedure, and call that from
> > bind :-)
>
> Yeah, but not nearly as much fun. ;) Seriously, for one-liners I'd do
> it directly inline and accept the hit. For long handlers where you
> can't see both ends on a standard 24-line terminal, I'd do it exactly
> like that; define the proc and then use a bind line to attach it.
> However, I find the [wrap] method perfect for 3-10 line scripts, where
> you can take in the whole thing with a glance.
>
> One way to avoid having to pass the widgets name, might actually be to
> wrap the entire bind statement. I'm going by vague memory here, but
> the second argument will usually be the widgets name, and the last
> argument will be the script. So if you wrote the script in
> lambda-form, your [wrap] command could lift that off and do what it
> needs to do, lift off the second word to bind a destructor, and then
> just [uplevel] the statement as provided (of course, substituting the
> script lambda with the appropriate command).

One can also do interesting things using a SNIT widgetadaptor. And
certainly with SNIT mega and meta widgets.

>
>
> Fredderic
>

--
Robert Heller -- Get the Deepwoods Software FireFox Toolbar!
Deepwoods Software -- Linux Installation and Administration
http://www.deepsoft.com/ -- Web Hosting, with CGI and Database
heller(a)deepsoft.com -- Contract Programming: C/C++, Tcl/Tk