10
$\begingroup$

ReplaceAll[] might lead to unexpected behavior (at least it surprised me). I use ReplaceAll[] to convert a list (basically data cleanup).

For the command:

{{1, "2"}, {2, "3"}} /. {x_, _ } :> {x, "SOMETHING"}

I expected

{{1, "SOMETHING"}, {2, "SOMETHING"}}

but got

{{1, "2"}, "SOMETHING"}.
$\endgroup$
  • 4
    $\begingroup$ Stricter pattern matching would have saved you: {{1, "2"}, {2, "3"}} /. {x_Integer, _String} :> {x, "SOMETHING"} $\endgroup$ – J. M. will be back soon Sep 26 '17 at 10:26
  • 3
    $\begingroup$ @J.M. It could have saved him, but it is not good practice. /. is much too tempting because it is short. People should always default to Replace (or in some cases Lookup) and use ReplaceAll only for algebraic replacements (or when replacing at all levels is required). $\endgroup$ – Szabolcs Sep 26 '17 at 10:42
  • 1
    $\begingroup$ @Szabolcs I don't (entirely) agree with that. I think /. can often be used well given a little thought, and I find defaulting to Replace a bit heavy handed. Of course there are cases where Replace is far superior, but in many other cases I would argue that a pattern restriction as J. M. offered is entirely adequate and not bad practice. Careless use of /. is just that: carelessness, and IMHO baroque code is not a remedy for that. $\endgroup$ – Mr.Wizard Sep 26 '17 at 21:32
  • 1
    $\begingroup$ @Mr.Wizard I would not call using Replace instead of ReplaceAll baroque. The shorthand /. is a minor convenience only. I do sloppily use /. when working interactively, but when writing code which is expected to be robust, it is a good idea to use defensive programming. Even the smartest programmer makes mistakes, or fails to see consequences sometimes. It is good practice to try to make our programs predictable and to reduce the chance of mistakes. $\endgroup$ – Szabolcs Sep 27 '17 at 9:36
  • 1
    $\begingroup$ @Szabolcs We should discuss this another time in more detail. I probably don't disagree with you in practice. Too sleepy now, and comments aren't the place. $\endgroup$ – Mr.Wizard Sep 27 '17 at 12:10
12
$\begingroup$

ReplaceAll is way overused, and it can very easily lead to unexpected results (or bugs in your code) because it replaces at all levels. In fact, the example you show is one of the most common errors stemming from the misuse of ReplaceAll.

I recommend using ReplaceAll only when you know you need it, except for algebraic replacements.

Otherwise, use Replace:

Replace[{{1, "2"}, {2, "3"}}, {x_, _ } :> {x, "SOMETHING"}, {1}]

Make Replace your default choice unless you know why you need ReplaceAll, especially when developing packages (where robustness is a requirement).

Of course, when doing interactive work, a bit of sloppiness if forgivable :-) /. is just shorter to type.

$\endgroup$
  • 3
    $\begingroup$ +1. You make a very good point. It is rather surprising that this has not been emphasized enough on this site for such a long time, or may be I just don't remember. $\endgroup$ – Leonid Shifrin Sep 26 '17 at 12:31
  • $\begingroup$ "I recommend using ReplaceAll only when you know you need it, except for algebraic replacements" seems a bit extreme. I think better advice is "use as specific pattern as possible when using ReplaceAll", for example {_Integer,_} in this case. I guess my POV is the subtly different "Replace is way underused". It's a great function and often exactly what you need, but it isn't a substitute for ReplaceAll. $\endgroup$ – Itai Seggev Oct 2 '17 at 17:27
  • 1
    $\begingroup$ FWIW, I did some work in the last year (I think for 11.1, but I'd have to double check) expanding the ref pages for Replace, ReplaceAll, and ReplaceRepeated to both clarify what each did and the relationships between them, and I do address this point. But I think I'll add a simpler example focusing exactly on ReplaceAll based on this question. $\endgroup$ – Itai Seggev Oct 2 '17 at 17:32
  • 1
    $\begingroup$ @Itai If you are working on the documentation pages, one difference you may want to point out is that ReplaceAll works "from the outside towards the inside" and Replace works "from the inside towards the outside". Thus it is not possible to do use Replace to do precisely what ReplaceAll does. I'm not sure how to phrase this concisely and clearly :-) $\endgroup$ – Szabolcs Oct 2 '17 at 18:11
  • 1
    $\begingroup$ I suggest you look at the 4th, 5th, and 7th Properties & Relations examples for Replace. I think they are documenting exactly what your trying to say. $\endgroup$ – Itai Seggev Oct 3 '17 at 5:46
2
$\begingroup$

The issue is that the provided pattern also matches the outer list. Therefore ReplaceAll[] replaces the outer list and stops (as there are no elements left).

To overcome this issue, Map[] must be used:

ReplaceAll[{x_, _} :> {x, "SOMETHING"}] /@ {{1, "2"}, {2, "3"}}
$\endgroup$
  • 1
    $\begingroup$ +1. Actually, David Wagner discusses exactly this case in his book, I think in the chapter on patterns and pattern-matching. It is a very common source of errors in Mathematica. $\endgroup$ – Leonid Shifrin Sep 26 '17 at 12:30

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