The below is the conclusion that I have drawn from answers to the SO question Does “untyped” also mean “dynamically typed” in the academic CS world?.
For a dynamic programming language L the following two statements are equivalent:
- L is dynamically typed.
- L is untyped.
A canonic representant of the (1) group is method (or attribute) resolution failure. That is, for an object
o, there is a request of method invocation
o.m() but no method is associated with
o under the name
m. (And no interception handler is defined.)
An example for the (2) group is a request to create a class that is a subclass of a non-class object (applies to both Python and Ruby). Or, in Python, to create a class with the
metaclass parameter used whose value is a class that is not a descendant of the
type class (i.e. whose value is not a metaclass). Or, in Ruby (as of 2016), to create a subclass of the
In my opinion, only the type enforcements of the (2) group can conceivably be removed. This would result into the possibility to create wild and/or unsupported structures between objects. But in the case of the (1) group, there is no clear candidate of what a "type enforcement removal" should mean. One can only invent some nonsense behavior in response to such situations.
(Added after 2 days.)
To me, the title question can be formulated as:
How can a dynamic object-oriented language like Python potentially be untyped?
My answer is that there are basically just two ways how to achieve this:
- Via the dynamically typed ↔ untyped equivalence.
- By inventing nonsense behavior (a generalized nasal demon) for method resolution.
as three significant languages that are relevant to the title question.
All of them are popular dynamic OO languages
"classes are objects" and in all of them
there is a built-in
where there classes are explicitly mentioned, including the
Moreover, the notion of a class is explicitly supported in ECMAScript 6.)
At this point let us emphasize, that assembly or the C language
mentioned in some answers or comments are NOT relevant.
Having established the group of three languages that are relevant to the question
we can observe that the
dynamically typed ↔ untyped equivalence has already been established in
There are probably more statements that the 3 languages are dynamically typed
but there is also considerable amount of statements about their
untypedness or typelessness.
As for Python:
(Py1), (Py2), (Py3), (Py4), (Py5), (Py6)
(Py7), (Py8), (Py9), (Py10), (Py11), (Py12).
As for Ruby:
(Rb1), (Rb2), (Rb3), (Rb4), (Rb5).
(Js1) – quoted by Wikipedia in the opening sentence,
Moreover, there are also articles ((eq1), (eq2)) where the equivalence
(dynamically typed ↔ untyped) is suggested explicitly.
The reason behind this terminological paradox is that removing what
is called run-time type checking would mean not throwing any
which is absurd. (Why then throw any
Error at all?)
One can imagine that there is no detection of possible invalid states
as I have mentioned before.
is a request to form a cycle in inheritance, and thus
rejected as a
__proto__ = x
But without the (absurd) concept of nasal demons,
I cannot imagine what should a "removal of type enforcement" mean in the
o.m() case of method resolution failure.
What is a possible meaning of calling a missing method?
I also think that the
1 + "a" example of typechecked Python code
provided in the answer by Gilles
should be presented for a user-defined function, rather than a built-in one.
In this case, disallowing type checking would in fact mean
to prohibit the programmer from using
This is absurd too.
The only non-absurd removal of a type constraint that I am aware of
is disregarding the number of method arguments
(probably due to missing default argument values).
But I doubt that this should be the dividing point - the reason why
Summed up, the
dynamically typed ↔ untyped equivalence can be
used as a mnemonic for an inconsistency in the terminology.
It is better than to pretend that the notions are well established.