CMUCL Python compiler (not to be confused with the much younger language of the same name), which is also used by CMUCL's descendants like SBCL, is famous for the amount of type-guided optimisation it performs. If it can subtype, or you can inform you of appropriately narrow type, it will happily replace more generic arithmetic and with (safety 0) elide all safety checks.
Opposite of static typing is dynamic typing.
Both CL and Python are strongly and dynamically typed by default. Their values have well defined types, variables don't.
C/C++ are statically and weakly typed. Haskell and Java is statically and strongly typed. Many shell and scripting languages are weakly or loosely and dynamically typed.
(defun foo (bar)
(declare (type (integer 100 200) bar))
...)
Above declares the variable BAR to have the type of a subtype of integers between 100 and 200.The language standard does not enforce any static type checking.
What implementations typically might do:
* ignore it: interpreters, Lisp Machines, etc.
* use it for optimizations: most compilers incl. SBCL
* do type inference: many compilers incl. SBCL
* use it at runtime for type assertions: SBCL
* use it at compile time for type checks: SBCL
The strong/weak distinction isn't particularly valuable in the first place, but it becomes especially useless if you try to shoehorn C/C++ into the "weak" category.
Firstly, Ability to circumvent type system means it's a weak type system. In in C and C++ you can take pointer to anything and cast it into anything. The memory model in both languages is just one or more contiguous sequences of bytes. https://en.cppreference.com/w/cpp/language/memory_model
Secondly, What you call "functional/academic language snobbery" is accurate language that every software engineer benefits from using and understanding. Being professional is not snobbery or elitism.
C: (type) casts
C++: reinterpret_cast and friends
Haskell: unsafeCoerce
Ocaml: Obj.magic
Golang: unsafe.Pointer
Rust: std::mem::transmute
SML: MLton doesn't provide one, but SML/NJ provides
Unsafe.cast. So I guess MLton's flavor of SML
is strongly typed, but SML/NJ's is weakly typed.
Any definition of "weakly typed" which excludes Haskell and Ocaml is farcical, inaccurate, and doesn't benefit any software engineer, especially the professional ones.Here is a definition: a language is weakly typed if and only if it has implicit type conversion. JavaScript is weakly typed:
> "3" * "4"
12
Haskell is not: ghci> "3" * "4"
<interactive>:1:5: error:
• No instance for (Num String) arising from a use of ‘*’
• In the expression: "3" * "4"
In an equation for ‘it’: it = "3" * "4"
Neither is OCaml: utop # "3" * "4";;
Error: This expression has type string but an expression was expected of type
int
C++ is weakly typed: #include <iostream>
int main() {
int x = 7;
bool y = x;
std::cout << x << "\n";
std::cout << y << "\n";
return 0;
}
which prints 7
1
Haskell and OCaml are not weakly typed: ghci> let x = 7 in let (y :: Bool) = x in print y
<interactive>:4:32: error:
• No instance for (Num Bool) arising from a use of ‘x’
• In the expression: x
In a pattern binding: (y :: Bool) = x
In the expression: let (y :: Bool) = x in print y
utop # let x = 7 in let (y : bool) = x in Printf.printf "%B\n" y;;
Error: This expression has type int but an expression was expected of type booldoes typescript-like type checking (which barks on 1+”1”) with “disallow emit on error” turn javascript into the strongly typed one?
Polymorphism is not the same as implicit type conversion. For example, in Haskell, `*` is defined for both integers and doubles so 3 * 4 and 3.0 * 4.0 both work without type conversion. But JavaScript converts strings to numbers in "3" * "4".
> does typescript-like type checking (which barks on 1+”1”) with “disallow emit on error” turn javascript into the strongly typed one?
I think so. And this is not surprising. TypeScript is a different language from JavaScript (even if it’s a superset of it).
On the other hand, Haskell's unsafeCoerce or OCaml Obj.magic are usually not considered to be part of the language, since they are "normal" functions, but it is impossible to implement them inside the language.
Common Lisp has always had types and type declarations (e.g. `the` in the hyperspec[1]) as it's part of the specification. It was not added later as far as I know.
However, `declaim` and `declare` were left very underspecified so they tend to be very implementation-specific, though there are libraries that make types more portable[2][3].
[1] http://www.lispworks.com/documentation/HyperSpec/Body/s_the....
[2] https://github.com/lisp-maintainers/defstar
[3] https://github.com/ruricolist/serapeum/blob/master/REFERENCE...