It is quite interesting why StringJoin does not apply ToString to those arguments which are non-string. I've overridden the built-in StringJoin, to save a few unnecessary ToStrings by the standard method (the context specifications are necessary for packaging):
This seems to work (after loading the package) for any cases, e.g.:
In[2]:= StringJoin[1, 2, 3]
Out[2]= "123"
In[3]:= 4 <> 5 <> 6
Out[3]= "456"
but has a strange effect on messages:
In[5]:= Append[dummy, 2]
During evaluation of In[5]:= Append::normal: {Nonatomic expression expected at position , {1}, in , {Append[dummy,2]}, .} >>
Out[5]= Append[dummy, 2]
that is: the message strings are displayed in a non-joined list format. The code below shows an other modified StringJoin, that gives the exact same results (after initiating a fresh kernel):
Now I've inserted a Print[#]; inside the function to see what's happening. This reveals some internal calculation that is done during the evaluation of the erroneous call of Append[dummy, 2], which I don't really understand (did not copy here for size constraints). Apart from this strange sideeffect on messages (which seems to be harmless), both functions work as expected. Does anyone have any idea what is the exact cause of this behaviour and how to overcome it?
It is quite interesting why StringJoin does not apply ToString to those arguments which are non-string. I've overridden the built-in StringJoin, to save a few unnecessary ToStrings by the standard method (the context specifications are necessary for packaging):
This seems to work (after loading the package) for any cases, e.g.:
In[2]:= StringJoin[1, 2, 3]
Out[2]= "123"
In[3]:= 4 <> 5 <> 6
Out[3]= "456"
but has a strange effect on messages:
In[5]:= Append[dummy, 2]
During evaluation of In[5]:= Append::normal: {Nonatomic expression expected at position , {1}, in , {Append[dummy,2]}, .} >>
Out[5]= Append[dummy, 2]
that is: the message strings are displayed in a non-joined list format. The code below shows an other modified StringJoin, that gives the exact same results (after initiating a fresh kernel):
Now I've inserted a Print[#]; inside the function to see what's happening. This reveals some internal calculation that is done during the evaluation of the erroneous call of Append[dummy, 2], which I don't really understand (did not copy here for size constraints). Apart from this strange sideeffect on messages (which seems to be harmless), both functions work as expected. Does anyone have any idea what is the exact cause of this behaviour and how to overcome it?
> It is quite interesting why StringJoin does not apply ToString to > those arguments which are non-string. I've overridden the built-in > StringJoin, to save a few unnecessary ToStrings by the standard method > (the context specifications are necessary for packaging):
> This seems to work (after loading the package) for any cases, e.g.:
> In[2]:= StringJoin[1, 2, 3]
> Out[2]= "123"
> In[3]:= 4 <> 5 <> 6
> Out[3]= "456"
> but has a strange effect on messages:
> In[5]:= Append[dummy, 2]
> During evaluation of In[5]:= Append::normal: {Nonatomic expression > expected at position , {1}, in , {Append[dummy,2]}, .} >>
> Out[5]= Append[dummy, 2]
> that is: the message strings are displayed in a non-joined list > format. > The code below shows an other modified StringJoin, that gives the > exact same results (after initiating a fresh kernel):
> Now I've inserted a Print[#]; inside the function to see what's > happening. This reveals some internal calculation that is done during > the evaluation of the erroneous call of Append[dummy, 2], which I > don't really understand (did not copy here for size constraints). > Apart from this strange sideeffect on messages (which seems to be > harmless), both functions work as expected. Does anyone have any idea > what is the exact cause of this behaviour and how to overcome it?
I think you would be much better off to leave the System functions as they are and define a tostring or mytostring that behaves as you want. I have no idea what causes the problems with messages that you see, but I suspect that there are many more problems that eventually could arise but you haven't yet discovered because you presumably only tried a very limited part of Mathematica's full functionality. On the other hand it is very easy to construct cases where your "improved" ToString behaves different from the original and so will potentially cause troubles, here is just one:
If[Head[Quiet[StringJoin[1,2,3]]] == StringJoin, Print["this was no string!"]]
> It is quite interesting why StringJoin does not apply ToString to > those arguments which are non-string. I've overridden the built-in > StringJoin, to save a few unnecessary ToStrings by the standard method > (the context specifications are necessary for packaging):
replicator...@gmail.com wrote: > It is quite interesting why StringJoin does not apply ToString to > those arguments which are non-string. I've overridden the built-in > StringJoin, to save a few unnecessary ToStrings by the standard method > (the context specifications are necessary for packaging):
> This seems to work (after loading the package) for any cases, e.g.:
> In[2]:= StringJoin[1, 2, 3]
> Out[2]= "123"
> In[3]:= 4 <> 5 <> 6
> Out[3]= "456"
> but has a strange effect on messages:
> In[5]:= Append[dummy, 2]
> During evaluation of In[5]:= Append::normal: {Nonatomic expression > expected at position , {1}, in , {Append[dummy,2]}, .} >>
> Out[5]= Append[dummy, 2]
> that is: the message strings are displayed in a non-joined list > format. > The code below shows an other modified StringJoin, that gives the > exact same results (after initiating a fresh kernel):
> Now I've inserted a Print[#]; inside the function to see what's > happening. This reveals some internal calculation that is done during > the evaluation of the erroneous call of Append[dummy, 2], which I > don't really understand (did not copy here for size constraints). > Apart from this strange sideeffect on messages (which seems to be > harmless), both functions work as expected. Does anyone have any idea > what is the exact cause of this behaviour and how to overcome it?
> Thanks
> Istvan Zachar
I would never routinely override built-in commands - even to extend their functionality. There are lots of reasons for this, but not least is the fact that code that uses this trick is very hard to read. Why not simply write a function ExtendedStringJoin.
Part of Mathematica is written using other Mathematica functions - so problems such as you report are not unexpected.
On the face of it, adding extra functionality to a built-in might not be expected to cause problems, but it is easy to write code that would be disrupted by your change:
ss = Quiet[2 <> 3]; Map[ToString[#^2] &, ss]
Who knows what sort of code lies inside Mathematica :)
with your extension the code works fine so far. For those who warned me not to play with system symbols: I use this modified StringJoin in a program where it can produce onyl two types of string outputs: either one that is printed for verbosing (i.e. just for me to check behaviour of the code) or a string that is used as a path of some file to be saved. In both situations any erroneous behaviour would be immediatley recognized, since either the text printed would be garbled, or the file/directory would not be created, thus I do not afraid using the modified StringJoin in this "controlled" environment.
First, I'm extremely sorry to mix up your name, ADL. Second: this code of you does only half of the job: It can not convert lists to strings verbatim, that is toString[{1,2,3}] gives {"1","2","3"} instead of "{1,2,3}". Which (as it seems to me) is exactly the problem causing the wrong pinting of Messages. Still I wonder whether there is a reliable solution to apply ToString to inputs of StringJoin without explicitely writing it each time I call StringJoin. If I use a different name (e.g. ExtendedStringJoin, as it was suggested), I loose the effective shorthand version (<>), as it would still use the original function. Is there a way to overwrite at least the definitions of the infix operator?
Istvan
On Apr 5, 12:40 pm, ADL <alberto.dilu...@tiscali.it> wrote:
> > It is quite interesting whyStringJoindoes not apply ToString to > > those arguments which are non-string. I've overridden the built-in > >StringJoin, to save a few unnecessary ToStrings by the standard method > > (the context specifications are necessary for packaging):
replicator...@gmail.com wrote: > If I use a different name (e.g. ExtendedStringJoin, as it was > suggested), I loose the effective shorthand version (<>), as it would > still use the original function. Is there a way to overwrite at least > the definitions of the infix operator?
You can't overwrite it (as far as I know), and in some ways that would be as bad as redefining the actual function, but you can co-opt an unused operator:
Istvan, actually toString was not meant to replace ToString, but only to support your StringJoin functionality in a "hidden" way. Also, StringJoin[{1, 2, 3}] gives "123", so that only ToString[{1, 2, 3}] can return "{1,2,3}".
In any case, I would also support David Bailey's suggestion. When I had to do similar things in the past, I used exactly CirclePlus, which is also rather handy to type in the GUI: <Esc>c+<Esc>.
In the same category, you also find CircleMinus <Esc>c-<Esc>, CircleDot <Esc>c.<Esc>, CircleTimes <Esc>c*<Esc> and perhaps some more.
So you can avoid tampering with built-in functions and keep effective shorthands. Unfortunately, only <> works also in the text interface, but you might use NonCommutativeMultiply (**), if you do not already use it for other reasons:
> First, I'm extremely sorry to mix up your name, ADL. > Second: this code of you does only half of the job: It can not convert > lists to strings verbatim, > that is toString[{1,2,3}] gives {"1","2","3"} instead of "{1,2,3}". > ... > Istvan Zachar
I've considered your warnings, but - mainly because of my curiosity - I continued to find a solution to the problem. Combining information from here and my earlier tries, I've managed to come up with a stable code that is quite short:
Extensive testing shows that this works as expected (error messages are returned unchanged, Import[file, "Lines"] works correctly, etc.). Of course, there are effects, which must be considered, e.g. David's example:
ss = Quiet[2 <> 3]; Map[ToString[#^2] &, ss]
this indeed would give 23 instead of 49, but that is definitely not disrupting, since one who uses the new StringJoin *should be aware* that it actually joins non-strings as well. I wouldn't consider it a problem, just a point, where it must be kept in mind what the extended StringJoin can do. To make my point clearer: no one would expect the following
ss = Quiet[2\[CirclePlus]3]; Map[ToString[#^2] &, ss]
to result other than "4"\[CirclePlus]"9" IFF there is no assigned meaning of CirclePlus. Although if one uses CirclePlus to actually do something, then the result of the first line won't be the same as the input: 2\[CirclePlus]3. As one would expect.
For the other problematic example of Albert (modified here a bit):
If[Head[Quiet[StringJoin[1, 2, 3]]] === StringJoin, Print["this was no string!"], Print["string ok"]]
This should (in case of the new StringJoin) result "string ok", while in case of the original StringJoin: "this was no string!". But the former is exactly the functionality I would like to gain, namely to get a string from StringJoin even in case of non-string input.
So, of course one must be cautios, but I wouldn't consider these cases problematic. Could anyone find any abnormal/unexpected behaviour of this new function?