Hacker News new | ask | show | jobs
by ceor4 3538 days ago
Frankly, each of your three paragraphs seems unrelated to each other, so I'm still not sure what your argument is.

1) Not type checking at runtime is exactly what people mean by static typing, because the definition of static typing means the checks are done before execution.

2) This does not make it harder to optimize, on the contrary if they generated type assertions it would considerable slow things down on the boundary of typed and untyped code.

3) C++, Go, Rust, Haskell they are fully statically typed, the only difference is they support varying levels type-inference which means you don't need to "type out the type" but it's really orthogonal to the whole optional/static/dynamic typing issue.

1 comments

C++ and Go don't have type inference. All they do is set the type of new variables to whatever they're first initialized to. Type inference means figuring out the types of variables from how they're used. The litmus test for type inference is inferring function argument types.
I'm sorry, but that's not the definition of type inference.

"Type inference refers to the automatic deduction of the data type of an expression in a programming language."

https://en.wikipedia.org/wiki/Type_inference

Which you'll notice C++ and Go, are listed as languages with type inference.

But you're right that they don't have as nearly as strong type inference as rust, which doesn't have as strong as haskell etc.

Rust and Haskell have very similar type inference. The only major difference is that Rust doesn't infer type signatures, but that's a design decision, not a power issue.
> "Type inference refers to the automatic deduction of the data type of an expression in a programming language."

Depending on how simple "deduction" can be, that arguably includes every language that includes expressions.

And if the deduction is required to include usage information, it quite arguably excludes C++/Go style "var": a variable declaration is not an expression.

Generally, that Wikipedia article doesn't seem very good - check the talk page.

True, C++ and Go don't have a real type inference engine. They just compute the result type of an expression and use that to create the type of a variable in an assignment. However, this handles enough of the common cases to be quite useful.

(When you have a real type inference engine, you spend a lot of time trying to figure out what it did, or why it didn't do something.)

Nobody forces you to use type inference. If you think a particular piece of code is too tricky to understand without explicit type annotations, by all means use explicit type signatures.

That being said, I have never encountered a program that was hard to understand because types were inferred rather than explicitly annotated. I use explicit type annotations in two situations:

(0) As a compile-time analogue of printf debugging. Not exactly a joyous thing.

(1) At module boundaries, to control what modules expose to each other.

If you don't call what C++ and Go do "type inference", would you call it "type deduction"?
It really doesn't matter what he calls it, as type inference has a well accepted definition that includes Go and C++. See: https://en.wikipedia.org/wiki/Type_inference

Perhaps the parent was trying to talk about "HM type inference" or something, but "type deduction" is also a fine name for a subset of type-inference, and perhaps more explicit for C++ and Go.

Type inference (not just Hindley-Milner) is divided in two logical phases:

(0) Generating a system of type equations, by recursively scanning the AST.

(1) Solving the system of equations. The nontrivial nature of this step is what makes type inference, well, inference.

In Go and C++'s case, the generated type equations come out already solved (that is, of the form `TypeVar = TypeExpr`), so there's nothing to infer!

Perhaps you'd be best up taking it up on wikipedia and primary sources, instead of arguing with random internet people when using their same definitions.
I don't think it deserves a special name. Would you use a special term for the fact you don't need to specify that the sum of two ints is an int?
I disagree. Naming things is useful. "Type deduction" says clearly what happens, and is still distinct enough from "type inference" which is a different, more sophisticated concept. I've seen the term "type deduction" used many times in the context of C++ and Rust.
Rust has actual type inference. It just happens to be a local affair. For example, you can create a vector, even an empty one, without explicitly specific its element type. But, somewhere in the current function, you have to provide information about the element type, say, by inserting elements into the vector, or by using an element in a way that constrains its type.
The ability to name things is useful, but there are far more things out there than we can come up with good names for, so we have to decide wisely what things we name and what things we don't. Something like C++'s `auto` doesn't need a name of its own. It's just unidirectionally propagating type information from child to parent nodes in the AST. This is something even FORTRAN (when its name was all caps) and ALGOL implementations did during normal type checking.