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$
8
  • 4
    $\begingroup$ Stricter pattern matching would have saved you: {{1, "2"}, {2, "3"}} /. {x_Integer, _String} :> {x, "SOMETHING"} $\endgroup$ Sep 26, 2017 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, 2017 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, 2017 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, 2017 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, 2017 at 12:10

2 Answers 2

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$
6
  • 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$ Sep 26, 2017 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$ Oct 2, 2017 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$ Oct 2, 2017 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, 2017 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$ Oct 3, 2017 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
  • 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$ Sep 26, 2017 at 12:30

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