Hi Gisle, thank you a lot for your ideas.
First, I did not liked the name bind_... either. create_commands obviously better. (or maybe create_tcl_commands?) However I think the idea could be extended to variables as well, how do you think, is it possible to leave this name but add functionality to variables also? And having default namespace to be 'perl' also seems reasonable to me. Please see below the code I suggest, it is not finished, but all ideas are expressed. Opinions welcome. Best regards, Vadim. =comment An interpreter method, bind_perl_to_tcl_commands, takes two optional arguments - tcl package name (defaults to 'tcl') and perl package name (defaults to 'tcl') Given a number of Perl sub's in said package, which is passed as the second parameter, binds all of them into tcl, in the said package, which is passed as the first parameter to the bind_perl_to_tcl_commands method. An example: use strict; use Tcl; my $int = new Tcl; $tcl::foo = 'qwerty'; $int->create_tcl_commands(subs_from=>'tcl'); $int->Eval(<<'EOS'); package require Tk button .b1 -text {a fluffy button} -command perl::fluffy_sub button .b2 -text {a foo button} -command perl::foo entry .e -textvariable perl::foo pack .b1 .b2 .e focus .b2 tkwait window . EOS sub tcl::fluffy_sub { print "Hi, I am a fluffy sub\n"; } sub tcl::foo { print "Hi, I am foo\n"; $tcl::foo++; } =cut sub create_tcl_commands { my $int = shift; my %args = @_; # name of Tcl package to hold tcl commands bound to perl subroutines my $tcl_namespace = $args{namespace} || 'perl'; # a batch of perl subroutines which tcl counterparts should be created my $subs = $args{subs} || {}; # name of Perl package, which subroutines would be bound to tcl commands my $subs_from = $args{subs_from}; if ($subs_from) { for my $name (keys %{"$subs_from\::"}) { print STDERR "$name;\n"; if (defined &{"$subs_from\::$name"}) { if (exists $sub->{$name}) { next; } # print STDERR "binding sub '$name'\n"; $int->CreateCommand("$tcl_namespace\::$name",\&{"$subs_from\::$name"}); } if (defined ${"$subs_from\::$name"}) { # print STDERR "binding var '$name'\n"; local $_ = ${"$subs_from\::$name"}; tie ${"$subs_from\::$name"}, 'Tcl::Var', $int, "$tcl_namespace\::$name"; ${"$subs_from\::$name"} = $_; } { # array, hash - no need to. } } } for my $subname (keys %$subs) { $int->CreateCommand("$tcl_namespace\::$subname",$subs{$subname}); } } > -----Original Message----- > From: Gisle Aas [mailto:gi...@activestate.com] > Sent: Tuesday, January 18, 2011 10:08 PM > To: Konovalov, Vadim (Vadim)** CTR ** > Cc: Jeff Hobbs; tcltk@perl.org > Subject: Re: bind some said tcl to perl - all at once > > I don't like to use the name 'bind_...' for this. To me it > sounds like this would bind the namespace together so that > subs created after the call also become visible to Tcl and > perhaps even that commands created on the Tcl side become > visible to Perl. > > My suggestion would be to make a convenience method like this one: > > $interp->create_commands( > namespace => "perl", > subs => { > foo => sub { .... }, > bar => sub { .... }, > } > ); > > where the "namespace" argument is optional. It's the Tcl > namespace where the commands will be created. If not provided > the names will be registered in the root namespace. This > would also always call the underlying $interp->CreateCommand > with FLAGS=1 in order to suppress the confusing initial > legacy arguments. The keys of the subs hash could also use > "::ns::foo" style names in which case the namespace argument > is ignored for that particular key. > > Your use case would then be covered by: > > $interp->create_commands( > namespace => "perl", > subs => \%{"tcl\::"}, > ); > > which is a bit ugly to write so you might be able to provide > some sugar like: > > $interp->create_commands( > namespace => "perl", > subs_from => "tcl", > ); > > if 'subs' and 'subs_from' are provided together they both > contribute; with 'subs' taking preference in case there are > conflicting names. Alternatively croak on conflicting names. > > I would also suggest a 'only => \@list_of_names' argument to > be able to limit the names to export to Tcl. > > Regards, > Gisle > > > > On Jan 18, 2011, at 17:20 , Konovalov, Vadim (Vadim)** CTR ** wrote: > > >> From: Jeff Hobbs [mailto:je...@activestate.com] > >> On 15/01/2011 1:35 PM, Konovalov, Vadim (Vadim)** CTR ** wrote: > >>> I wonder, is it reasonable for this approach to be > >> "standartized" and included to, say, Tcl.pm module? > >>> > >>> For example - all Tcl names from some predefined Tcl > >> namespace could be bound to perl subroutines all at once. > >> > >> I think it would be good to provide this as a standard convenience > >> function, that would tie either a Perl or Tcl namespace to > the other > >> language. I don't think we'd want to pre-define the > namespace (note > >> that Tcl.pm already uses ::perl:: on the Tcl side), but > let the user > >> pick it with a single command invocation. > > > > Indeed, Tcl.pm uses ::perl:: in Tcl::call. > > > > All refs in this namespace have names like > "SCALAR(0xXXXXXX)" or "CODE(0x######)", and it is very > unlikely to have a collision. IOW, the collision could happen > if a user have an intention to create a collision, but he/she > could just create such a collision anyway, by creating > conflicting names using another existing mechanisms. > > > > Ok, below is my suggestion to include to Tcl.pm, > > > > > > =comment > > An interpreter method, bind_perl_to_tcl_commands, takes two optional > > arguments - tcl package name (defaults to 'tcl' and perl > package name > > (defaults to 'tcl') > > > > Given a number of Perl sub's in said package, which is passed as the > > second parameter, binds all of them into tcl, in the said > package, which > > is passed as the first parameter to the > bind_perl_to_tcl_commands method. > > > > An example: > > > > use Tcl; > > > > my $int = new Tcl; > > > > $int->bind_perl_to_tcl_commands; > > > > $int->Eval(<<'EOS'); > > > > package require Tk > > > > button .b1 -text {a fluffy button} -command perl::fluffy_sub > > button .b2 -text {a foo button} -command perl::foo > > pack .b1 .b2 > > > > tkwait window . > > EOS > > > > sub tcl::fluffy_sub { > > print "Hi, I am a fluffy sub\n"; > > } > > sub tcl::foo { > > print "Hi, I am foo\n"; > > } > > > > =cut > > > > sub bind_perl_to_tcl_commands { > > my $int = shift; > > > > # name of Tcl package to hold tcl commands bound to perl > subroutines > > my $tcl_namespace = shift || 'perl'; > > > > # name of Perl package, which subroutines would be bound > to tcl commands > > my $perl_namespace = shift || 'tcl'; > > > > die "Shouldn't bind to main package" > > if $perl_namespace eq "" || $perl_namespace eq "main"; > > > > for my $subname (keys %{"$perl_namespace\::"}) { > > # have no need to check if this is a sub name or a var > name, as long > > # as we're binding to CODE, \&{"..."} > > > $int->CreateCommand("$tcl_namespace\::$subname",\&{"$perl_name > space\::$subname"}); > > } > > } > > > > > > Similar binding of variables could also be added. > > > > Best regards, > > Vadim. > >