I\'m reading a slide deck that states \"JavaScript is untyped.\" This contradicted what I thought to be true so I started digging to try and learn more.
Every answer
This question is all about Semantics
If I give you this data: 12
what is it's type? You have no way of knowing for sure. Could be an integer - could be a float - could be a string. In that sense it's very much "untyped" data.
If I give you an imaginary language which lets you use operators like "add", "subtract", and "concatenate" on this data and some other arbitrary piece of data the "type" is somewhat irrelevant (to my imaginary language) (example: perhaps add(12, a)
yields 109
which is 12
plus the ascii value of a
).
Let's talk C for a second. C pretty much lets you do whatever you want with any arbitrary piece of data. If you're using a function that takes two uint
s - you could cast and pass anything you want - and the values will simply be interpreted as uint
s. In that sense C is "untyped" (if you treat it in such a way).
However - and getting to Brendan's point - if I told you that "My age is 12
" - then 12
has a type - at least we know it's numeric. With context everything has a type - regardless of the language.
This is why I said at the beginning - your question is one of semantics. What is the meaning of "untyped"? I think Brendan hit the nail on the head when he said "no static types" - because that's all it can possibly mean. Humans naturally classify things into types. We intuitively know that there is something fundamentally different between a car and a monkey - without ever being taught to make those distinctions.
Getting back to my example in the beginning - a language that "doesn't care about types" (per-se) may let you "add" an "age" and a "name" without producing a syntax error... but that doesn't mean it's a logically sound operation.
Javascript may let you do all sorts of crazy things without considering them "errors". That doesn't mean what you are doing is logically sound. Thats for the developer to work out.
Is a system/language which doesn't enforce type safety at compile/build/interpretation time "untyped" or "dynamically typed"?
Semantics.
EDIT
I wanted to add something here because some people seem to be getting caught up on "yeah, but Javascript does have some "types"".
In my comment on someone else's answer I said:
In Javascript I could have objects I've built up to be "Monkeys" and objects I've built up to be "Humans" and some functions could be designed to operate on only "Humans", others on only "Monkeys", and yet others on only "Things With Arms". Whether or not the language has ever been told there is such a category of objects as "things with arms" is as irrelevant to assembly ("untyped") as it is to Javascript ("dynamic"). It's all a matter of logical integrity - and the only error would be using something that didn't have arms with that method.
So, if you consider Javascript to have some "notion of types" internally - and, hence "dynamic types" - and think this is somehow "distinctly different from an untyped system" - you should see from the above example that any "notion of types" it has internally is really irrelevant.
To perform the same operation with C#, for example, I'd NEED an interface called ICreatureWithArms
or something similar. Not so in Javascript - not so in C or ASM.
Clearly, whether or not Javascript has any understanding of "types" at all is irrelevant.
Both statements are correct, depending on whether you are talking about values or variables. JavaScript variables are untyped, JavaScript values have types, and variables can range over any value type at runtime (i.e. 'dynamically').
In JavaScript and many other languages, values and not variables carry types. All variables can range over all types of values and may be considered "dynamically typed" or "untyped" - from the perspective of type-checking a variable that has no/unknowable type and a variable that can take any type are logically and practically equivalent. When type theorists talk about languages and types, they are usually talking about this - variables carrying types - because they are interested in writing type checkers and compilers and so on, which operate on program text (i.e. variables) and not a running program in memory (i.e. values).
By contrast in other languages, like C, variables carry types but values do not. In languages like Java, variables and values both carry types. In C++, some values (those with virtual functions) carry types and others do not. In some languages it is even possible for values to change types, although this is usually considered bad design.
I've looked into it, and found that the answer to your question is simply, and surprisingly, "yes": academic CS types, or at least some of them, do use "untyped" to mean "dynamically typed". For example, Programming Languages: Principles and Practices, Third Edition (by Kenneth C. Louden and Kenneth A. Lambert, published 2012) says this:
Languages without static type systems are usually called untyped languages (or dynamically typed languages). Such languages include Scheme and other dialects of Lisp, Smalltalk, and most scripting languages such as Perl, Python, and Ruby. Note, however, that an untyped language does not necessarily allow programs to corrupt data—this just means that all safety checking is performed at execution time. […]
[link] (note: bolding in original) and goes on to use "untyped" in just this way.
I find this surprising (for much the same reasons that afrischke and Adam Mihalcin give), but there you are. :-)
Edited to add: You can find more examples by plugging "untyped languages"
into Google Book Search. For example:
[…] This is the primary information-hiding mechanism is many untyped languages. For instance PLT Scheme [4] uses generative
struct
s, […]
— Jacob Matthews and Amal Ahmed, 2008 [link]
[…], we present a binding-time analysis for an untyped functional language […]. […] It has been implemented and is used in a partial evaluator for a side-effect free dialect of Scheme. The analysis is general enough, however, to be valid for non-strict typed functional languages such as Haskell. […]
— Charles Consel, 1990 [link]
By the way, my impression, after looking through these search results, is that if a researcher writes of an "untyped" functional language, (s)he very likely does consider it to be "untyped" in the same sense as the untyped lambda calculus that Adam Mihalcin mentions. At least, several researchers mention Scheme and the lambda calculus in the same breath.
What the search doesn't say, of course, is whether there are researchers who reject this identification, and don't consider these languages to be "untyped". Well, I did find this:
I then realized that there is really no circularity, because dynamically typed languages are not untyped languages — it's just that the types are not usually immediately obvious from the program text.
— someone (I can't tell who), 1998 [link]
but obviously most people who reject this identification wouldn't feel a need to explicitly say so.
Untyped and dynamically typed are absolutely not synonyms. The language that is most often called "untyped" is the Lambda Calculus, which is actually a unityped language - everything is a function, so we can statically prove that the type of everything is the function. A dynamically typed language has multiple types, but does not add a way for the compiler to statically check them, forcing the compiler to insert runtime checks on variable types.
Then, JavaScript is a dynamically typed language: it is possible to write programs in JavaScript such that some variable x
could be a number, or a function, or a string, or something else (and determining which one would require solving the Halting Problem or some hard mathematical problem), so you can apply x
to an argument and the browser has to check at runtime that x
is a function.
Agree with Brendan - context is everything.
My take:
I remember being confused, circa 2004, because there were arguments breaking out about whether Ruby was untyped or dynamically typed. Old school C/C++ people (of which I was one) were thinking about the compiler and saying Ruby was untyped.
Remember, in C, there are no runtime types, there are just addresses and if the code that's executing decides to treat whatever's at that address as something it isn't, whoops. That's definitely untyped and very different from dynamically typed.
In that world, "typing" is all about the compiler. C++ had "strong typing" because the compiler's checks were more stringent. Java and C were more "weakly typed" (there were even arguments about whether Java was strongly or weakly typed). Dynamic languages were, in that continuum, "untyped" because they had no compiler type checking.
Today, for practicing programmers, we're so used to dynamic languages, we obviously think of untyped to mean no compiler nor interpreter type-checking, which would be insanely hard to debug. But there was a period there where that wasn't obvious and in the more theoretical world of CS is may not even be meaningful.
In some deep sense, nothing can be untyped (or almost nothing, anyway) because you must have some intent in manipulating a value to write a meaningful algorithm. This is the world of theoretical CS, which isn't dealing with the specifics of how a compiler or interpreter is implemented for a given language. So "untyped" is (probably, I don't know) entirely meaningless in that context.
While it is true that most of the CS researchers that write about types essentially consider only languages with syntactically-derivable types as typed languages, there are lots more of us using dynamically/latently typed languages who take umbrage at that usage.
I consider there to be 3 types [SIC] of languages:
Untyped - only the operator determines the interpretation of the value - and it generally works on anything. Examples: Assembler, BCPL
Statically typed - expressions/variables have types associated with them, and that type determines the interpretation/validity of the operator at compile-time. Examples: C, Java, C++, ML, Haskell
Dynamically typed - values have types associated with them, and that type determines the interpretation/validity of the operator at run-time. Examples: LISP, Scheme, Smalltalk, Ruby, Python, Javascript
To my knowledge, all dynamically-typed languages are type-safe - i.e. only valid operators can operate on values. But the same is not true for statically-typed language. Depending on the power of the type system used, some operators may be checked only at run-time, or not at all. For example, most statically-typed languages do not handle integer overflow properly (adding 2 positive integers can produce a negative integer), and out-of-bound array references are either not checked at all (C, C++) or are checked only at run-time. Further, some type systems are so weak that useful programming requires escape hatches (casts in C and family) to change the compile-time type of expressions.
All of this leads to absurd claims, such as that C++ is safer than Python because it's (statically-typed), whereas the truth is that Python is intrinsically safe while you can shoot your leg off with C++.