15

The dynamically typed languages I know never let the developers specify the types of variables, or at least have a very limited support for that.

JavaScript, for example, doesn't provide any mechanism to enforce types of variables when it is convenient to do so. PHP let you specify some types of method arguments, but there is no way to use native types (int, string, etc.) for arguments, and there is no way to enforce types for anything other than arguments.

At the same time, it would be convenient to have a choice to specify in some cases the type of a variable in a dynamically typed language, instead of doing the type check manually.

Why there is such limitation? Is it for technical/performance reasons (I suppose it is in the case of JavaScript), or only for political reasons (which is, I believe, the case of PHP)? Is this a case for other dynamically typed languages that I'm not familiar with?


Hhere's an example for a clarification: let's say we have the following method in plain PHP:

public function CreateProduct($name, $description, $price, $quantity)
{
    // Check the arguments.
    if (!is_string($name)) throw new Exception('The name argument is expected to be a string.');
    if (!is_string($description)) throw new Exception('The description argument is expected to be a string.');
    if (!is_float($price) || is_double($price)) throw new Exception('The price argument is expected to be a float or a double.');
    if (!is_int($quantity)) throw new Exception('The quantity argument is expected to be an integer.');

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

With some efforts, this can be rewritten as (also see Programming by contracts in PHP):

public function CreateProduct($name, $description, $price, $quantity)
{
    Component::CheckArguments(__FILE__, __LINE__, array(
        'name' => array('value' => $name, 'type' => VTYPE_STRING),
        'description' => array('value' => $description, 'type' => VTYPE_STRING),
        'price' => array('value' => $price, 'type' => VTYPE_FLOAT_OR_DOUBLE),
        'quantity' => array('value' => $quantity, 'type' => VTYPE_INT)
    ));

    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

But the same method would be written as follows if PHP would optionally accept native types for arguments:

public function CreateProduct(string $name, string $description, double $price, int $quantity)
{
    // Check the arguments.
    if (!$name) throw new Exception('The name argument cannot be an empty string.');
    if ($price <= 0) throw new Exception('The price argument cannot be less or equal to zero.');
    if ($price < 0) throw new Exception('The price argument cannot be less than zero.');

    // We can finally begin to write the actual code.
    // TODO: Implement the method here.
}

Which one is shorter to write? Which one is easier to read?

8
  • 1
    You can optionally specify types in some dynamically typed languages - e.g., in Common Lisp.
    – SK-logic
    May 9, 2011 at 11:29
  • Quite a few dynamically typed languages use casts to force a type...
    – Trezoid
    May 9, 2011 at 11:42
  • Some do. Objective-C, for example, is dynamically typed, but you can declare a type for variables and the compiler will issue warnings if you don't get the type you are expecting.
    – mipadi
    May 9, 2011 at 14:37
  • 1
    Clojure is an example of a language that is normally dynamically typed but you can optionally give variables types through "type hints" (this is typically only done where needed to get the performance benefits of compile-time type information)
    – mikera
    May 9, 2011 at 18:43
  • 1
    Groovy is another example of a dynamically typed language that allows a type to be specified. May 9, 2011 at 20:32

10 Answers 10

18

The point of having static typing is the ability to prove statically that your program is correct with regard of types (note: not completely correct in all senses). If you have a static type system throughout, you can detect type errors most of the time.

If you only have partial type information, you can only check the small pieces of a call graph where type info happens to be complete. But you have spent time and effort to specify type information for incomplete parts, where it can't help you but could give a false sense of security.

To express type information, you need a part of language which cannot be excessively simple. Soon you'll find out that info like int is not enough; you'll want something like List<Pair<Int, String>>, then parametric types, etc. It can be confusing enough even in the rather simple case of Java.

Then, you'll need to handle this information during translation phase and execution phase, because it's silly to only check for static errors; the user is going to expect that the type constraints always hold if specified at all. Dynamic languages are not too fast as they are, and such checks will slow the performance down even more. A static language can spend serious effort checking types because it only does that once; a dynamic language can't.

Now imagine adding and maintaining all of this just so that people sometimes optionally used these features, only detecting a small fraction of type errors. I don't think it's worth the effort.

The very point of dynamic languages is to have a very small and very malleable framework, within which you can easily do things that are much more involved when done in a static language: various forms of monkey-patching that are used for metaprogramming, mocking and testing, dynamic replacement of code, etc. Smalltalk and Lisp, both very dynamic, took it to such an extreme as to ship environment images instead of building from source. But when you want to ensure that particular data paths are type-safe, add assertions and write more unit tests.

Update from 2020: Some dynamic languages now support partial typing of sorts. Python allows type hints, to be used by external tools like mypy. TypeScript allows mixing with type-oblivious JavaScript. Still, the points above mostly hold.

13
  • 1
    +1, though tests can only show that errors do not happen in certain situations. They're a poor replacement for a proof that (type) errors are impossible.
    – Ingo
    May 9, 2011 at 13:17
  • 1
    @Ingo: surely. But dynamic languages are great for tinkering and quick prototyping, where you express relatively simple ideas very fast. If you want bulletproof production code you could turn to a static language afterwards, when you have extracted some stable core components.
    – 9000
    May 9, 2011 at 14:29
  • 1
    @9000, I don't doubt that they are great. Wanted just to point out that writing 3 or 4 lame tests is not, and cannot be ensuring type saftey.
    – Ingo
    May 9, 2011 at 14:35
  • 2
    @9000, True, and the bad news is that even then, its practically impossible. Even Haskell or Agda code relies on assumptios, like, for instance, that the library that is used in the runtime is correct. That being said, in a project with some 1000 LOC spread over some dozen source code files, it is so cool when you can change something and you know that the compiler will point at every line where the change has an impact.
    – Ingo
    May 9, 2011 at 15:20
  • 5
    Poorly written tests are not a replacement for static type checking: they are inferior. Well written tests are also not a replacement for static type checking: they are superior. May 9, 2011 at 16:20
10

In most dynamic languages, you can at least dynamically test the type of an object or value.

And there are static type inferencers, checkers and/or enforcers for some dynamic languages: e.g.

And Perl 6 will support an optional type system with static typing.


But I guess that the bottom line is that a lot of people use dynamically languages because they are dynamically typed, and for them optional static typing is very "ho hum". And a lot of other people use them because they are "easy for non-programmers to use", largely as a consequence of the forgiving nature dynamic typing. For them, optional typing is something they either won't understand, or won't be bothered to use.

If you were cynical, you could say that optional static typing offers the worst of both worlds. To a static type zealot, it doesn't prevent all dynamic type failures. For a dynamic type fan, it is still a straight jacket ... albeit with the straps not done up tight.

3
  • 2
    It should be noted that checking types yourself is frowned up by most communities in most circumstances. Use polymorphism (specifically, "duck typing") when dealing with with object hierachies, coerce to the expected type if possible/sensible. A few cases remain where it just doesn't make sense to allow any type, but in many languages you get an exception in most of these cases anyway, so type checking is rarely useful.
    – user7043
    May 9, 2011 at 15:22
  • 7
    "people typically use dynamically languages because they are dynamically typed": JavaScript is used because it is the only language which is supported by most browsers. PHP is used because it is popular. May 9, 2011 at 23:45
  • @ArseniMourzenko - I am generalizing. Obviously there are other reasons to chose a specific dynamic typed language for specific context. Like Javascript. But your point about PHP is a bit circular. Why is it popular? Because (in part) it is easy to use because it is dynamically typed.
    – Stephen C
    Apr 10, 2020 at 2:06
2

Javascript did plan to include some optional static typing, and it seems as if many mature dynamic languages are heading that way-

The reason is that when you first code, you want to be fast and dynamically typed. Once your code is solid, working and has many use(r)s, you want to lock down the design to reduce errors. (this is beneficial both users and developers, as the former will get error checking on their calls and the latter won't break things accidentally.

Makes some sense to me, since I usually find there too much type-checking at the start of a project, too little at the end of it's life-time, no matter what language I use ;).

5
  • I don't know about those plans to include optional static typing in JavaScript; but hope they weren't so atrocious as that in ActiveScript. the worst of both JavaScript and Java.
    – Javier
    May 9, 2011 at 14:04
  • It was planned for JS 4 (or ECMAscript 4) but that version was dropped due to controversy. I'm sure something similar will appear in the future, in some language. (In Python you can sort-of do it with decorators, btw.)
    – Macke
    May 9, 2011 at 14:12
  • 1
    Decorators add dynamic type checking, a sort of assertions. You can't get comprehensive static type checking in Python, however hard you try, due to the extreme dynamism of the language.
    – 9000
    May 9, 2011 at 14:34
  • @9000: That is correct. However, I don't think dynamic type checking is bad though (but I'd prefer duck-type comparisons ala JS4), especially when combined with unit tests, and typeifying decorators could be more useful support IDEs/lint-checkers if they where standardized.
    – Macke
    May 9, 2011 at 14:47
  • of course it is not bad! This is not a matter of morality. At some point, the type must be "checked" in one way or another. If you write *((double *) 0x98765E) in C the CPU will do it and check if 0x98765E is indeed a pointer to a double.
    – Ingo
    May 9, 2011 at 20:24
2

Most of the time, you don't need to, at least not at the level of detail you're suggesting. In PHP, the operators you use make it perfectly clear what you expect the arguments to be; it's a little bit of a design oversight though that PHP will cast your values if at all possible, even when you pass an array to an operation that expects a string, and because the cast isn't always meaningful, you sometimes get strange results (and this is exactly where type checks are useful). Other than that, it doesn't matter if you add integers 1 and 5 or strings "1" and "5" - the mere fact that you are using the + operator signals to PHP that you want to treat the arguments as numbers, and PHP will obey. An interesting situation is when you receive query results from MySQL: Many numeric values are simply returned as strings, but you won't notice since PHP casts them for you whenever you treat them as numbers.

Python is a bit stricter about its types, but unlike PHP, Python has had exceptions from the beginning and uses it consistently. The "easier to ask forgiveness than permission" paradigm suggests to just perform the operation without type checking, and rely on an exception being raised when the types don't make sense. The only downside of this that I can think of is that sometimes, you'll find that somewhere a type doesn't match what you expect it to be, but finding the reason can be tedious.

And there's another reason to consider: Dynamic languages do not have a compilation stage. Even if you have type constraints, they can only fire at runtime, simply because there is no compile time. If your checks lead to runtime errors anyway, it's much easier to model them accordingly: As explicit checks (such as is_XXX() in PHP or typeof in javascript), or by throwing exceptions (like Python does). Functionally, you have the same effect (an error is signalled at runtime when a type check fails), but it integrates better with the rest of the language's semantics. It simply doesn't make sense to treat type errors fundamentally different from other runtime errors in a dynamic language.

1

Python objects do have a type.

You specify the type when you create the object.

At the same time, it would be convenient to have a choice to specify in some cases the type of a variable in a dynamically typed language, instead of doing the type check manually.

Actually, a manual type check in Python is almost always a waste of time and code.

It's simply a bad practice to write type checking code in Python.

If an inappropriate type was used by some malicious sociopath, Python's ordinary methods will raise an ordinary exception when the type fails to be appropriate.

You write no code, your program still fails with a TypeError.

There are very rare cases when you must determine type at run-time.

Why there is such limitation?

Since it's not a "limitation", the question isn't a real question.

3
  • 2
    "Python objects do have a type." - ohh really? Just as perl objects, PHP objects and every other data item in the world. The difference between static and dynamic typing is only when the type is going to be checked, i.e. when type errors manifest themselves. If they appear as compiler errors, it's static typing, if they appear as runtime errors, it's dynamic.
    – Ingo
    May 9, 2011 at 20:16
  • @Ingo: Thanks for the clarification. The issue is that C++ and Java objects can be cast from one type to another, making the type of an object somewhat murky, and therefore making "type checking" in those compilers a bit murky, also. Where Python type checking -- even if it is at run time -- is much less murky. Also, the question runs sort of close to saying dynamically typed languages don't have types. The good news is that it doesn't make that common mistake.
    – S.Lott
    May 9, 2011 at 20:18
  • 1
    You are right, type casts (in contrast to type conversions, i.e. ((double) 42)) subvert static typing. They are needed when the type system is not powerful enough. Before Java 5, Java had no parmeterized types, you couldn't live without type casts then. Today it is much better, yet the type system still lacks higher kinded types, not to speak of higher ranked polymorphism. I think it is well possible that dynamically typed languages enjoy that much followers precisely because they liberate one from too narrow type systems.
    – Ingo
    May 9, 2011 at 20:32
0

As the other answers have alluded to, there are two approaches to typing when implementing a programming language.

  1. Have the programmer tell you what all of the variables and functions use for types. Ideally, you also verify that the type specifications are accurate. Then, because you know what type of thing will be in each place, you can write code that assumes the appropriate thing will be there and uses whatever data structure you use to implement that type directly.
  2. Attach a type indicator to the values that will be stored in variables and passed to and returned from functions. This means that the programmer won't have to specify any types for variables or functions, because the types actually belong to the objects the variables and functions refer to.

Both approaches are valid, and which to use depends partly on technical considerations like performance, and partly on political reasons like the target market for the language.

1
  • In case (1), letting the compiler instead of the programmer figure out the correct type has become fashionable. Just noticed I'm typing this almost nine years later...
    – gnasher729
    Apr 9, 2020 at 16:43
0

First of all dynamic languages are been created mainly for the ease of use. As you have mentioned it is really good to take type conversion automatically, and provide us less overhead. But at the same time it lacks in performance issues.

You can stick with the dynamic languages, at the case your not worrying about the performance. Say for example JavaScript run slower when it needs to perform many type conversion in your program, but it helps to reduce the number of lines in your code.

And to be mention, there are other dynamic languages even that allow the programmer to specify the type. For example Groovy is one of the famous dynamic language that runs on JVM. And it is been very famous in the recent days even. Note that the performance of Groovy is as same as Java.

Hope it helps you.

-1

You may be interested in Haskell - it's type system infers the types from the code, and you can specify types as well.

3
  • 6
    Haskell is a great language. It is somehow an opposite to dynamic languages: you spend a lot of time describing types, and usually once you've figured your types the program works :)
    – 9000
    May 9, 2011 at 14:32
  • @9000: Indeed. Once it compiles, it usually works. :)
    – Macke
    May 9, 2011 at 14:48
  • @Macke - for different values of usually, of course. :-) For me, the greatest benefit of the type system and the functional paradigm is, as I pointed out elsewhere, that one does not have to care whether a change somewhere silently impacts some depending code elsewhere - the compiler will point out type errors and mutable state just does not exist.
    – Ingo
    May 9, 2011 at 15:25
