Hacker Read top | best | new | newcomments | leaders | about | bookmarklet login

I read lots of complaints about how hard it is to discover what types of arguments are needed and what types result for any particular function. If they were declared, there would be no need to dig and guess.


sort by: page size:

On the other hand, big codebases without type hints rely on their engineers remembering types of every argument. Or the functions being overly defensive.

Each to their own liking, I prefer knowing what argument types a function accepts so I don't need to think about it, and focus on writing business logic. If the function could accept more types, Id just improve it.


One pattern that I've seen in recently-designed programming languages is to make type declarations mandatory for function arguments and return values, but to make them optional for local variables. In other words, these languages do not attempt to perform program-wide inference.

One big advantage of this approach is that function types and return values are always documented in the source. But another advantage is that when type inference needs to look at many functions at once, then type errors are frequently misleading and they are reported far from the cause. By requiring parameter and return types to be declared, type inference will always report errors in the correct function.

It does also help to have a good IDE. rust-analyzer, for example, can show the inferred types of local variables, or even automatically insert the inferred type into the source code.


I don't agree with this at all. Having the types of every variable written explicitly in the code is important documentation that answers very quickly the question 'what is the type of this thing' without having to look everywhere and anywhere to perhaps find out that it could be any one of three types. If you do not know the type of something you also do not know what operations are available on that thing.

To me, if you feel compelled to start putting type information in the variable names, function names, etc., what you're showing is that you really want a type system.

I think if you're already documenting function argument types, there is no point. But in my experience it's unworkable to ask people to write full documentation for every function, but requiring type hints is not as hard and is nearly as useful. It is a little weird that they look like code, but I think you get used to it.

It's about readability. You write the types for documentation, and to make it easier for people doing a code walkthrough to simulate what is happening in their heads.

IDEs can add type annotations not present in the code, but there are many contexts (source control diffs, or code in a PDF, or code in a website) where that kind of software type annotation is not available.

I find that in OCaml, which has type inference for everything (function arguments, function return type, local variables, expressions) I end up writing the types almost everywhere, for two reasons. The first is documentation: it helps me to read and understand code I wrote ages ago.

But the second is that type inference often goes haywire, because the compiler doesn't know ahead of time whether the code you wrote is in error. So when you make a mistake, like forgetting to pass the right number of arguments to a curried function, the compiler will happily propagate that mistake around, even propagating the erroneously-inferred types to other functions. And you get these incomprehensible type error messages that come from places that are very separate from where the mistake actually happened.

And then I find myself taking a random walk through the code, adding type annotations to constrain the inference until I find my mistake. So why not skip the middle step, and require annotations?

Often, however, it isn't obvious what the type of an expression is going to be, and it's easier to construct the value level than the type level. For those cases you could simply force a type error to find out the type and write it in the text.

The simplicity reason is not that inference rules vary by compiler (the rules can be put in the spec), it's that type inference (as opposed to one-directional type propagation) can be complex to implement, and for simple extensions to an H-M type system it can become undecidable.


I mean it can be gradual. There already are ways of compiling functions which require type annotations, just make those less of a pain in the ass.

> I have to annotate all structs and function input types.

Can you elaborate on that? Argument types in function definitions do not help the compiler infer types - you can leave them completely untyped. It's really only required in struct fields, so that the compiler can know the size of your struct and doesn't have to box everything.


Type hints just make everything so much easier. When you're writing a function, you _know_ that parameter is an int, or float, or something you can use a list comprehension on (iterable). Why not just say it right there in the function definition?

It's better than writing it in a docstring, because a type checker will tell you to change the type if you change how you use a variable.

Does everyone need to go all the way and type 100% of things and use heavily generic code to represent all possible cases? Well, that would be wonderful, but just sprinkling built-in types is already a massive improvement over no types at all.


I think explicit types for function arguments and return types are a good thing, even in languages that support their omission.

For local variables, it's probably not necessary, unless the type is especially complicated.

Though, I wouldn't call putting type annotations on all variables as a bad thing.

As an aside, Intellij has this great future with Scala where it displays the inferred type of all functions and variables automatically.


Yeah exactly, there's like zero difference to the compiler. That's why it's such an easy feature. (To be fair you probably also want some syntactic niceties like destructuring bindings.) But clearly in practice, no one wants to define a new named struct type for every function that needs to return an error. I think part of the pain is that, without some sort of "auto" type deduction feature, you force the caller to type out the name of the return type most of the time, in addition to the name of the function. And yeah, if I had type out StringAndError or IntAndError a million times to use a library, I'm sure I'd hate that library :)

Type inference is good for the writer, not the reader.

Relying on type inference isn’t some rule. Your can find many projects that use it selectively, being explicit where it makes sense. The point of writing code is to make it readable and maintainable. The explicit type isn’t redundant, it’s explicit in presentation, and can be functional, like my example.

I mean, just look at this example. You know the type without having to dig in, do you not? You don’t have to look at the function definition. You know immediately. That’s the point of being explicit, where it makes sense. No guessing, where it makes sense. This is why we have all these type hints now, in a dynamic language: because guessing sucks.


You add the types on every function definition, and almost never have a problem.

Many people forget that the point of type inference is to eliminate uselessly redundant clutter, not to completely eliminate types from source code. A function is usually called many times, so keeping types on public API definitions and eliminating types from call sites and throwaway REPL code eliminates a huge amount of wasted typing (hah!) with near no loss of clarity.


> Just get the machine to do it.

Exactly. Many people already use IDEs, or programs which provide auto-completion or hinting of the types a function accepts when writing out a function name - the type does not need to be explicitly written for the machine to identify the type of the function.


I wrote a small XML parsing library for a firewall API recently. Just writing about 15 functions handing data off to each other made me nervous about not enforcing types. The best I could do was write function signatures and descriptions.

But they can just be auto-generated in documentation. It gets pretty annoying to type annotate everything for nothing but warm fuzzies when the compiler can figure it all out for you.

Also, any decent IDE will show the types any way.

The complaint about the types is just strange and shows a failure in getting Rust out of their head. Once you get used to F# and OCaml, then going back to a language that forces type annotations everywhere gets old and seems archaic because you spend all this time telling the compiler what it already knows (in a language like F# and OCaml). However, there are times in which type annotations are needed, especially in F# when dealing with objects. I generally type annotate when I feel the name of the argument doesn't capture the type.

Writing F# often feels very Pythonic or Scheme-y, but at the end of the day, everything is being statically typechecked, so it's the best of both worlds.


Requiring type annotations on all functions would make programming with higher order functions very laborious.

I'd agree if we're talking about top-level only, though.


> If items ("fn" definitions) implemented type inference instead of requiring the programmer to manually document something the compiler can figure out, the learning curve would be easier.

No, it wouldn't. Not when the compiler is spewing error messages about types you didn't even mention, especially if the compiler inferred that type on the basis of code in some random other file you didn't know about.


The compiler can already infer all the types anyways, you don't need to declare types. It is considered good practice (and -Wall warns for it) to provide types for top level definitions, as they are usually important enough to warrant this form of machine checked documentation.

note: Yes I know the compiler can't actually infer all types all the time, but the exceptions are obvious and require type information in dynamically typed languages too (ie. convert a string to an int: you have to tell it you want an int, you can't just say "convert this string" and have it guess what you want it converted to).

next

Legal | privacy