-3

Below is an answer explaining Dynamic vs. Static Typing.

I'm confused why this demonstrates Dynamic vs. Static typing as I thought all errors for compiled languages are caught during compilation anyway so it wouldn't matter whether it's statically or dynamically typed.

Maybe this is demonstrating that statically typed languages always raise errors before running and dynamic typing will always raise errors during execution regardless of it being compiled or interpreted?

Can someone explain this more in depth?

Here is an example contrasting how Python (dynamically typed) and Go (statically typed) handle a type error:

def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

Python does type checking at run time, and therefore:

silly(2)

Runs perfectly fine, and produces the expected output Hi. Error is only raised if the problematic line is hit:

silly(-1) 

Produces

TypeError: unsupported operand type(s) for +: 'int' and 'str'

because the relevant line was actually executed.

Go on the other hand does type-checking at compile time:

package main

import ("fmt"
)

func silly(a int) {
  if (a > 0) {
      fmt.Println("Hi")
  } else {
      fmt.Println("3" + 5)
  }
}

func main() {
  silly(2)
} 

The above will not compile, with the following error:

invalid operation: "3" + 5 (mismatched types string and int)
JBallin
  • 8,481
  • 4
  • 46
  • 51
  • Well, actually there are third-party static-type checkers for Python (with more and more built-in language support for static-type checking), so a language can be interpreted (as Python still is) and have static-type checking, which would have complained for `def silly(a)`. – juanpa.arrivillaga Dec 05 '17 at 00:32
  • sure but the answer is just trying to explain static vs dynamic, can you clarify how your comment is relevant? not trying to be rude, just want to understand. to me it looks like you're just pointing out an exception to his answer. – JBallin Dec 05 '17 at 00:34
  • That the difference isn't whether the language is compiled or interpreted, the difference is *when the type checking occurs*. I've given you an example that type-checking can happen statically, i.e. not at runtime, for Python if you use a third-party static-type checker. Therefore, the difference truly is whether the type-checking happens statically before run time (e.g. Python + mypy) or at run time (just Python). – juanpa.arrivillaga Dec 05 '17 at 00:36
  • Also, I'm sure there is some variety of LISP that is compiled, but still dynamically typed. Also note, Python already does a compilation step, where it checks for certain errors, e.g. syntax errors, unbound-local errors, before executing on the interpreter. There's no reason in principle why static-typing couldn't occur in that step. – juanpa.arrivillaga Dec 05 '17 at 00:38
  • Python isn't entirely interpreted; the reference implementation has a compilation phase during which bytecode is generated. It is this bytecode that is later executed by the Python interpreter. (Other implementations run on the .NET CLR or the Java VM and are also compiled to different bytecode.) It is therefore feasible for Python to be type-checked even though it's thought of as an interpreted language. These days the distinction between compiled and interpreted languages is so fuzzy as to be useful mainly as an indicator of performance; dynamic and static are more useful categories. – kindall Dec 05 '17 at 00:42
  • You are correct. – Hector Correa Dec 05 '17 at 01:30

2 Answers2

2

Compiled <-> interpreted scale is completely orthogonal to the dynamic <-> static typing scale. (and potentially another orthogonal scale of compile-time type checked and runtime type-checked)

For example, you can compile the Python script from the example using Cython to a native binary. It will work exactly the same way, but it's going to be compiled. The Python script can be also type-checked ahead of time using mypy and be run using CPython which provides runtime type exceptions.

On the other hand, you can install a language with static types and an interactive shell (interpreter) and try a similar expression - you'll get a type error before the code executes. This part is slightly confusing, since to get a type error, you need to compile the code to some extent (process into AST and type check), but I don't think it matches the common definition of "compiled".

In summary, you can have compiled dynamically typed, compiled statically, interpreted dynamically typed, and interpreted statically typed. (And the linked example from the repl can be argued it's about strong typing - feel free to provide a better one)

viraptor
  • 33,322
  • 10
  • 107
  • 191
  • 1
    1st paragraph is interesting. But do you agree that the answer provided is not an example of static vs dynamic? – JBallin Dec 05 '17 at 01:17
  • 1
    @JBallin Sorry, I did get off-topic there a bit :) To be precise, I'd say it provides an example of run-time strong types (CPython) -vs- compile-time strong types (Golang). It shows there's no automatic coercion between string and integer in either language (strong typing) and that there's no compile-time type checking in the CPython implementation of Python. – viraptor Dec 05 '17 at 02:29
1

No. Type errors are not caught in compilation unless the language is statically typed.

Note that compilation WILL catch syntax errors regardless of typing.


The example is confusing as it couples "Static & Compiled" with "Dynamic & Interpreted" which obscures the effects of the different type systems.

  • Go example WOULD NOT throw an error if it was dynamically typed, despite being compiled!
  • Python example WOULD throw an error if it was statically typed, even though that line would never be interpreted!

Type-checking has nothing to do with the language being compiled or interpreted!


I'll review the basic concepts, then delve deeper into the example.


Compiled vs. Interpreted

"When source code is translated"

  • Source Code: Original code (usually typed by a human into a computer)
  • Translation: Converting source code into something a computer can read (i.e. machine code)
  • Run-Time: Period when program is executing commands (after compilation, if compiled)
  • Compiled Language: Code translated before run-time
  • Interpreted Language: Code translated on the fly, during execution

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

  • Static: Types checked before run-time
  • Dynamic: Types checked on the fly, during execution

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

def silly(a):
    if a > 0:
        print 'Hi'
    else:
        print 5 + '3'

silly(2)

Because Python is both interpreted and dynamically typed, it only translates and type-checks code it's executing on. The else block never executes, so 5 + '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

package main

import ("fmt"
)

func silly(a int) {
  if (a > 0) {
      fmt.Println("Hi")
  } else {
      fmt.Println("3" + 5)
  }
}

func main() {
  silly(2)
}

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.

num = 2
num = '3' // ERROR

Dynamic typing is more flexible, which some appreciate. It typically allows for variables to change types, which can result in unexpected errors.

JBallin
  • 8,481
  • 4
  • 46
  • 51