Javascript:
>>> 1()
TypeError: 1 is not a function
Ruby:
>>> 1 + ""
String can't be coerced into Fixnum
These are both simple cases of dynamic type error. Many languages, including almost all dynamic languages but also, e.g., C# and Java, do "type tagging". That is, the runtimes of these environments must, in effect, attach a representation of a type to every object. This is different than static typing because type tags exist at runtime and in at least the dynamic, imperative languages like Ruby and Javascript one variable may point to different objects with different types.
The runtime must, to implement the semantics of the language, check these type tags all the time. For instance, in performing the +
operation on two objects, these languages check the type tags on both objects to decide what to do. If both objects are tagged as numeric, then addition is performed (possibly after some type conversion to a common numeric type). If both objects are tagged as string type-tags, then string concatenation is performed. (What may have tripped you up is that Javascript will perform extensive amounts of runtime-type conversions in normal operation. This makes it seem like it is not checking type-tags, because no type errors are thrown, when in fact type-tags are being checked all over the place to perform these conversions.)
Note that this type-tag checking bears only a vague and mostly misleading resemblance to (static) type checking. Static type checking checks properties of the expression before run time while type-tag checking checks properties of the value the expression expresses at run time. Both Ruby and Javascript perform type-tag checking in their basic runtime environment (e.g. in +
, -
, function invocation). They also allow the user of the language to perform type-tag introspection. That is, they allow the user to check the type-tag of a value at runtime.
Actually, according to GoF, a type is simply a set of interface, so how can you "check" the type, other than whether it responds to a particular message?
I am not familiar with this definition, but it strikes me as misleading. A static type is a token that gets associated according to a set of typing rules with expressions in a language and is used to define which expressions are semantically valid in that language. A "dynamic type" (or type-tag, as I prefer) is a value that gets associated with objects in a language's runtime. In some sense, both are tied to interfaces. In statically typed languages, the type defines what expressions an expression of that type may legally appear in and so to that extent determines an interface for that type. Vaguely similarly, type-tags determine, in part, which operations will end in a runtime "TypeError" before the operation is even attempted.
However, it is misleading to identify the type/type-tag with its interface in most static-dynamic languages. Essentially all static and dynamic languages are largely nomatively and not structurally typed. That is, in a normal statically typed language, if you define a type YourCustomer
and I define MyCustomer
, expressions of the two types will not be interchangeable. even if the definitions of YourCustomer
and MyCustomer
are identical up to naming. Similarly, if you define a Javascript object with type-tag YourJSCustomer
and I define a Javascript object with type-tag MyJSCustomer
, even if these two objects have all the same properties and methods otherwise they will not be interchangeable in the face of type-tag introspection.
It is true that in many dynamically typed languages, type-tag introspection is not always used and so YourJSCustomer
and MyJSCustomer
will be interchangeable in many environments. This is because these languages allow replacing or supplementing type-tag checking with attribute-checking. So if you call x.foo()
in JS, Ruby, Python, &c., it will look for the .foo
attribute on the object x
. This allows the elimination of some, but typically not all, type-tag checking.
Note that in statically typed languages with structural typing, you can have YourCustomer
and MyCustomer
interchangeable in most/all contexts. This gives a language feel much closer to a language like Javascript or Ruby. I would suggest looking at TypeScript for this, which adds a type system to Javascript.