Error processing request

Parameters

CONTENT_LENGTH0
REQUEST_METHODGET
REQUEST_URI/revision/lreplace?V=35
QUERY_STRINGV=35
CONTENT_TYPE
DOCUMENT_URI/revision/lreplace
DOCUMENT_ROOT/var/www/nikit/nikit/nginx/../docroot
SCGI1
SERVER_PROTOCOLHTTP/1.1
HTTPSon
REMOTE_ADDR172.69.7.182
REMOTE_PORT61390
SERVER_PORT4443
SERVER_NAMEwiki.tcl-lang.org
HTTP_HOSTwiki.tcl-lang.org
HTTP_CONNECTIONKeep-Alive
HTTP_ACCEPT_ENCODINGgzip, br
HTTP_X_FORWARDED_FOR3.140.198.43
HTTP_CF_RAY879d7ba51d056165-ORD
HTTP_X_FORWARDED_PROTOhttps
HTTP_CF_VISITOR{"scheme":"https"}
HTTP_ACCEPT*/*
HTTP_USER_AGENTMozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
HTTP_CF_CONNECTING_IP3.140.198.43
HTTP_CDN_LOOPcloudflare
HTTP_CF_IPCOUNTRYUS

Body


Error

Unknow state transition: LINE -> END

-code

1

-level

0

-errorstack

INNER {returnImm {Unknow state transition: LINE -> END} {}} CALL {my render_wikit lreplace {'''[http://www.tcl.tk/man/tcl/TclCmd/lreplace.htm%|%lreplace]''' replaces or
deletes elements in a [list], and can also prepend elements to a list.



** Documentation ** 

   [http://www.tcl.tk/man/tcl/TclCmd/lreplace.htm%|%man page]:   


** Synopsis **

    :   '''lreplace''' ''list first last'' ?''element element ...''?


** Description **

'''lreplace''' returns a new list formed by replacing one or more elements of
''list'' with the ''element'' arguments. ''first'' gives the zero-based index
in ''list'' of the first element to be replaced. If ''first'' is less than zero
then it is interpreted as zero. ''first'' must correspond to the index of an
existing element in ''list''. ''Last'' gives the index in ''list'' of the last
element to be replaced. If ''last'' is less than ''first'' then no elements are
deleted; the new elements are simply inserted before ''first''.  ''first'' or
''last'' may be '''`end`''' (or any abbreviation of it), which denotes the last
element of the list. 

Each ''element'' is added to the list in place of those that are deleted.  If
''element'' arguments are not specified, then the elements between first and last
are simply deleted.



** Examples **

======none
% lreplace {a b c} 0 0 @
@ b c
% lreplace {a b c} 1 1 
a c
% lreplace {a b c} 1 1 hello there
a hello there c




** Performance: Modifying a List In-Place **

If  `lreplace` is handed an unshared list, it will grab the opportunity to
modify the list in place, avoiding the processing overhead of making the copy,
and the additional memory usage of the copy.  The problem with the following
example is that `$l` is shared:

======
set l [lreplace $l $j $j $newvalue]
======

The value of `$l` is bound to `$l` in the caller of `lreplace`, making it
shared, so `lreplace` must copy the value before it can modify it.  To unshare
the value, set `$l` to the empty string after obtaining its value, and before
`lreplace` is actually invoked, i.e., sometime later on the command line:

======
set l [lreplace $l[set l {}] $j $j $newvalue]
======

Tcl substitutes the value `$l`, and then appends the empty string to that
value, except that it doesn't, because appending the empty string is a no-op.
In the meantime, thanks to `[set]`, `$l` is no longer bound to that value, so
that value is unshared.  When `lreplace` is finally called, it the value is no
longer shared. `[unset] l` would also work, but would be slower because of the
additional overhead of unsetting a variable.


In older versions of Tcl, before appending the empty string was a no-op, [K]
was used:

======
set l [lreplace [K $l [set l {}]] $j $j $newvalue]
======

Set also [Shuffle a list] and [lset]

The following procedure accomplishes the same thing:

======
proc lipreplace {_list first last args} {
    upvar $_list list
    set list [lreplace $list[set list {}] $first $last {*}$args]
}
======

======none
% set A [list 1 2 3]
1 2 3
% lipreplace A 1 end c d
1 c d
======



** Performance; Shifting Subsequent Items **

It's more expensive to replace items toward the front of the list.  If
`lreplace` causes the size of the list to change, all remaining items in the
list must be shifted up or down to accomodate the new size.  Therefore, when
iterating through a list of lists and deleting items, designing the process so
that items toward the end of the list are replaced first can have a big speed
benefit.  For example, the list could be iterated from back to front:

======
for {set i [expr {[llength $list]-1}]} {$i >= 0} {incr i -1} {
    set list [lreplace $list[set list {}] $i $i]
}

======



** Prepend, Yes, Append, No **

[AMG]: While `lreplace` can be used to prepend elements to the beginning of a
list, it cannot be used to append elements to the end of a list.

======
lreplace {0 1 2} 0 -1 x y z
→ x y z 0 1 2
lreplace {0 1 2} end -1 x y z
→ 0 1 x y z 2
lreplace {0 1 2} end+1 -1 x y z
→ error: list doesn't contain element end+1
======

The documentation says "if ''last'' is less than ''first'', then any specified
elements will be inserted into the list at the point specified by ''first''
with no elements being deleted."  Like `[lindex]`, it refers to `[string
index]` for an explanation of the index notation and interpretation, so
'''end''' is the last element, which is '''2''' in this case.

Clearly, the insertion takes place ''just before'' the ''first'' element, even
when ''first'' is '''end'''-relative.  This is inconsistent with `[linsert]`,
which (despite the documentation) inserts ''just after'' the ''index'''th
element when ''index'' is '''end'''-relative.

It is also inconsistent that `[lreplace]` accepts indexes before the beginning
of the list but rejects indexes after the end of the list.  `[linsert]` accepts
out-of-bounds indexes in either direction.

By the way, to prepend and append individual elements or entire lists to a
list, several combinations of `[concat]`, `[list]`, and [{*}] can be used.  Or
if in-place modification is desired, use `[lappend]` with or without [{*}], or
use `[lset]` one element at a time.  For example, all of the following
combinations return `x y 0 1`:

======
set elem1 0; set elem2 1
set list1 {x y}; set list2 {0 1}
======

%| | |%
&| Combine lists and elements using '''concat''' and '''list''' | `concat $list1 [[list $elem1]] [[list $elem2]]` |&
&| Combine lists using '''concat'''                             | `concat $list1 $list2` |&
%| | |%
&| Combine lists and elements using '''list''' and '''{*}'''    | `list {*}$list1 $elem1 $elem2` |&
&| Combine lists using '''list''' and '''{*}'''                 | `list {*}$list1 {*}$list2` |&
%| | |%
&| Append elements to a list using '''lappend'''                | `lappend list1 $elem1 $elem2` |&
&| Append a list to a list using '''lappend''' and '''{*}'''    | `lappend list1 {*}$list2` |&
%| | |%
&| Append elements to a list using '''lset'''                   | `lset list1 end+1 $elem1; lset list1 end+1 $elem2` |&
%| | |%
    :   


[PYK] 2016-04-14:  (Note: The documentation has been changed to say "... before
the point specified by ''first'' with no elements being deleted.").  Another
way to describe the behaviour of `linsert` is to say that when it's given an
end-relative index, it approaches the list from the end, and from that
perspective, inserting a value ''just before the index'th element of list''
means inserting it prior to the first item it encounters, which is last item in
the list.  If anything, `linsert` is the "inconsistent" one among the list
commands, but it's a useful inconsistency.

`lreplace` is more oriented towards ensuring that no elements beyond the last
index it's given are replaced.  That "beyond" idea makes switching orientation
like `linsert` does less appealing.  In the case of a range like `end -1`,
appending to the list wouldn't be very consistent with its behaviour for more
common ranges that specify a non-negative width, replacing the last element
wouldn't be very consistent either, since the range has no width, and replacing
the entire list is unlikely to be what was desired, so it does what seems most
sensible.



** Bounds Checking **

[escargo] 2005-09-15:  Perhaps there is a better place for the following
discussion, but this is where I saw a specific feature mentioned that I want to
raise an issue about.

'''List commands bounds checking and associated behavior'''

The description above states (in part):
"If ''first'' is less than zero then it refers to the first element of ''list''."

I see two problems with this:

   * What should the behavior be when indexing outside the bounds of a list?
   * How does this behavior vary from other list operations?

Personally, I see allowing negative indexes (''first'' or ''last'') to be
errors, and ones that are ''silent failures'' at that.  (This is unlike [Icon
Programming Language%|%Icon] where at least some negative indexes have
semantically valid meaning.)  Perhaps list operations that do indexing should
have a '''-strict''' option so that if indexes are outside the proper ranges,
errors would be thrown.

On the second issue, [lindex] allows negative indexes (and indexes greater than
the length of the list), but returns no values.  The negative index is not
coerced to zero. Thus the same index value (a negative one) refers to no
element with [lindex] but the zeroth element with lreplace.  Perhaps an item
for the [Tcl 9.0 WishList] would be consistent behavior for [list] and [string]
indexing semantics.



** Misc **

If the ''last'' argument of lreplace was made optional, one could essentially
just alias ldelete to lreplace [CmCc]

[AMG]: I assume your suggestion is that omitting the ''last'' argument (plus
all the ''element'' arguments to follow, of course) be taken to mean that the
element at index ''first'' be removed from the output list.  This seems
reasonable to me.

My kneejerk complaint is that the name `lreplace` doesn't seem suitable for
this usage, but this complaint already applies to the current case of omitting
all ''element'' arguments, so no new naming problem is introduced.



** See Also**

   [linsert]:   

   [lappend]:   

   [list]:   


<<categories>> Command} regexp2} CALL {my render lreplace {'''[http://www.tcl.tk/man/tcl/TclCmd/lreplace.htm%|%lreplace]''' replaces or
deletes elements in a [list], and can also prepend elements to a list.



** Documentation ** 

   [http://www.tcl.tk/man/tcl/TclCmd/lreplace.htm%|%man page]:   


** Synopsis **

    :   '''lreplace''' ''list first last'' ?''element element ...''?


** Description **

'''lreplace''' returns a new list formed by replacing one or more elements of
''list'' with the ''element'' arguments. ''first'' gives the zero-based index
in ''list'' of the first element to be replaced. If ''first'' is less than zero
then it is interpreted as zero. ''first'' must correspond to the index of an
existing element in ''list''. ''Last'' gives the index in ''list'' of the last
element to be replaced. If ''last'' is less than ''first'' then no elements are
deleted; the new elements are simply inserted before ''first''.  ''first'' or
''last'' may be '''`end`''' (or any abbreviation of it), which denotes the last
element of the list. 

Each ''element'' is added to the list in place of those that are deleted.  If
''element'' arguments are not specified, then the elements between first and last
are simply deleted.



** Examples **

======none
% lreplace {a b c} 0 0 @
@ b c
% lreplace {a b c} 1 1 
a c
% lreplace {a b c} 1 1 hello there
a hello there c




** Performance: Modifying a List In-Place **

If  `lreplace` is handed an unshared list, it will grab the opportunity to
modify the list in place, avoiding the processing overhead of making the copy,
and the additional memory usage of the copy.  The problem with the following
example is that `$l` is shared:

======
set l [lreplace $l $j $j $newvalue]
======

The value of `$l` is bound to `$l` in the caller of `lreplace`, making it
shared, so `lreplace` must copy the value before it can modify it.  To unshare
the value, set `$l` to the empty string after obtaining its value, and before
`lreplace` is actually invoked, i.e., sometime later on the command line:

======
set l [lreplace $l[set l {}] $j $j $newvalue]
======

Tcl substitutes the value `$l`, and then appends the empty string to that
value, except that it doesn't, because appending the empty string is a no-op.
In the meantime, thanks to `[set]`, `$l` is no longer bound to that value, so
that value is unshared.  When `lreplace` is finally called, it the value is no
longer shared. `[unset] l` would also work, but would be slower because of the
additional overhead of unsetting a variable.


In older versions of Tcl, before appending the empty string was a no-op, [K]
was used:

======
set l [lreplace [K $l [set l {}]] $j $j $newvalue]
======

Set also [Shuffle a list] and [lset]

The following procedure accomplishes the same thing:

======
proc lipreplace {_list first last args} {
    upvar $_list list
    set list [lreplace $list[set list {}] $first $last {*}$args]
}
======

======none
% set A [list 1 2 3]
1 2 3
% lipreplace A 1 end c d
1 c d
======



** Performance; Shifting Subsequent Items **

It's more expensive to replace items toward the front of the list.  If
`lreplace` causes the size of the list to change, all remaining items in the
list must be shifted up or down to accomodate the new size.  Therefore, when
iterating through a list of lists and deleting items, designing the process so
that items toward the end of the list are replaced first can have a big speed
benefit.  For example, the list could be iterated from back to front:

======
for {set i [expr {[llength $list]-1}]} {$i >= 0} {incr i -1} {
    set list [lreplace $list[set list {}] $i $i]
}

======



** Prepend, Yes, Append, No **

[AMG]: While `lreplace` can be used to prepend elements to the beginning of a
list, it cannot be used to append elements to the end of a list.

======
lreplace {0 1 2} 0 -1 x y z
→ x y z 0 1 2
lreplace {0 1 2} end -1 x y z
→ 0 1 x y z 2
lreplace {0 1 2} end+1 -1 x y z
→ error: list doesn't contain element end+1
======

The documentation says "if ''last'' is less than ''first'', then any specified
elements will be inserted into the list at the point specified by ''first''
with no elements being deleted."  Like `[lindex]`, it refers to `[string
index]` for an explanation of the index notation and interpretation, so
'''end''' is the last element, which is '''2''' in this case.

Clearly, the insertion takes place ''just before'' the ''first'' element, even
when ''first'' is '''end'''-relative.  This is inconsistent with `[linsert]`,
which (despite the documentation) inserts ''just after'' the ''index'''th
element when ''index'' is '''end'''-relative.

It is also inconsistent that `[lreplace]` accepts indexes before the beginning
of the list but rejects indexes after the end of the list.  `[linsert]` accepts
out-of-bounds indexes in either direction.

By the way, to prepend and append individual elements or entire lists to a
list, several combinations of `[concat]`, `[list]`, and [{*}] can be used.  Or
if in-place modification is desired, use `[lappend]` with or without [{*}], or
use `[lset]` one element at a time.  For example, all of the following
combinations return `x y 0 1`:

======
set elem1 0; set elem2 1
set list1 {x y}; set list2 {0 1}
======

%| | |%
&| Combine lists and elements using '''concat''' and '''list''' | `concat $list1 [[list $elem1]] [[list $elem2]]` |&
&| Combine lists using '''concat'''                             | `concat $list1 $list2` |&
%| | |%
&| Combine lists and elements using '''list''' and '''{*}'''    | `list {*}$list1 $elem1 $elem2` |&
&| Combine lists using '''list''' and '''{*}'''                 | `list {*}$list1 {*}$list2` |&
%| | |%
&| Append elements to a list using '''lappend'''                | `lappend list1 $elem1 $elem2` |&
&| Append a list to a list using '''lappend''' and '''{*}'''    | `lappend list1 {*}$list2` |&
%| | |%
&| Append elements to a list using '''lset'''                   | `lset list1 end+1 $elem1; lset list1 end+1 $elem2` |&
%| | |%
    :   


[PYK] 2016-04-14:  (Note: The documentation has been changed to say "... before
the point specified by ''first'' with no elements being deleted.").  Another
way to describe the behaviour of `linsert` is to say that when it's given an
end-relative index, it approaches the list from the end, and from that
perspective, inserting a value ''just before the index'th element of list''
means inserting it prior to the first item it encounters, which is last item in
the list.  If anything, `linsert` is the "inconsistent" one among the list
commands, but it's a useful inconsistency.

`lreplace` is more oriented towards ensuring that no elements beyond the last
index it's given are replaced.  That "beyond" idea makes switching orientation
like `linsert` does less appealing.  In the case of a range like `end -1`,
appending to the list wouldn't be very consistent with its behaviour for more
common ranges that specify a non-negative width, replacing the last element
wouldn't be very consistent either, since the range has no width, and replacing
the entire list is unlikely to be what was desired, so it does what seems most
sensible.



** Bounds Checking **

[escargo] 2005-09-15:  Perhaps there is a better place for the following
discussion, but this is where I saw a specific feature mentioned that I want to
raise an issue about.

'''List commands bounds checking and associated behavior'''

The description above states (in part):
"If ''first'' is less than zero then it refers to the first element of ''list''."

I see two problems with this:

   * What should the behavior be when indexing outside the bounds of a list?
   * How does this behavior vary from other list operations?

Personally, I see allowing negative indexes (''first'' or ''last'') to be
errors, and ones that are ''silent failures'' at that.  (This is unlike [Icon
Programming Language%|%Icon] where at least some negative indexes have
semantically valid meaning.)  Perhaps list operations that do indexing should
have a '''-strict''' option so that if indexes are outside the proper ranges,
errors would be thrown.

On the second issue, [lindex] allows negative indexes (and indexes greater than
the length of the list), but returns no values.  The negative index is not
coerced to zero. Thus the same index value (a negative one) refers to no
element with [lindex] but the zeroth element with lreplace.  Perhaps an item
for the [Tcl 9.0 WishList] would be consistent behavior for [list] and [string]
indexing semantics.



** Misc **

If the ''last'' argument of lreplace was made optional, one could essentially
just alias ldelete to lreplace [CmCc]

[AMG]: I assume your suggestion is that omitting the ''last'' argument (plus
all the ''element'' arguments to follow, of course) be taken to mean that the
element at index ''first'' be removed from the output list.  This seems
reasonable to me.

My kneejerk complaint is that the name `lreplace` doesn't seem suitable for
this usage, but this complaint already applies to the current case of omitting
all ''element'' arguments, so no new naming problem is introduced.



** See Also**

   [linsert]:   

   [lappend]:   

   [list]:   


<<categories>> Command}} CALL {my revision lreplace} CALL {::oo::Obj783647 process revision/lreplace} CALL {::oo::Obj783645 process}

-errorcode

NONE

-errorinfo

Unknow state transition: LINE -> END
    while executing
"error $msg"
    (class "::Wiki" method "render_wikit" line 6)
    invoked from within
"my render_$default_markup $N $C $mkup_rendering_engine"
    (class "::Wiki" method "render" line 8)
    invoked from within
"my render $name $C"
    (class "::Wiki" method "revision" line 31)
    invoked from within
"my revision $page"
    (class "::Wiki" method "process" line 56)
    invoked from within
"$server process [string trim $uri /]"

-errorline

4