RE: [tcltk-perl] Drop listify [PATCH]
Brought to you by:
hobbs
|
From: Jeff H. <je...@Ac...> - 2004-04-14 16:59:39
|
> "Konovalov, Vadim" <vko...@sp...> writes:
> > To be honest, I did not tried that Jeff's subroutine yet, but why do
> > you think it should not be included?
>
> Because it is dead code which i not needed. Also the 'it is
> also not "comprehensive"' make me think it is actually buggy.
That is correct, it is buggy (given certain input, it will not
produce a 100% correct list), and it isn't used anywhere at the
moment. The xs changes I made alleviate the need - for now.
This touches on stuff that I think requires rethinking in the
whole Tcl module - array/list handling.
The SvFromTclObj and TclObjFromSv procedures that I added allow
for the efficient transformation of data at the object level
between Perl and Tcl. An SvIV becomes a Tcl int object and vice
versa. What is not completely round-tripped are Tcl lists, but
an AV will become a pure Tcl list.
You can see the part in SvFromTclObj where I try to create an
AV back from a Tcl list. The problem with this is that we then
return an array reference, and I think it's complicated by the
code in Tcl.xs:prepare_Tcl_result that handles G_SCALAR and
G_ARRAY differently, in addition to the code in Tcl.pm:call()
that does at the end:
return @res if wantarray;
return $res[0];
Let's make some concrete examples. Here is a code block:
use Tcl;
my $interp = Tcl->new;
my $lres = $interp->Eval("set var [list a b c]"); #1
my $sres = $interp->Eval("set var {a b c}"); #2
my (@lares) = $interp->Eval("set var [list a b c]"); #3
my (@sares) = $interp->Eval("set var {a b c}"); #4
print STDOUT "list: ", $lres, "\n";
print STDOUT "string: ", $sres, "\n";
print STDOUT "litems: ", $_, "\n" for (@lares);
print STDOUT "sitems: ", $_, "\n" for (@sares);
This will currently work "as expected" whether we get a true
(pure) list back from Tcl, or a string that can be broken into
a list. #1 returns a Tcl_Obj of tclListType, whereas #2 returns
just a string (NULL object type). For a small list, the time
difference is negligible, but for 1000 items lists, we should
really be treating it right. The results with current code are:
list: a b c
string: a b c
litems: a
litems: b
litems: c
sitems: a
sitems: b
sitems: c
If you flip on the tclListType conversion (to AV ref) in
SvFromTclObj (there is a #if there), you instead get:
list: ARRAY(0x191ea5c)
string: a b c
litems: a
litems: b
litems: c
sitems: a
sitems: b
sitems: c
and I believe that this may lead to problems (it broke an app
that I was converting from pTk code) where I had this:
my $themes = $interp->Eval("style theme names");
OK, so I really should have this:
my (@themes) = $interp->Eval("style theme names");
but I think making the change leads to issues that force users
to think more about the return value. The above code returns a
pure Tcl list - but the coder could have been lazy and created
a list-like string instead (as many people still do), and it
would all work.
Am I wrong in thinking that users should be forced to code
properly (whether they expect list/array or string/scalar) in
the first place?
I'm also unsure about both $interp->icall and $interp->call
behavior handling G_ARRAY and G_SCALAR differently. See this
difference (this behaves the same whether you do the pure list
conversion or not):
my $res = $interp->call('set', 'var', 'a b c');
my $ires = $interp->icall('set', 'var', 'a b c');
my @ares = $interp->call('set', 'var', 'a b c');
my @iares = $interp->icall('set', 'var', 'a b c');
print STDOUT "call: ", $res, "\n";
print STDOUT "icall: ", $ires, "\n";
print STDOUT "lcall: ", $_, "\n" for (@ares);
print STDOUT "licall: ", $_, "\n" for (@iares);
outputs:
call: a
icall: a b c
lcall: a
lcall: b
lcall: c
licall: a
licall: b
licall: c
but I guess that's an expectation for Perl users (for $res to
grab first element of a list), but when I change to pure list
form in calling convention and use tclListType conversion with:
my @list = $interp->icall('list', 'a', 'b', 'c');
my $res = $interp->call('set', 'var', [@list]);
my $ires = $interp->icall('set', 'var', [@list]);
my @ares = $interp->call('set', 'var', [@list]);
my @iares = $interp->icall('set', 'var', [@list]);
print STDOUT "call: ", $res, "\n";
print STDOUT "icall: ", $ires, "\n";
print STDOUT "lcall: ", $_, "\n" for (@ares);
print STDOUT "licall: ", $_, "\n" for (@iares);
I get:
call: a
icall: ARRAY(0x191e9ec)
lcall: a
lcall: b
lcall: c
licall: a
licall: b
licall: c
again, basically same as above. Is this something that won't
surprise Perl users?
Jeff
|