I am using an overloaded version of the StringJoin function since years now, without any problem, as I've invested a lot of time and effort earlier to make its behaviour consistent and predictable (see discussion here). I am fully aware that modifying built-in symbols is not a good idea.

The new StringJoin automatically converts any non-string input to String thus I don't have to type ToString every time. It still threads over lists, i.e. StringJoin[{"1", "2", "3"}] returns "123". Also StringJoin[{1, 2, 3}] returns the same, but StringJoin[{1, 2, 3}, "s"] gives "{1, 2, 3}s". The code is:

toString[expr_String] := expr;
toString[expr_] := ToString@expr;
Attributes[System`StringJoin] = {};
System`StringJoin[expr___] := StringJoin@{expr};
System`StringJoin[expr_List] := 
  Fold[StringInsert[#1, toString@#2, -1] &, "", expr];

For me, it works as expected, and I am really happy to use it as it saves me a lot of typing. Though there is one minor annoyance I cannot track down. Consider the following example:

Append[test, 1];

Mathematica graphics

Note, that the message is printed with List-s wrapping each argument of the printed StringForm (that is: 1 and Append[test, 1]). Interestingly, StringForm on its own works as expected:

StringForm["Test variable insertion: `1`, `2`.", 111, 222]

Mathematica graphics

Question: Can anyone explain why Message fails to print its result correctly?


Modifying System` symbols could have many unexpected side-effects. It happens for this modified StringJoin too (apart from the above example): as Import uses StringJoin, the modification causes a massive performance drop when importing e.g. images. For details, see this post.


2 Answers 2


Short answer: because StringJoin has this little-known behavior normally:

StringJoin["abc", {"def"}, "ghi"]

  ==> "abcdefghi"

while after you overloaded it, the result is


Long answer

You start by using

Trace[Append[test, 1], TraceInternal -> True]

from the Trace output, you can locate the following code:

StringJoin[(If[ListQ[#1], StringJoin["\[NoBreak]", #1, "\[NoBreak]"],  #1] & ) /@ 
       "Nonatomic expression expected at position `1` in `2`.", 
        System`Dump`del : "`" ~~ DigitCharacter ... ~~ "`" :> 


"Nonatomic expression expected at position \[NoBreak]{`}\[NoBreak] in \[NoBreak]{`}\[NoBreak]."

Analyzing this code leads to the short answer above.


Don't overload built-ins globally. Who knows what else you will break? There are other options to do what you want. For example, you can use Internal`InheritedBlock to create local environments, as explained e.g. here.

  • $\begingroup$ Pardon me, but it is not my fault if I mess up something that is not documented at all (though I will suffer the consequences). Generally I never modify anything that's built-in, but this function proved really useful throughout the years. Of course it's a PITA when you have to deploy packages to others... $\endgroup$ Commented Feb 6, 2012 at 14:44
  • $\begingroup$ So, Leonid, I guess you highly DO NOT recommend to put a Flatten in the 6th line to read: System`StringJoin[expr_List] := Fold[StringInsert[#1, toString@#2, -1] &, "", Flatten@expr]; $\endgroup$ Commented Feb 6, 2012 at 14:56
  • 4
    $\begingroup$ @Istvan The problem is that the system itself is using many of its own functions, to implement other functions. And Mathematica as a language does not have a formal specification, and is defined by its single implementation. In practice, I think it is just not possible to anticipate all the consequences of your modifications for such a huge system. Even in your example, the problem happened in a rather unexpected place, and only because you overloaded a single function, you could make a connection. Overload many, and it will go off hand. This is just my opinion, of course. $\endgroup$ Commented Feb 6, 2012 at 16:17
  • 4
    $\begingroup$ @IstvánZachar The behavior of StringJoin when given lists is documented in the third Basic Example, even if it's not under More Information. $\endgroup$ Commented Feb 6, 2012 at 18:46
  • 1
    $\begingroup$ @BrettChampion: indeed, I did realize that later. @Leonid: Not at all, since I don't use StringJoin in heavy computation. Moreover, my question was answered perfectly :) $\endgroup$ Commented Feb 7, 2012 at 8:59

I agree that a user needs to proceed with caution when modifying System` functions. However, once a long time ago I saw a Wolfram Research tech-support web-page that provided a way to overload a System function to patch a bug. My code below uses the same trick which is very neat!

$modifyStringJoin = True;
wasProtected = Unprotect[StringJoin];

StringJoin[args__] /; $modifyStringJoin := Block[{$modifyStringJoin},
      StringJoin[Map[ToString, Flatten[{args}], Heads -> False]]

Apply[Protect, wasProtected, Heads -> False];

This version has linear complexity. Also, if you ensure $modifyStringJoin is not True, the code above is disabled.

---- Going off on a tangent -----

Using Apply[Protect, wasProtected] ensures ToString is Protected 'if and only if' it was protected before evaluating the code above.

Notice I use the InputForm of Map, Apply, and I include (Heads->False). I always do this to ensure my code is not brokent if somebody evaluates

   SetOptions[Map, Heads->True];

However, I don't know what system code would be broken if you do that!

Imagine what would happen to the system code if you evaluate

Attributes[Plus, {Flat, Listable, NumericFunction, OneIdentity, Orderless}];

or if you overload ReplacePepeated!


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.