-2

It simply makes no sense to do so.

Why?

Because the type system of DTLs is precisely such that types can't be determined at compile time. Therefore, the compiler couldn't even check that the type specified would make sense.

7
  • 2
    Why? It makes a perfect sense to hint a compiler on what types to expect. It won't contradict any of the type system constraints.
    – SK-logic
    May 9, 2011 at 12:16
  • 1
    SK-logic: If dynamically typed means that every function/method/operations takes objects of type "Dynamic", "Any" or whatever and returns "Dynamic", "Any" whatever, there's in general no way to tell that a certain value will always be an integer, for example. Therefore, runtime code must check for non-integers anyway, just as if the type was "Dynamic" in the first place. This is just what a static type system does: it makes it possible to proove that a certain variable, field or method return will always be of a certain type.
    – Ingo
    May 9, 2011 at 12:25
  • 1
    @Ingo, no, there is a way. See how it is implemented in Common Lisp, for example. It is especially useful for local variables - you can increase performance dramatically by introducing all that typing hints.
    – SK-logic
    May 9, 2011 at 12:28
  • @SK-logic: Perhaps you can tell me when and how type errors are detected in CL? Anyway, @MainMa summarized the status quo quite nicely in his/her question: It's just what one could expect from "purely" dynamic languages.
    – Ingo
    May 9, 2011 at 12:35
  • @Ingo, what makes you think that types are only useful for statically proving correctness? It is not true for even languages like C, where you've got an unchecked type casting. Type annotations in dynamic languages are mostly useful as compiler hints that improves performance or specifies a concrete numeric representation. I'd agree that in most cases annotations should not change semantics of the code.
    – SK-logic
    May 9, 2011 at 12:57
-3

Take a look at Go, on the surface it is statically typed, but those types may be interfaces which are essentially dynamic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.