20

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?

hawkeye
  • 4,819
  • 3
  • 24
  • 35
  • I am no language expert, but a few that instantly come to mind that I do not believe have dynamic types (Natively, not saying you couldn't cobble something together in these) - Fortran, Ada, Pascal, Cobol – mattnz Dec 28 '13 at 22:35
  • 4
    I am a language expert, and I am not sure what this guy is claiming. "static" and "dynamic" are misnomers and usually indicate the time of type check/analysis (whether at compilation time or at runtime). Some languages conciliate both (eg. by disallowing operations on unsupported types during compilation and raising exceptions like ClassCastException during runtime), and that may be what he means. If so, it is true that C usually does not perform **type check** during runtime. Saying a lang. does not have "dynamic type system" doesn't make sense. – Thiago Silva Dec 29 '13 at 00:51

6 Answers6

37

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.

Aleks Bromfield
  • 486
  • 3
  • 2
  • 9
    "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." – Well, it's not just that we don't know how to do it. "Does this program halt for this input" is an interesting property that we not just don't know how to check, but in fact we *do* know is *impossible* to check. – Jörg W Mittag Dec 30 '13 at 04:39
  • "Other examples include arithmetic overflow, array bounds checking, and null checking." Just a note that while there are a few languages that check these properties in the type system, even in most dynamically typed languages these are usually a feature of *values*, not types. ("Null" checking is a common feature of static type systems though.) – porglezomp Nov 29 '15 at 02:02
  • There *is* a dynamic type _system_, and a static type _system_. Even if neither is enforced, they are still there, describing what is correct and what is an error. The language/implementation may or may not check either of them. BTW, the static and dynamic type system should be in consistent, but it is not the case _by definition_. – Elazar Jul 04 '16 at 07:09
  • Every language has a dynamic type system, which is a set of rules forbidding certain operations from being performed. – Elazar Jul 04 '16 at 07:12
7

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.

Euphoric
  • 36,735
  • 6
  • 78
  • 110
  • Technically, you can do it in C# as of version 4 with `ExpandoObject`, although it's very much an opt-in process, much unlike JavaScript or Ruby. Still, you've made a very important point, which is that duck typing (what 99% of developers actually mean when they say "dynamically typed") and reflection are not the same things at all. – Aaronaught Dec 29 '13 at 02:45
  • Might I also add that Python does not have real duck typing. It just has some hooks for you to "implement your own" (has a magic method that can return `True` in order to say "this crazy object is an instance of the class i'm defining"). OCaml does have this feature as far as i understand, but i don't really know. – vlad-ardelean Dec 21 '14 at 21:26
6

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!

Doval
  • 15,347
  • 3
  • 43
  • 58
  • But the cast is done statically. I fail to see how this is an example of dynamic typing. – osa Dec 22 '14 at 06:58
  • @osa Just because the code says `String foo = (String) bar` it doesn't mean that `bar` is in fact a `String`. You can only know that for sure at run time, so I don't see how the cast is done "statically". – Doval Dec 22 '14 at 12:24
  • I don't agree with this. At least in Javascript, you can add new methods and properties to objects in runtime. In C#, you need to explicitly use a `dynamic` object to do this. If you try to add a property to an `object`... well, you can't. – Arturo Torres Sánchez Jan 10 '16 at 04:57
  • A popular myth but entirely untrue. In statically typed languages the types of expressions must be known, but not the type of values. In dynamic languages it is the reverse. The types of expressions are generally not known, but the types of values are known. I can do `a.foobar()` in a dynamic language and it just works if the types match. In a static language `a` will have to be cast to a type supporting `foobar`. You cannot do anything in a a static language without knowing the types of expressions you evaluate. – Erik Engheim Feb 25 '20 at 13:37
  • If you work with a gradual typing system such as Objective-C it becomes quickly apparent how dynamic typing and static typing are entirely different things. You can place types around in Objective-C which are all wrong and still have the system work, because the types are right at runtime. A proper statically typed language could not survive that. You would get undefined behavior. – Erik Engheim Feb 25 '20 at 13:40
3

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).

amon
  • 132,749
  • 27
  • 279
  • 375
  • 1
    I don't think a cast counts as dynamic typing in any really practical sense. It still requires knowledge of the type at compile-time, it just defers the actual validation until runtime. You can't invoke the `frobnicate` method here without first knowing about `SpecificType`. – Aaronaught Dec 29 '13 at 02:47
  • 3
    @Aaronaught But this *is* dynamic typing once we've deferred the type check to run time. Note that both of my examples use *nominative typing* which require a specific type name. You are thinking of *structural typing*, e.g. duck typing which requires a presence of some method. The axes structural vs. nominative and static vs. dynamic typing are orthogonal to each other (Java is nominative and mostly static; ML and Go are structural and static; Perl, Python, and Ruby are (mostly) structural and dynamic). – amon Dec 29 '13 at 09:14
  • Like I said in my last comment, it's a theoretical distinction that no programmer I've ever met really cares about. You can abrasively argue that people are using the wrong terminology (and it does in fact appear that the original tweeter was going for precisely that sort of snarkiness) but for people who are actually in the trenches, dynamic typing = duck typing. In fact that definition is so common that langues such as C# have actually codified it (i.e. with the `dynamic` keyword). Equating *static* to *compile-time* and *dynamic* to *runtime* mostly just muddies the waters. – Aaronaught Dec 29 '13 at 19:44
  • @Aaronaught: If one casts to an interface, and if classes that implement a method with the intended meaning consistently implement the same interface to say so, then one would essentially be run-time duck-typing. While some might argue that "duck typing" should just use the method name, I think it would be more helpful to regard the "real" method name as being the interface name plus the method name. Otherwise, should `[1,2].Add([3,4])` yield `[1,2,3,4]`, `[1,2,[3,4]]`, or `[4,6]`? – supercat Jan 28 '14 at 17:56
  • @supercat: None of the above, it should fail because there is no `Add` method on array that accepts an array because such a method would be ambiguous. Duck typing doesn't excuse you from writing comprehensible types and functions. – Aaronaught Jan 28 '14 at 22:15
2

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.

Random42
  • 10,370
  • 10
  • 48
  • 65
  • Then it is not correct. In C++, Pascal, Fortran --- in any compiled languages --- the types are only checked statically, and not dynamically (unless you are using dynamic_cast). You can use pointers to write arbitrary stuff to memory, and nobody will know the types. So static typing means ONLY CHECK STATICALLY, whereas dynamic typing means ONLY CHECK AT RUNTIME. – osa Dec 22 '14 at 06:57
-1

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.

Elazar
  • 99
  • 3