string append

APN In 8.6, string cat provides more or less this functionality.

This extends the command string to accept a new sub-command append:

 if {[catch {string append}]} then {
    rename string STRING_ORIGINAL
    proc string {cmd args} {
        switch -regexp -- $cmd {
            ^a(p(p(e(n(d)?)?)?)?)?$ {
                uplevel [list join $args {}]
            }
            default {
                if {[catch {
                    set result [uplevel [list STRING_ORIGINAL $cmd] $args]
                } err]} then {
                    return -code error\
                        [STRING_ORIGINAL map\
                             [list\
                                  STRING_ORIGINAL string\
                                  ": must be bytelength,"\
                                  ": must be append, bytelength,"]\
                             $err]
                } else {
                    set result
                }
            }
        }
    }
 }

Now test it:

% string append ham - and - eggs
ham-and-eggs
%

Now test an "original" sub-command:

% string match -nocase ham and
0
% 

Result is 0 -- indeed, that is true. Now test an erraneous situation:

% string match -nocase ham and eggs
wrong # args: should be "string match ?-nocase? pattern string"
% 

The error message hides the STRING_ORIGINAL and shows up string instead. Another error:

% string brumm
bad option "brumm": must be append, bytelength, compare, (...)
% 

The error message shows the sub-commands inclusive the newly created append.

See also wrapping commands.


Lars H, 28 July 2006: Wouldn't string concat have been a more appropriate name? I know I expected a name involving "concat" for this operation when I was a Tcl beginner (and thus tried some monstrous constructions involving concat when I really only wanted to do [set a "$b$c"]). See also cconcat.

NEM: Yes, string concat would be better. The -append commands also usually operate on a variable rather than simply concatenating arguments (e.g. lappend, append, and the dict variants). Indeed, what is being appended to in this case? Also, what is the uplevel for? Just [join $args {}] would do it.

wdb [join $args {}] does the same, insofar true spoken; but my intention was some syntactical sugar. I always try tho avoid the return statement in every procedure as it is some kind of goto the use of which should not be discussed anymore.

Often enough, my procedures end on a last statement with something like prefix${result}${more}suffix, and the only way to return this seemed to be either use return (see goto above), or use "set result prefix${result}${more}suffix" which obfuscates my intentions.

Being a puristic functional programmer, I prefer some statement the result of which is returned by itself. I want my programs to be human-legible straight downwards without branches.

(Do not believe that I've succeeded this way -- but I'm still trying!)

The idea for the name was based on the Scheme function (string-append str1 str2 ...). As a native German speaker, I was more comfortable with the word append than with concatenate ... but, if everybody agrees, I'll be happy to change the name of the sub-cmd from string append to string concat. I'm more interested in what it does than how it is named.


DKF: In Tcl 8.5 onwards, there is an easier way:

namespace ensemble configure string -map \
        [dict replace [namespace ensemble configure string -map] \
        append {::apply {args {join $args ""}}}]