I assume you want to see some examples so bellow I've listed some of the most common.
Problem #1: Tab width is not consistent
This is for "displayed completely differently on different types of systems and editors" part.
Even assuming all systems and editors (that your code will be displayed on) agrees on same tab semantics: "move to the right until the current column is a multiple of N", the N is arbitrary.
Historically "standard" for this N is 8 but now most people configure their editors it to be 4 or 2 to "look better".
This is where tab width inconsistency problems come from.
I will use tab widths 2 and 8 in my examples to make differences more visual but same applies to other widths as well.
Indent
Lets say someone is using tab width: 2 in their editor. They see the code like this:
class Foo:
def doSomething(a):
if test(a):
// some nice comment
// about this
bar(a)
Now someone else reads this code in say terminal that uses tab width 8. They see the code like this:
class Foo:
def doSomething(a):
if test(a):
// some nice comment
// about this
bar(a)
That someone may see this as not very pleasant.
Align
So far we have seen inconsistency in indent. But some people like to also align code e.g. assignments, comments.
Again with tab width 2:
class Foo:
def do_something(a):
if test(a):
foo = a.foo // some nice comment
foo_bar = bar(foo) // about this
bar(a)
Again someone else reads this in environment where tab width is 8. Lets say they need to post this snippet to the web and uses <pre>
tag. Browsers by default use "standard" tab width 8 and the code looks like this:
class Foo:
def do_something(a):
if test(a):
foo = a.foo // some nice comment
foo_bar = bar(foo) // about this
bar(a)
They can't post it as is. They have to modify the code to replace tabs to spaces.
Line length
Most coding standards define maximum line width.
Lets take max line width 80 for example.
Someone using tab width 2 may see this code completely standard conforming. For them the longest line width is 74 (visible width as opposed to line length in bytes which is 72).
class Foo:
def do_something(a):
// Some very nice comment about code bellow using more then few words.
Someone else using tab width 8 (in a terminal for example) will see the same line as non-conforming because now longest line width is 86:
class Foo:
def do_something(a):
// Some very nice comment about code bellow using more then few words.
Since tab width is inconsistent, line with is now inconsistent too.
Problem #2: Tab is not same thing everywhere
This is for the "semantics of tabs are not very well-defined" part.
So far we assumed that everyone uses tab character as "move to the right until the current column is a multiple of N".
But in some contexts tab character may be used for something a bit different. For example in word processors tab means "move to the the next tab stop", where tab stops are completely arbitrary (and most likely not event the same width).
For example lets say someone is writing a document that uses tab stops:
Now lets say they need to paste some code snippet in it. If code is using tabs, following happens:
They can't leave it as is. They have to modify the code to replace tabs to spaces.
Conclusion
As you can see tabs in different contexts may render code from slightly to completely unreadable.
Spaces have none of the above problems.