Skip to content

R and tcltk Package

3 messages · Roderick, Ivan Krylov

#
Dear Sirs,

I began not long ago to learn R. Now I want to understand the
tcltk binding. I have very elementary questions that are not
clear from help(TclInterface).

Let us say, I do
<Tcl> 2

How do I access the variable k from R?
And how do I access R variables from tcl?

I read that tclVar() creates a new Tcl variable. Well, the following
example shows that this is not 100% true:
[1] "::RTcl1"
<Tcl> 5
<Tcl> 5
<Tcl>
[1] "::RTcl2"

Since ::RTcl2 existed, b<-tclVar() should have created something
different and new, perhaps ::RTcl3.

Can I at least be sure that all variables generated by tclVar()
and tclArray() are of the form ::RTcl2N ?

And what are these callbacks, are they functions callable from Tcl?
The following does not work:
[1] 7
[1] " { R_call 0x80e29e2e0 }"
Error in structure(.External(.C_dotTcl, ...), class = "tclObj") :
   [tcl] invalid command name " R_call 0x80e29e2e0 ".

Is there a more detailed guide than help(TclInterface)?

Thanks for any hint
Rodrigo
#
? Tue, 15 Mar 2022 19:27:13 +0000 (UTC)
Roderick <hruodr at gmail.com> ?????:
tclvalue('k') can give you the string representation of the variable.
With R-controlled variables (the tclVar interface), you can use tclObj
to get other representations of variables and avoid quoting hell. You
can also get the Tcl object using tcl('set', 'k').
I think that you have to use callbacks for that. At least I see no way
of giving R environments to Tcl, and that would be the basis of
accessing arbitrary variables.
The idea behind the tclVar interface was to avoid dealing with names
(since creating global variables manually may result in namespace
collisions) and only use tclvalue() and friends to access the
variables.
Yes, this has been mentioned in the R News articles (see below) and you
can see that in the tclVar/tclArray implementations. If you peek behind
the curtain, you'll see that R assumes that the number of global Tcl
variables stored in .TkRoot$env$TclVarCount is correct.
That's because passing an R function to a Tcl call converts it into a
command string (e.g. { R_call 0x80e29e2e0 }) to be evaluated as a whole:

f <- function() message('Hello from R from Tcl from R!')
tcl('eval', f)
# Hello from R from Tcl from R!
# <Tcl>

(Alternatively, .Tcl(.Tcl.callback(f)), because that doesn't wrap the
string into {}. .Tcl.args(f), which does wrap, makes Tcl interpret that
as a single command, which is results in an error, because "R_call
whatever" is, indeed, not a command.)

If you want to call it yourself, you have to separate R_call from its
argument. Be careful, because passing the wrong pointer to R_call will
crash the process:

.Tcl.callback(f)
# [1] "R_call 0x563e6e10b900"
tcl('R_call', '0x563e6e10b900')
# Hello from R from Tcl from R!
# <Tcl>
tcl('R_call')
# 
#  *** caught segfault ***
# address (nil), cause 'memory not mapped'
# ...
As far as I can tell, the R-Tcl/Tk interface is not well documented,
but here are two R News articles providing some more information with
examples:

https://cran.r-project.org/doc/Rnews/Rnews_2001-3.pdf#section*.69
https://cran.r-project.org/doc/Rnews/Rnews_2002-3.pdf#section*.54

"Programming Graphical User Interfaces in R" by Michael F. Lawrence
John Verzani (ISSN 978-1-4398-5683-3) also provides some information.
After that, I'm afraid you'll have to resort to source code diving.
1 day later
#
Dear John, dear Ivan, thanks a lot.

I am learning R, now trying to learn the Low-level Tcl/Tk Interface,
because I want to write functions programming tcl, with the tcl syntax.
I could do something like .Tcl("source file.tcl"). From there I can
for example do "package require sqlite3", tcl and sqlite combine very
good together. But perhaps also write widgets in the usual tcl/tk form:
why to learn then the R translations of the well known tk commands?
The examples of James Wettenhall are for learning these translations,
perhaps good for someone that do not know tcl/tk and only needs it with R.

We have in R a function as.tclObj() to make objects of class tclObj,
we may make a R list with such objects, like the one generated by
.Tcl.args.objv(), and pass it to the tcl interpreter with .Tcl.objv().
We are calling here tcl from R.

The opposite, with the callbacks, seems not to be possible. We do
not have in the tcl interpreter functions to pass tcl objects as
R objects.

Somethings seems to work:
[1] "R_call 0x80ec1d318 %x %y"

That the arguments x, y of g are translated to %x, %y seems to be intended
for using .Tcl.args(g) as script argument for a bind command in tk.
In this case, for reading mouse coordinates. Look:
[1] "1" "2"
<Tcl>

But is there an "official way" of calling R functions from tcl in R?
Without doing with tcl strange things with the result of .Tcl.callback()
that I would have to pass to the tcl interpreter in some way?

Thanks
Rodrigo