Question

This claim by Aleks Bromfield states:

Almost every language with a static type system also has a dynamic type system. Aside from C, I can't think of an exception

Is this a valid claim? I understand that with Reflection or Loading classes at runtime Java gets a bit like this - but can this idea of 'gradual typing' be extended to a large number of languages?

Was it helpful?

Solution

Original tweeter here. :)

First of all, I'm somewhat amused/shocked that my tweet is being taken so seriously! If I had known it was going to be this widely disseminated, I would have spent more than 30 seconds writing it!

Thiago Silva is correct to point out that "static" and "dynamic" more accurately describe type checking, rather than type systems. In fact, it isn't really accurate to say that a language is statically or dynamically typed, either. Rather, a language has a type system, and an implementation of that language might enforce the type system using static checking, or dynamic checking, or both, or neither (though that would not be a very appealing language implementation!).

As it happens, there are certain type systems (or features of type systems) which are more amenable to static checking, and there are certain type systems (or features of type systems) which are more amenable to dynamic checking. For example, if your language allows you to specify in the text of a program that a particular value must always be an array of integers, then it's reasonably straightforward to write a static checker to verify that property. Conversely, if your language has subtyping, and if it permits downcasting, then it's reasonably straightforward to check the validity of a downcast at runtime, but extremely difficult to do so at compile time.

What I really meant by my tweet is simply that the vast majority of language implementations perform some amount of dynamic type checking. Or, equivalently, the vast majority of languages have some features that are difficult (if not impossible) to check statically. Downcasting is one example. Other examples include arithmetic overflow, array bounds checking, and null checking. Some of these can be statically checked in some circumstances, but by and large, you'd be hard-pressed to find a language implementation that doesn't do any checking at runtime.

This is not a bad thing. It's just an observation that there are many interesting properties that we would like our languages to enforce, and that we don't really know how to check statically. And it's a reminder that distinctions like "static types" versus "dynamic types" are not nearly as clear-cut as some people would have you believe. :)

One final note: the terms "strong" and "weak" aren't really used in the programming language research community, and they don't really have a consistent meaning. In general, I've found that when someone says that a language has "strong typing" and some other language has "weak typing", they're really saying that their favorite language (the one with "strong typing") prevents them from making some mistake that the other language (the one with "weak typing") doesn't -- or conversely, that their favorite language (the one with "weak typing") allows them to do some cool thing that the other language (the one with "strong typing") does not.

OTHER TIPS

Well yes. You can have property bags in any statically typed language. The syntax will be terrible while at the same time you will gain all the disadvantages of dynamically typed system. So there is not really any advantage unless compiler allows you to use nicer syntax, something like C# with dynamic is doing.

Also, you can do that pretty easily in C too.

In reaction to other answers: I think people are mistaking static/dynamic typing with strong/weak typing. Dynamic typing is about being able to change the structure of data at runtime and code being able to used data that just fits what the code needs. This is called Duck Typing.

Mentioning reflection is not telling the whole story, because reflection does not allow you to change existing structure of data. You cannot add new field to a class or structure in either C, C++, Java or C#. In dynamic languages, adding new fields or attributes to existing classes is not only possible, but actually quite common.

For example, look at Cython, the Python-to-C compiler. It creates static C code, but the type system still retains it's dynamic nature. C is statically typed language, yet it is able to support dynamic typing from Python.

Dynamic languages are static languages. What is commonly called "dynamic typing" is really a special case of static typing - the case where you've restricted yourself to only having one type. As a thought experiment, imagine writing a program in Java or C# using only Object variables/fields/parameters and down-casting immediately before calling any method. It'd be more accurate to call languages like Python or Javascript "unityped". (This claim will likely confuse/bother many people, considering such a Java or C# program would use many sub-types, but that's because the average OOP language conflates types and classes. Read the blog post for more details.)

Note that even C has "dynamic" typing - you can cast any pointer to a void (and if memory serves me, char) pointer and back again. And note, also, that there is no runtime checking there; if you get it wrong, enjoy your undefined behavior!

The difference between static and dynamic typing is when the type of a value is checked: compile time vs. run time. In languages where values carry their type with them (e.g. Java objects), then you can always resort to dynamic typing even when the language actually prefers static typing. Here is an example in Java, with a dynamically typed method:

void horribleJava(List untypedList) {
  for (Object o : untypedList)
    ((SpecificType) o).frobnicate();
}

Notice how the type of each item is checked at runtime. The equivalent statically typed method is:

void goodJava(List<SpecificType> typedList) {
  for (SpecificType o : typedList) {
    o.forbnicate();
  }
}

In C, values (and specifically pointers) do not retain their type during runtime – every pointer is equivalent to a void *. Instead, variables and expressions have a type. To achieve dynamic typing, you have to carry around the type information yourself (e.g. as a field in a struct).

Static vs. Dynamic typing basically refers on to how types are checked. Static typing means that the verification of the types of various variables or expressions are checked based on the actual code (usually by the compiler) while in a dynamic type system this verification is performed only at runtime, by the runtime environment.

What I believe the text is referring is that even if the types are actually checked statically, they are also checked at runtime, i.e. dynamically. You correctly mentioned Java Reflection; reflection only happens at runtime and the Java Runtime Environment (JVM) actually performs type checking when reflection is used, which basically means dynamic type checking.

The excpetion is wrong: C also have an important dynamic type system. It simply does not check it ("C is strongly-typed, weakly checked"). For example, treating a struct as a double (reinternpret_cast-style) yields undefined behavior - a dynamic type error.

Licensed under: CC-BY-SA with attribution
scroll top