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 |