Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

reusing "code entities" without oop

6 views
Skip to first unread message

Stephen M. Gava

unread,
Mar 28, 2007, 8:25:32 PM3/28/07
to
Since we've been evaluating tcl/tk for a project I've found it asserted
in several places in documentation that most things that you might use
oop for in other languages are achievable in a non oop way in tcl.

In python for instance (using tkinter) you might make a tailored tk
control, or even a whole toplevel with all its functionality, an object.
You can then instantiate this object any number of times as a way of
reusing this packaged functionality.

What would be the "standard" (non oop) tcl way of acheiving this outcome,
or would the best answer be to use one of the oop "addons" for this
purpose?

The reason I ask is that the simplicity of pure tcl/tk is compelling for
deployment reasons, but if things like the "instantiation effect" need
non core addons then it probably makes more sense for us to go with a
combination of python (which we are more familliar with) and tk (via
tkinter).

TIA for any help,
Stephen.

Bryan Oakley

unread,
Mar 28, 2007, 10:59:00 PM3/28/07
to
Stephen M. Gava wrote:
> Since we've been evaluating tcl/tk for a project I've found it asserted
> in several places in documentation that most things that you might use
> oop for in other languages are achievable in a non oop way in tcl.
>
> In python for instance (using tkinter) you might make a tailored tk
> control, or even a whole toplevel with all its functionality, an object.
> You can then instantiate this object any number of times as a way of
> reusing this packaged functionality.
>
> What would be the "standard" (non oop) tcl way of acheiving this outcome,
> or would the best answer be to use one of the oop "addons" for this
> purpose?

There isn't a standard way, per se. I've been meaning to write an
article on this very subject on tclscripting.com, but the time to do
that seems to elude me.

I'll give a short example of the technique that I use, but it's
certainly not the only way to solve the problem. This example creates a
tcl psuedo-object (read: not a tk megawidget). The same technique
applies to widgets, only you create a frame of the given name and do a
little other housework when creating the pseudo-object.

With this example you can create "objects" by running the command
"myObject". These pseudo-objects have two subcommands: configure and
cget. It should be obvious how to add other subcommands simply by
writing a proc in the proper namespace. I've left out all error checking
and many conveniencesfor the sake of brevity.

These pseudo-objects don't behave exactly like true objects which you
might get with python. For example, you can't do inheritance (out of the
box, anyway, but just about anything's possible in Tcl if you're
motivated!). Still, for my needs this technique has served me well for
years.

(Tcl veterans might suggest I use namespace ensembles, dicts and
{expand}/{*}, all of which are dandy features in 8.5, but I wanted to
present a bare-bones solution using as few advanced features as possible...)

Without further ado (golly, all that explanation was longer than the code!)

namespace eval myObject {namespace export myObject}
proc myObject::myObject {name args} {
# create a new command, '$name', in the global scope
interp alias {} ::$name {} ::myObject::proxy $name

# establish a variable for instance data
upvar #0 ::myObject::instance-$name data

# apply the command line options
eval configure $name $args
}

proc ::myObject::proxy {name subcommand args} {
if {[llength [info commands ::myObject::$subcommand]] == 1} {
eval ::myObject::$subcommand \$name $args
} else {
return -code error "unknown subcommand \"$subcommand\""
}
}

# the "configure" sub-command (or "method", if you prefer)
proc ::myObject::configure {name args} {
upvar #0 ::myObject::instance-$name data

foreach {option value} $args {
set data($option) $value
}
}

# the "cget" sub-command (or "method", if you prefer)
proc ::myObject::cget {name option} {
upvar #0 ::myObject::instance-$name data
if {[info exists data($option)]} {
return $data($option)
} else {
return -code error "unknown option \"$option\""
}
}

# Example:

namespace import myObject::*
myObject obj1 -string "Hello, world" -foo "tcl rocks"
myObject obj2 -string "Goodbye, world" -foo "tk rocks"

puts "obj1 string: [obj1 cget -string]"
puts "obj1 foo: [obj1 cget -foo]"
puts "obj2 string: [obj2 cget -string]"
puts "obj2 foo: [obj1 cget -foo]"

Larry W. Virden

unread,
Mar 29, 2007, 7:26:16 AM3/29/07
to
On Mar 28, 8:25 pm, "Stephen M. Gava" <elgua...@users.sourceforge.net>
wrote:
> [...] I've found it asserted

> in several places in documentation that most things that you might use
> oop for in other languages are achievable in a non oop way in tcl.>

Not knowing the specific references in question, I can't tell whether
the authors referenced are thinking of the "create an OO extension in
pure tcl" approach, or if they are thinking of using namespaces, the
package mechanism, etc. to make it easy to bundle up code, then
dynamically load and use the code in question.


Neil Madden

unread,
Mar 29, 2007, 8:04:34 AM3/29/07
to

