Tim Delaney <timothy.c.dela...@gmail.com> writes:
> As others have said, typing is about how the underlying memory is treated.
No. It is much more than that. Typing is about everything you can say
about a given statement. Some type systems are focusing on type labels
only (like most statically typed programming languages), others are
fairly elaborate (for instance, Eiffel's, if requires/ensures are
considered part of the type system). There is a wide range of type
systems, more or less practical depending on your needs (see
https://www.cis.upenn.edu/~bcpierce/tapl/ if you want to see how far you
can go with typing).
> C is statically and weakly typed. Variables know their types at compile
> time (static typing). It is a feature of the language that you can cast any
> pointer to any chunk of memory to be a pointer to any other type (normally
> via void *). This is not coercion - it takes the bit pattern of memory of
> one type and interprets it as the bit pattern for another type, and is weak
No. C has much stronger rules, not on casting, but on accessing the
pointees, which basically invalidates your argument. Refer to the C
standard for details.
> Python is strongly and dynamically typed. In Python, once you create an
> object, it remains that type of object, no matter what you do to it*. That
> makes it strongly typed.
But you can modify the class (not __class__) in whatever way you want.
def f(self): ...
So, in Python, knowing that object x is an instance of class X tells
you... essentially nothing. Call this strong typing if you want. In
terms of type systems, it is (strong) simplistic-typing based on type
labels, and labels carry no information whatsoever.
Dynamic typing lets you avoid doing nonsense with bit-patterns, as you
say, by gracefully crashing at run-time instead of performing
"unexpected" actions. "Unexpected" is defined by the whole *execution*
of the program up to the point where typing takes place. To understand
whether a Python statement
is meaningful (which is what typing is about), you have to know the full
sequence of actions that have taken place on x *and* on its class (and
on everything that that call may use) since the beginning of the
program. For any non-trivial program, this is usually way too complex to
capture, testing will be incomplete, and all you can do is run your
program and see whether is goes through.
As a general rule, if that's all you expect from typing, then, fine,
call this "strong". I won't go as far, and just say that it is good
enough for the programs I use Python for.