Ticket UUID: | 3048771 | |||
Title: | tailcall constraints chafe with control command procs | |||
Type: | Bug | Version: | None | |
Submitter: | dgp | Created on: | 2010-08-19 16:20:31 | |
Subsystem: | 45. Parsing and Eval | Assigned To: | msofer | |
Priority: | 5 Medium | Severity: | ||
Status: | Closed | Last Modified: | 2010-08-30 21:08:29 | |
Resolution: | Fixed | Closed By: | msofer | |
Closed on: | 2010-08-30 14:08:29 | |||
Description: |
A celebrated feature of Tcl is the ability to replace built-in commands with functionally equivalent procs. The constraints on [tailcall] diminish that ability. Utility command from TIP 90: % namespace eval control { proc ascaller script { if {[info level] < 2} { return -code error \ "[lindex [info level 0] 0] called outside a proc" } variable result variable options set code [uplevel 2 \ [list ::catch $script [namespace which -variable result] \ [namespace which -variable options]]] if {$code == 0} { return $result } dict incr options -level 2 return -options $options $result } } % proc myIf {cond body} { set bool [control::ascaller [list ::expr $cond]] if {!$bool} return return [control::ascaller $body] } % proc good {} {if 1 {tailcall concat}} % good % proc bad {} {myIf 1 {tailcall concat}} % bad tailcall can only be called from a proc or lambda | |||
User Comments: |
msofer added on 2010-08-30 21:08:29:
allow_comments - 1 Patch committed; mores docs and tests needed: see new ticket #3056056 dgp added on 2010-08-24 20:51:42: One place where this implementation may cause surprise is with commands like [subst] that have their own treatment of TCL_RETURN. proc demo {template} { ... set result [subst $template] .... return $result } demo {[tailcall puts foo]} The [subst] will effectively [catch] the TCL_RETURN. The rest of [demo] will run, and then, possibly long after the [subst], when [demo] returns, its results will get replaced by the results of running [puts foo]. Similar issue is possible with [source]. ferrieux added on 2010-08-22 05:31:57: Note that in such cases the order of execution is sometimes funny, tailcall scheduling something for execution at proc exit, but still disrupting the current sequence within the catch range... (That's just a note, OK once acknowledged) Also note that an alternative would be 'eventually', that does only the scheduling-at-exit part, not the error code: proc f {} { puts AAA eventually g puts BBB } so that the current tailcall would be [eventually ...;return] dgp added on 2010-08-22 00:13:18: File Added - 384146: 3048771.patch dgp added on 2010-08-22 00:12:58: Also broken, though less severely. Uploading a working patch. msofer added on 2010-08-21 21:12:53: File Added - 384134: newTailcall.patch msofer added on 2010-08-21 21:12:30: File Deleted - 384089: msofer added on 2010-08-21 21:12:09: Those patches did not apply - sorry about that. Removed them, new one should be ok. msofer added on 2010-08-21 04:21:06: File Added - 384089: newTailcall2.patch msofer added on 2010-08-21 04:20:23: Better patch, fixes tailcall/coroutine interaction. Different from HEAD, but HEAD was arguably wrong: tailcall-13.1 fails. msofer added on 2010-08-20 07:28:02: File Deleted - 383990: msofer added on 2010-08-20 07:27:49: File Added - 384007: newTailcall.patch msofer added on 2010-08-20 02:45:00: File Added - 383990: diffH msofer added on 2010-08-20 02:44:23: Attached a patch that implements tailcall as returning TCL_RETURN, and where this works ok. Changes in behaviour: - catch stops tailcall, but is not an error. The tailcall is scheduled anyway, and hence it will run unless it is cleared - tailcall with no arguments just clears any tailcall that might have been scheduled - tailcall replaces any previously scheduled tailcall with the new one dgp added on 2010-08-19 23:55:22: Still exploring the space, but currently my preferences is to reduce the amount of new "magic" in the implementation of [tailcall] and let it use return codes like any other command (and interact with [catch] the same way as any other command). Not yet clear whether it needs a new code, or whether TCL_RETURN will do. Miguel has suggested in the chat room that [tailcall] might be revised to become the (near- ?) equivalent of [atProcExit....; return]. Such a revision ought to play well with [catch], [uplevel], etc. But all the implications are not yet laid out. ferrieux added on 2010-08-19 23:49:24: Possibilities: (1) lose trust in [catch]. (2) silently turn [tailcall] into a normal call when crossing a catch boundary, putting a limit on iterations (stack full). (3) automagically detect [catch] when it is at the end of a proc, and allow tailcall to cross it in that case. Preferences ? |