3

After reading this post:

How does an interpreter/compiler work

I have this question:

In a programming language that has only interpreter (for example Basic) (as shown in the photo in the second answer in the above link) is it possible to have static type checking??.
As far as I know the interpreter run each single line-command every time we execute the program. So how could be possible to do check the types statically before we run the program??

Community
  • 1
  • 1
coder
  • 12,832
  • 5
  • 39
  • 53
  • 1
    Doesn't "interpreter" mean "no types" by definition? – barak manos Sep 08 '16 at 09:32
  • 1
    It depends on your definition of "statically typed". If you mean "known at compile time", then no, interpreted only languages cannot have statically typed variables simply because there is no "compile time" step. If you mean "variable is locked to a type" then yes, an interpreted language can have statically typed variables. I've seen both definitions, which is why I bring it up. Usually the term is referring to the first definition. – Lasse V. Karlsen Sep 08 '16 at 09:33
  • 1
    But the whole issue is blurry because many interpreted languages also have a compile step, it just happens at runtime. So the case in which you're asking should be made explicitly clear, otherwise the only answer that can be given is "it depends". – Lasse V. Karlsen Sep 08 '16 at 09:34
  • @ Lasse V. Karlsen ,I mean "known at compile time" ,thanks for the answer ,I just want to make sure if i had thought this right thanks!!!! – coder Sep 08 '16 at 09:34
  • A language is a language, it is neither interpreted nor compiled. *The interpreter* for that language or *the compiler* for that language is what determines how it runs. The same language can be run through an interpreter *or* compiled by a compiler. Many languages have multiple compiled/interpreted implementations. The same language can also be *statically analysed*, with the static analyser trying to infer as much type information as it can without actually executing the code. – deceze Sep 08 '16 at 09:43
  • @ deceze ,Yes but with interpreter everything is decided in running time ,so how could we talk about static typing language??? – coder Sep 08 '16 at 09:46
  • That is not the deciding factor. Imagine a *type annotated* language, e.g. `Foo foo = new Foo()`… An interpreter could heed those type hints *at runtime* and throw errors when they don't match. Conversely, you can perfectly have *non-type annotated* languages which are compiled: `let foo = new Foo()`. The compiler is able to *infer* the type here pretty obviously. And so can a static analyser. – deceze Sep 08 '16 at 09:52
  • 3
    As an example: Haskell is a well-known statically typed PL. You can run a Haskell program via the interpreter `runhaskell hello.hs`. Haskell does check the types first — compile time is just before run time. – Steven Shaw Sep 08 '16 at 12:23

2 Answers2

2

It is common to say that a statically typed programming language is type checked "at compile time", so it might be easy to say "interpreters don't have a compile time1 and therefore can't be statically typed", but really "static" doesn't necessarily mean "at compile time", it means "before run time" or "without running the code".

So a statically typed language is one where a type error anywhere in the program will cause the program not to run. Whereas in a dynamically typed language a type error will only abort execution when and if control flow reaches the ill-typed statement.

So given this definition can a statically typed language be implemented using an interpreter? Sure. Just let the interpreter find type errors in the program (using the same algorithms a compiler would use) before it starts executing anything and voilà you have static type checking.

The reason you might not want to do that is that it increases startup time as it introduces an additional step before the code starts executing. And depending on the complexity of your type system, type checking may actually consume a lot of time. So that can be quite annoying for an interpreter, but it's definitely possible.


1 This is only true for very simple interpreters though. Most real-world interpreters involve some code generation, be it bytecode or JITed machine code.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
1

A language is a language, it is neither interpreted nor compiled, until it is. Meaning, the same language can be interpreted on the fly or it can be compiled into a binary. In fact, an interpreter does compile the code on the fly into byte code.

The main difference between compiled and interpreted languages is that an interpreted program needs a separate runtime, while a compiled program can typically run by itself or with minimal bootstrap help from the operating system. A compiler will typically also spend more time on the compilation step than an interpreter, where it can do more in-depth error checking and code optimisations. An interpreter doesn't do this only because it is a slow process, not because it's fundamentally impossible.

Type hints/inference is a completely separate problem. Many languages which are primarily compiled use type hints extensively, because the compiler has the time to use that information. Mainly interpreted languages often forgo type hints, because the additional type checking costs time at runtime, and the design goal for the language is a fast development cycle to begin with, which includes less typing. That doesn't mean those languages are "type free" by any means, every single value still has a type, and that type is known. In fact, even many compiled languages these days forgo explicit type annotation when it is unnecessary for brevity. For example:

Foo foo = new Foo();

let foo = new Foo();

The Foo type hint here is rather superfluous; of course the compiler can infer that foo is of type Foo here, just looking at the right hand side of the assignment. The same goes for any other type, including numbers, strings and so on. A compiler or static type analyser can trace what values are being assigned to variables or returned from functions and infer a lot about types without a single explicit annotation.

Having said this, in unannotated languages which heavily depend on runtime information, in some situations it's not possible to know what type a variable will be until runtime. In that case a static type analyser or compiler cannot help in advance and cannot catch errors resulting from incompatible types at compile time. For example, TypeScript is a bolt-on solution for static typing for Javascript, and it walks that line. Everything you do annotate in TypeScript is rigorously type checked; anything you do not annotate or leave as any cannot be type checked and may blow up in your face at runtime.

Type systems in statically typed languages and dynamically typed languages serve different purposes (note statically vs. dynamically typed, not "compiled" vs. "interpreted"). Static typing serves mainly to catch errors at compile time and give a compiler more information to produce better code; dynamic typing serves to define program behaviour, i.e. how values of two types should behave when operated upon, which includes throwing an error on incompatible types. Such incompatible type errors can still be predicted by a static analyser, even if not in all situations.

deceze
  • 510,633
  • 85
  • 743
  • 889
  • deceze, I agree that the characteristics of a language depends on the designing process of the language ,but I can't when it comes to check the types which I believe the type checking is independent (as you also mention) from the language ,the I think we couldn't statically check the types with only interpreter?? – coder Sep 08 '16 at 11:33
  • I'm not sure I understand what you're asking, but… If you assign a number to a variable, it's clear that the variable will hold a value of type number. If then the code goes on to only do numeric operations on that value, it's very clear and easy to trace that this value will continue to be a number. That's what a static analyser can do perfectly fine. There are situations in code where the analyser will cease to be able to infer the type in advance, e.g. `foo = rand(0, 1) ? 42 : 'bar'`. In that case it can either raise a warning about type safety, or give up predictability features. – deceze Sep 08 '16 at 11:46