But there are other cases where the variable-width nature of tabs can create ambiguity all by itself. Take this example from R7RS small:
(cond ((> 3 3) ’greater)
((< 3 3) ’less)
(else ’equal))
If you write it like this, a smart editor (e.g., Emacs) would probably be able to do the right thing and line up the forms that follow the `cond`: (cond ((> 3 3) ’greater)
<tab>((< 3 3) ’less)
<tab>(else ’equal))
But to everyone else using a different editor, where the convention is "the tab character just advances to the next multiple of T" (where T is usually 4 or 8), then the second and third lines won't be correctly aligned. And then instead of being able to use the indentation as a visual reference and ignore the parentheses, those people will have to revert to counting parentheses in order to figure out what S-expression each form is part of. Granted, in this simple example that's not hard, but imagine that `cond` nested deep inside a larger expression including a `call/cc` and a `let` or two, rather than being at the top level where it's easy to read.Here, the ambiguity is because the tab character needs to have a width of six characters in order to align with the text `(cond `. If that had been an `(if ` with just two forms (omitting the `(else 'equal)` case) then the tab would have needed to have a width of four characters. A smart editor that reads the Lisp code and can interpret `<tab>` as meaning "indent this form to align with the form on the line above", but any context that isn't syntax-aware, such as a git diff, will not align those tabs correctly.
Which is why I consider tabs to be ambiguous, because I'm looking at it from the perspective of "how many spaces does this correspond to", and spaces to be unambiguous.