I hear a lot that new programming languages are dynamically typed but what does it actually mean when we say a language is dynamically typed vs. statically typed?
相关问题
- Is divide by zero an error or an exception?
- Inferred Type and Dynamic typing
- How do you measure the popularity of a programming
- Common Lisp type declarations not working as expec
- How to use static type checking using Dict with di
相关文章
- Are there any reasons not to use “this” (“Self”, “
- Call/Return feature of classic C++(C with Classes)
- What are the major differences between C and C++ a
- When is sqlite's manifest typing useful?
- Implement a mutex in Java using atomic variables
- A common set of problems to learn new languages
- Why do COM libraries used from C# 4.0 require such
- Enforcing types on untyped data in TypeScript
Here is an example contrasting how Python (dynamically typed) and Go (statically typed) handle a type error:
Python does type checking at run time, and therefore:
Runs perfectly fine, and produces the expected output
Hi
. Error is only raised if the problematic line is hit:Produces
because the relevant line was actually executed.
Go on the other hand does type-checking at compile time:
The above will not compile, with the following error:
Simply put it this way: in a statically typed language variables' types are static, meaning once you set a variable to a type, you cannot change it. That is because typing is associated with the variable rather than the value it refers to.
For example in Java:
Where on the other hand: in a dynamically typed language variables' types are dynamic, meaning after you set a variable to a type, you CAN change it. That is because typing is associated with the value it assumes rather than the variable itself.
For example in Python:
So, it is best to think of variables in dynamically typed languages as just generic pointers to typed values.
To sum up, type describes (or should have described) the variables in the language rather than the language itself. It could have been better used as a language with statically typed variables versus a language with dynamically typed variables IMHO.
Statically typed languages are generally compiled languages, thus, the compilers check the types (make perfect sense right? as types are not allowed to be changed later on at run time).
Dynamically typed languages are generally interpreted, thus type checking (if any) happens at run time when they are used. This of course brings some performance cost, and is one of the reasons dynamic languages (e.g., python, ruby, php) do not scale as good as the typed ones (java, c#, etc.). From another perspective, statically typed languages have more of a start-up cost: makes you usually write more code, harder code. But that pays later off.
The good thing is both sides are borrowing features from the other side. Typed languages are incorporating more dynamic features, e.g., generics and dynamic libraries in c#, and dynamic languages are including more type checking, e.g., type annotations in python, or HACK variant of PHP, which are usually not core to the language and usable on demand.
When it comes to technology selection, neither side has an intrinsic superiority over the other. It is just a matter of preference whether you want more control to begin with or flexibility. just pick the right tool for the job, and make sure to check what is available in terms of the opposite before considering a switch.
The terminology "dynamically typed" is unfortunately misleading. All languages are statically typed, and types are properties of expressions (not of values as some think). However, some languages have only one type. These are called uni-typed languages. One example of such a language is the untyped lambda calculus.
In the untyped lambda calculus, all terms are lambda terms, and the only operation that can be performed on a term is applying it to another term. Hence all operations always result in either infinite recursion or a lambda term, but never signal an error.
However, were we to augment the untyped lambda calculus with primitive numbers and arithmetic operations, then we could perform nonsensical operations, such adding two lambda terms together:
(λx.x) + (λy.y)
. One could argue that the only sane thing to do is to signal an error when this happens, but to be able to do this, each value has to be tagged with an indicator that indicates whether the term is a lambda term or a number. The addition operator will then check that indeed both arguments are tagged as numbers, and if they aren't, signal an error. Note that these tags are not types, because types are properties of programs, not of values produced by those programs.A uni-typed language that does this is called dynamically typed.
Languages such as JavaScript, Python, and Ruby are all uni-typed. Again, the
typeof
operator in JavaScript and thetype
function in Python have misleading names; they return the tags associated with the operands, not their types. Similarly,dynamic_cast
in C++ andinstanceof
in Java do not do type checks.Compiled vs. Interpreted
"When source code is translated"
Typing
"When types are checked"
5 + '3'
is an example of a type error in strongly typed languages such as Go and Python, because they don't allow for "type coercion" -> the ability for a value to change type in certain contexts such as merging two types. Weakly typed languages, such as JavaScript, won't throw a type error (results in'53'
).The definitions of "Static & Compiled" and "Dynamic & Interpreted" are quite similar...but remember it's "when types are checked" vs. "when source code is translated".
You'll get the same type errors irrespective of whether the language is compiled or interpreted! You need to separate these terms conceptually.
Python Example
Dynamic, Interpreted
Because Python is both interpreted and dynamically typed, it only translates and type-checks code it's executing on. The
else
block never executes, so5 + '3'
is never even looked at!What if it was statically typed?
A type error would be thrown before the code is even run. It still performs type-checking before run-time even though it is interpreted.
What if it was compiled?
The
else
block would be translated/looked at before run-time, but because it's dynamically typed it wouldn't throw an error! Dynamically typed languages don't check types until execution, and that line never executes.Go Example
Static, Compiled
The types are checked before running (static) and the type error is immediately caught! The types would still be checked before run-time if it was interpreted, having the same result. If it was dynamic, it wouldn't throw any errors even though the code would be looked at during compilation.
Performance
A compiled language will have better performance at run-time if it's statically typed (vs. dynamically); knowledge of types allows for machine code optimization.
Statically typed languages have better performance at run-time intrinsically due to not needing to check types dynamically while executing (it checks before running).
Similarly, compiled languages are faster at run time as the code has already been translated instead of needing to "interpret"/translate it on the fly.
Note that both compiled and statically typed languages will have a delay before running for translation and type-checking, respectively.
More Differences
Static typing catches errors early, instead of finding them during execution (especially useful for long programs). It's more "strict" in that it won't allow for type errors anywhere in your program and often prevents variables from changing types, which further defends against unintended errors.
Dynamic typing is more flexible, which some appreciate. It typically allows for variables to change types, which can result in unexpected errors.
http://en.wikipedia.org/wiki/Type_system
Statically typed languages: each variable and expression is already known at compile time.
(
int a;
a can take only integer type values at runtime)Examples: C, C++, Java
Dynamically typed languages: variables can receive different values at runtime and their type is defined at run time.
(
var a;
a can take any kind of values at runtime)Examples: Ruby, Python.