Also cc'd to tcltk@perl.org
https://www.nntp.perl.org/group/perl.tcltk/2018/07/msg718.html
per Vadim's request
At 09:07 AM 7/3/2018, you wrote:
<URL: https://rt.cpan.org/Ticket/Display.html?id=125472 >
Thank you for the prompt and detailed response.
> I added comments to the tests i added to t/ to document the problems
> i noticed with the v1.05 process that you may find helpful to read.
>
> I found that others were already using the create_tcl_sub() entry
> even though it was not documented. And i found that the description
> of CreateCommnd() to be confusing to me as well.
I think someone uses the internal function does not necessary mean
that the function has to be exposed by document. The difference is:
If a module user uses undocumented internal function, he/she takes
the risk of function robustness and compatibility on module
revision. On the other hand, if a module document a function as an
API, the module shall take response that both interface and behavior
should not change in the future.
I agree that documented interfaces should continue to work as
documented, but that does not mean they must stay static, it just
means they should not bust any pervious uses.
After looking at tcl.pm/.xs it was clear to me that create_tcl_sub()
should be the preferred method for introducing code to tcl because
CreateCommand() was so vaguely documented and its arguments are very
specific to the tcl interface and can cause bigger problems is used
improperly.
create_tcl_sub() takes care of much of the needed background
processing needed to properly create a tcl<=>perl subroutine such as
placeing it into the proper namespace and returing the tcl name in
that namespace. it also populates the tracking structure such that
further uses of a static coderef will not repopulate the tcl
subroutine internal reference (in v1.02- and v1.06+ at least) if it
is found a second time by call().
> Since create_tcl_sub() is what was used in call(), and that was that
> pair where the code needed to be patched i thought it made sense to
> document how create_tcl_sub() worked and how code disposal worked
> within it. IMHO it made sense to expose create_tcl_sub() so that
> programmers could use the automatic recoding of a call(,,$coderef)
> process as well as being able to control when code disposal took
> place if they wanted to handle it themselves. This allows them to
> continue to use coderefs if they want and just delete one use by
> using DESCRNAME, or all clear it totally by using TCLNAME.
Yes, it makes sense to document how internal mechanism works, but
again it does not mean create_tcl_sub() has to be documented so
detail and as a part of API.
> I think i made it clear that the user supplied DESCRNAME can be
> anything they want it to be, as long as it does not begin with '='
> or '@', or '::perl::'.
> '=' now prefaces "normal" entries created by create_tcl_sub().
> '@' prefaces entries create_tcl_sub() will use to possibly dispose of
> coderefs "AT" a future time since they were used by an after command.
> and '::perl::' prefaces the TCLNAME assigned by create_tcl_sub() and
> is used in anon_refs{} to determine when no more "users" exist and
> the coderef can now be safely deleted from the tcl namespace.
Okay, I finally get the the point of DESCRNAME usage now. I did not
know that DESCRNAME can be passed to _code_dispose() so I did not
get the purpose of DESCRNAME at all. I suggest to have more explicit
description that argument of _code_dispose() is either TCLNAME or
DESCRNAME. And the major purpose of DESCRNAME is used to pass to
_code_disposal().
I get your point more, but I still think we shall properly define
the interface to support code disposal instead of just directly
expose an internal function out. For example, how about modify
call() to support the form of call(DESCRNAME, cmd, arg ...), where
DESCRNAME is optional and is a string that with '@' prefix. Then we
have a good compatibility and user do not have to worry about
GENCODE, EVENTS etc.
The main purpose of DESCRNAME is to name the slot used in $anon_refs
to store information about the tcl<=>perl subroutine linkage and
track it. Just one of the purposes of tracking is to be able to
dispose of it later.
I do not understand why you mean to accomplish by modifying call()
that way, how would call understand that it is a descrname and not a tcl verb?
The @ prefix was selected to identify a group of coderefs that
might be able to be deleted by a call() generated "after" call to
_code_dispose once the initiating "after" call has completed. For
the most part $anon_refs keys beginning with '@" should be very short
lived transients. I think adding another use for the '@' prefix would
be counterproductive. And a call() can also have more than one
coderef in its args as call('if','1',$sub1,$sub2) illustrates.
The documentation for Tcl::_code_destroy(NAME) already states
>calling _code_destroy on a TCLNAME retruned from create_tcl_sub
removes all use instances and purges the command table.
>calling _code_destroy on a DESCRNAME passed to create_tcl_sub
removes only that instace
>Code used in a DESCRNAME may be used in other places as well,
>only when the last usage is purged does the entry get purged from
the command table
I think that is a pretty good description of its modes, but if you
can suggest a better description you are free to have a go at it.
I can understand why you think that EVENTS should be hidden better,
and then GENCODE as well, but both of them were well integrated into
the existing code and i did not want to break that. I can also see
cases where a user may want to use the EVENTS parm tho, and in that
case they would want both the TCLNAME and GENCODE returned, so i
introduced a change to what was returned to allow for that. Existing
code expecting a scalar to be returned still gets GENCODE as it did
before, but new code expecting an array can get both of them. And
uless EVENTS was populated both are the same anyway.
> > 2) The newest POD in github HEAD mentioned
> >
> > $interp->call('fileevent','sock9827430','writable');
> >
> > won't dispose the sub created from
> >
> > $interp->call('fileevent','sock9827430', 'writable'=>sub{...});
> >
> > is it still true? Or only 'set' command behaves in this way?
>
> yes this is still true, it was true in v1.02 and v1.05 and reverted
> back to that behavior in v1.11. at v1.06 i had tried to make it so
> the first call would cause code disposal of the sub created by the
> second, but that was what broke your "set foo" tests. At the time i
> introduced that behavior i thought it made sense to try to initiate
> code disposal in those cases, to keep the internal table and tcl
> namespace clean, but after spending some time trying to decide if
> "set foo" was the only place this should be avoided i decided that
> it was safer to revert to the original processing where code
> disposal would only be triggered if there was a different coderef in
> the new call. but not when the coderef was now missing.
>
> I wrapped the place where it occurs with a flag so it could be
> reinstated if desired when it was determined that only "set foo"
> should be handled in this special manner
Too bad that it is disabled by default. IMO
'$interp->call("FILEEVENT" ... "WRITABLE=>"")' shall be a suggested
way to dispose the code and well documented. 'set' command is an
exception and to be documented. Of course there are other exceptions
to be found out. The flag SAVENOCODE might be better documented in POD too.
i did not document SAVENOCODE nor SAVEALLCODES because i feel both to
be transient flags destined to be deleted when the tcl.pm code is solidified.
both serve to temporarily encapsulate code i felt to be useful but
might not deserve to be in the final code, and allow the encapsulated
code to be toggled on/off to see how it works in different
situations. If you look at where both are used i think you will find
that i did document what i was trying to do when i introduced the
code they encapsulate. Again if you think you can explain it better
please feel free to do so.
i am not a fan of "Of course there are other exceptions to be found
out." methods. It disgusted me greatly that my introduction of the
code to deal with '$interp->call("FILEEVENT" ... "WRITABLE=>"")' (or
its bind cousins) busted the "set foo" test in Tkx.pm. I hate to
bust existing working code and feel it diminishes my reputation as a
responsible programmer when i do so.
I would rather shut it off for now, reverting to the existing process
in v1.02/v1.05 than to play catchup to bug reports stating it busted
something else. I have been thru much of the tcl/tk documentation
looking for other cases the newer behavior may also break but so far
have only identified the "set foo" instance, but that does not mean
no other cases still exist and would rather revert to the previous
behavior until i can be assured that the "set foo" instance is the
only one to be exempted rather than bust someone elses code and
require them to figure out how to file a bug report about it. When
we are assured that the code will do what we want it is a simple
matter to remove the encapsulation and delete the transient flags.
SJ
This new code disposal process is opening a can of worms, but that
does not mean it cannot be accomplished successfully. As i was
working on the reference counting i imagined inserting a new code
disposal method that could clean up after a deleted tk element,
searching the keys of %anon_refs for keys prefixed with '='
(internally generated) and tracking button/bind/menu objects related
to a element name specified as a parameter. It could then dispose of
them in the normal method, freeing any that are no longer referenced.
while i did not think i should being this up until the code disposal
code has stabilized more, i think now is not a bad time to mention it
as it serves to solidify the direction i think code_disposal should
proceed in.