The ability of the interpreter to deduce type and type conversions makes development time faster, but it also can provoke runtime failures which you just cannot get in a statically typed language where you catch them at compile time. But which one's better (or even if that's always true) is hotly discussed in the community these days (and since a long time).
Advocates of static typing argue that
the advantages of static typing
include earlier detection of
programming mistakes (e.g. preventing
adding an integer to a boolean),
better documentation in the form of
type signatures (e.g. incorporating
number and types of arguments when
resolving names), more opportunities
for compiler optimizations (e.g.
replacing virtual calls by direct
calls when the exact type of the
receiver is known statically),
increased runtime efficiency (e.g. not
all values need to carry a dynamic
type), and a better design time
developer experience (e.g. knowing the
type of the receiver, the IDE can
present a drop-down menu of all
applicable members). Static typing
fanatics try to make us believe that
“well-typed programs cannot go wrong”.
While this certainly sounds
impressive, it is a rather vacuous
statement. Static type checking is a
compile-time abstraction of the
runtime behavior of your program, and
hence it is necessarily only partially
sound and incomplete. This means that
programs can still go wrong because of
properties that are not tracked by the
type-checker, and that there are
programs that while they cannot go
wrong cannot be type-checked. The
impulse for making static typing less
partial and more complete causes type
systems to become overly complicated
and exotic as witnessed by concepts
such as “phantom types” [11] and
“wobbly types” [10]. This is like
trying to run a marathon with a ball
and chain tied to your leg and
triumphantly shouting that you nearly
made it even though you bailed out
after the first mile.
Advocates of dynamically typed
languages argue that static typing is
too rigid, and that the softness of
dynamically languages makes them
ideally suited for prototyping systems
with changing or unknown requirements,
or that interact with other systems
that change unpredictably (data and
application integration). Of course,
dynamically typed languages are
indispensable for dealing with truly
dynamic program behavior such as
method interception, dynamic loading,
mobile code, runtime reflection, etc.
In the mother of all papers on
scripting [16], John Ousterhout argues
that statically typed systems
programming languages make code less
reusable, more verbose, not more safe,
and less expressive than dynamically
typed scripting languages. This
argument is parroted literally by many
proponents of dynamically typed
scripting languages. We argue that
this is a fallacy and falls into the
same category as arguing that the
essence of declarative programming is
eliminating assignment. Or as John
Hughes says [8], it is a logical
impossibility to make a language more
powerful by omitting features.
Defending the fact that delaying all
type-checking to runtime is a good
thing, is playing ostrich tactics with
the fact that errors should be caught
as early in the development process as
possible.
Best Answer
Neither approach has a clear advantage over the other - if one approach was always better, chances are that we'd start using it everywhere!
Generally speaking, compilers offer the following advantages:
Because they can see all the code up-front, they can perform a number of analyses and optimizations when generating code that makes the final version of the code executed faster than just interpreting each line individually.
Compilers can often generate low-level code that performs the equivalent of a high-level ideas like "dynamic dispatch" or "inheritance" in terms of memory lookups inside of tables. This means that the resulting programs need to remember less information about the original code, lowering the memory usage of the generated program.
Generally speaking, compilers have the following drawbacks:
Generally speaking, interpreters have the following advantages:
Because they can read the code as written and don't have to do expensive operations to generate or optimize code, they tend to start up faster than compilers.
Because interpreters can see what the program does as its running, interpreters can use a number of dynamic optimizations that compilers might not be able to see.
Generally speaking, interpreters have the following disadvantages:
Interpreters typically have higher memory usage than compilers because the interpreter needs to keep more information about the program available at runtime.
Interpreters typically spend some CPU time inside of the code for the interpreter, which can slow down the program being run.
Because interpreters and compilers have complementary strengths and weaknesses, it's becoming increasingly common for language runtimes to combine elements of both. Java's JVM is a good example of this - the Java code itself is compiled, and initially it's interpreted. The JVM can then find code that's run many, many times and compile it directly to machine code, meaning that "hot" code gets the benefits of compilation while "cold" code does not. The JVM can also perform a number of dynamic optimizations like inline caching to speed up performance in ways that compilers typically don't.
Many modern JavaScript implementations use similar tricks. Most JavaScript code is short and doesn't do all that much, so they typically start off using an interpreter. However, if it becomes clear that the code is being run repeatedly, many JS engines will compile the code - or at least, compile bits and pieces of it - and optimize it using standard techniques. The net result is that the code is fast at startup (useful for loading web pages quickly) but gets faster the more that it runs.
One last detail is that languages are not compiled or interpreted. Usually, C code is compiled, but there are C interpreters available that make it easier to debug or visualize the code that's being run (they're often used in introductory programming classes - or at least, they used to be.) JavaScript used to be thought of as an interpreted language until some JS engines started compiling it. Some Python implementations are purely interpreters, but you can get Python compilers that generate native code. Now, some languages are easier to compile or interpret than others, but there's nothing stopping you from making a compiler or interpreter for any particular programming language. There's a theoretical result called the Futamura projections that shows that anything that can be interpreted can be compiled, for example.