There are ways to do this in pure Tcl. However, if your primary purpose
is to create re-useable Tk components, then I'd recommend using Snit
(http://wiki.tcl.tk/snit). It is itself pure Tcl code, and is very well
polished for this kind of work.

-- Neil

Aric Bills

unread,
Mar 29, 2007, 11:41:41 AM3/29/07
to
> There are ways to do this in pure Tcl. However, if your primary purpose
> is to create re-useable Tk components, then I'd recommend using Snit
> (http://wiki.tcl.tk/snit). It is itself pure Tcl code, and is very well
> polished for this kind of work.
>
> -- Neil

I second this suggestion. Snit is all of 376K (compare to the size of
Python + Tkinter - Tcl/Tk itself), and was designed with Tk GUI
components in mind. It also feels very "tcl-ish" (rather than C+
+ish), which I consider to be a strength.

Here's an example of a (useless) component coded in Snit. It's an
entry widget with a history feature. Hopefully it gives you a feel
for what it's like to write Tk code with Snit.


package require snit

snit::widget mementry {
# an entry widget that remembers previous input

variable history {}

component entry
component button
component historylist

# pass on all unknown options and commands to the entry widget
delegate option * to entry
delegate method * to entry

constructor {args} {

# create widgets
install entry using entry $win.entry
install button using button $win.button \
-text "History" \
-command [mymethod showhistory]
install historylist using menu $win.historylist \
-tearoff 0

# widget geometry management
grid $entry $button -sticky nsew
grid rowconfigure $win 0 -weight 1
grid columnconfigure $win 0 -weight 1

# add to history when user presses Enter
bind $entry <Key-Return> [mymethod addtohistory]

# process any options invoked at widget creation
$self configurelist $args
}

method addtohistory {} {
# called when the user presses <Enter> / <Return>
lappend history [$entry get]
$entry selection range 0 end
}

method showhistory {} {
# called when user clicks on the "History" button
if {[llength $history] == 0} {
return
}

# history mechanism is a popup menu--
# clear any previous entries in the menu,
# then repopulate it with history info

$historylist delete 0 end
foreach item $history {
$historylist insert 0 command \
-label $item \
-command [mymethod selecthistory $item]
}
$historylist post [winfo pointerx $win] [winfo pointery $win]
}

method selecthistory {value} {
# called when the user selects something from the menu
$entry delete 0 end
$entry insert end $value
$entry selection range 0 end
}

method clearhistory {} {
# for programmer's convenience
set history {}
}
}

Gerald W. Lester

unread,
Mar 29, 2007, 12:16:59 PM3/29/07
to
Aric Bills wrote:
>> There are ways to do this in pure Tcl. However, if your primary purpose
>> is to create re-useable Tk components, then I'd recommend using Snit
>> (http://wiki.tcl.tk/snit). It is itself pure Tcl code, and is very well
>> polished for this kind of work.
>>
>> -- Neil
>
> I second this suggestion. Snit is all of 376K (compare to the size of
> Python + Tkinter - Tcl/Tk itself), and was designed with Tk GUI
> components in mind. It also feels very "tcl-ish" (rather than C+
> +ish), which I consider to be a strength.
>
> Here's an example of a (useless) component coded in Snit. It's an
> entry widget with a history feature. Hopefully it gives you a feel
> for what it's like to write Tk code with Snit.

And I have heard that once the OO support makes it into the core that Snit
will be lighting fast.

--
+--------------------------------+---------------------------------------+
| Gerald W. Lester |
|"The man who fights for his ideals is the man who is alive." - Cervantes|
+------------------------------------------------------------------------+

Jeff Hobbs

unread,
Mar 29, 2007, 2:52:58 PM3/29/07
to Stephen M. Gava

While OO is often overused, it is actually useful in UI programming and
for the building of megawidgets in particular. I would recommend using
the 'snit' module in tcllib (part of ActiveTcl). It is conceptually
clean and easier to use. You will find examples of snit widgets in the
tklib 'widget' package (also in ActiveTcl).

Jeff

Cameron Laird

unread,
Mar 29, 2007, 3:59:26 PM3/29/07
to
In article <460C0B0A...@activestate.com>,

All true, along with the remarks of Bryan, Aric, Gerald, and the others.

I remain suspicious that there's an even more elementary answer. While
I don't have time before next week to engage in much of a conversation,
I suspect this thread as it stands underestimates the extent to which
simple procedural "factory functions" are the aptest idiom for many GUI
programming chores. In the sentence, "You can then instantiate this


object any number of times as a way of reusing this packaged

functionality", is "reuse" something that's taking place across or
within applications? Is the point to manage several instances within
what the end-user sees as a single program, or to stockpile useful parts
for a team of developers working on many programs?

Stephen M. Gava

unread,
Mar 29, 2007, 10:36:07 PM3/29/07
to
Thanks for all replies, I've had a look at snit and it seems to fit the
bill nicely for the kinds of encapsulation we had in mind, and it's good
that it's part of tclib.

Cheers,
Stephen

0 new messages