[Sarnold] -- 2005/12/13 Typically, when you do some list processing, you can use the [foreach] command which is efficient, but a construct like: for {set i 0} {$i<[llength $mylist]} {incr i} {...} is slow because it has to call [llength] at each iteration. I admit it is not new. So a construct like : for {set i 0;set len [llength $mylist]} {$i<$len} {incr i} {...} would be faster, but less readable as there is a new variable that does not mean anything in the rest of the program. ''[MG] Can you not just do something like this:'' for {set i 0} "\$i < [llength $myList]" {incr i} {...} ''so that the llength is only evaluated once (at the very beginning), and it's result is used in future (for each loop)?'' In [Python], you can get more speed by the range() function: for i in range(l.length): # some code I submit a new command called ''foriter'' that mimics Python's functionality: foriter loopvar ?start? end ?increment? body loopvar - the name of a variable (existing or not) that holds the counter start - defaults to 0 increment - defaults to 1 Then, foriter i start end increment body is equivalent to: for {set i $start} {$i<$end} {incr i $increment} $body Some benchmarks show that it is faster than [for] in many cases. ---- [KPV] Two comments: first, calls to [[llength]] are extremely fast, probably just as fast as a variable assignment. Second, I bet that most of the time when a loop goes from 0 to [[llength...]] there will be, very early in the loop body, a call to [[lindex...]]. Thus, I believe that the construct that is really needed is a variation on '''foreach''' so that it has a counter variable. [Sarnold] You are right, a '''foreach''' alternative is certainly better. But I still find Python's syntax appealing because it adds sugar. Well, every programmer has been tought the '''for''' syntax early in his/her trainings, but I am *bored* with this syntax because I have to type too much. That is the major reason. ---- ''Here is an implementation in C:'' critcl::ccode { #include } package provide Foriter 0.1 critcl::ccommand foriter {dummy interp objc objv} { int result; /* foriter loop : from start to end-1 increment by do */ Tcl_Obj *obj_body = NULL; /* the int values of the loop range */ int start = 0; int end; int increment = 1; /* the name of the variable to set the counter */ char *counter_name = NULL; if (objc<4 || objc>6) { Tcl_WrongNumArgs(interp, 1, objv, "foriter varname ?start? end ?increment? body"); return TCL_ERROR; } if (objc == 4) { result = Tcl_GetIntFromObj(interp, objv[2], &end); if (result != TCL_OK) { return result; } obj_body = objv[3]; } else { /* the user provided 'start' as 2nd argument, and the 'end' of the range is then the 3rd argument */ result = Tcl_GetIntFromObj(interp, objv[2], &start); if (result != TCL_OK) { return result; } result = Tcl_GetIntFromObj(interp, objv[3], &end); if (result != TCL_OK) { return result; } if (objc == 5) { obj_body = objv[4]; } else { obj_body = objv[5]; } } if (objc == 6) { result = Tcl_GetIntFromObj(interp, objv[4], &increment); if (result != TCL_OK) { return result; } } Tcl_LinkVar(interp, counter_name=Tcl_GetString(objv[1]), &start, TCL_LINK_INT); if ((end-start) * increment < 0) { /* the iterating range goes the other way than incrementation does */ Tcl_SetObjResult(interp, Tcl_NewStringObj( "invalid range : an endless loop would occur", -1)); return TCL_ERROR; } /* please note that a negative increment could be used (I wonder if one shall do so ?) now, the loop begins */ for ( ; (increment > 0)? (start < end): (start > end) ; ) { /* we are into the loop */ /* printf("."); */ result = Tcl_EvalObjEx(interp, obj_body, 0); if ((result != TCL_OK) && (result != TCL_CONTINUE)) { if (result == TCL_ERROR) { Tcl_SetObjResult(interp, Tcl_NewStringObj( "error in foriter body", -1)); /* when an error occurs, we quit the loop and clean up things like References */ break; } /* when the user breaks the evaluation we have to break out of the loop */ break; } /* updating the integer value */ start += increment; Tcl_UpdateLinkedVar(interp, counter_name); } Tcl_UnlinkVar(interp, counter_name); if (result == TCL_ERROR) { return result; } Tcl_ResetResult(interp); return TCL_OK; } ---- [Category Critcl]