Why specify argument types and return types

Sorry I have to comment here, or maybe it would be better to comment in the pull request.

I feel like there is a fury with which most(?) people push others to not declare parameter/return types. It is to the point that it feel like the language designers would prefer if you couldn’t declare types at all, but since they couldn’t swing that any unnecessary type declaration are vehemently attacked.

I do see your point of view for the data processing space. Many math/array operations don’t really care if the types are Ints, Floats, or BigInts, and code reuse is always good. However there is a minority(?) of us that are using Julia as a general programming language.

When I write a method to handle an HTTP.Request and return an HTTP.Response there is no need for generalization unless someone creates a new HTTP package and mirrors the HTTP.jl package’s API, which I find significantly less likely than defining a function for Ints that could also be used for Floats.

Defining the parameter types allows me to catch errors with clear errors. When the calling method is compiled I get an error that “SomethingElse” cannot be passed to a method. I don’t get the obscurer error that “SomethingElse” doesn’t have a “query” property. Or possibly 5 levels above that method that the HTTP.decode method doesn’t take “SomethingElse”, and I have to go down through the call stack trying to figure out when “SomethingElse” started getting passed up.

Defining the return types also allows me to catch errors early, and more importantly at the point of the error. In the HTTP processing case not returning an HTTP.Response means a bug. When the compiler tries to compile that method it tells me that “SomethingElse” could not be converted to an HTTP.Respons. I do not get some obscure error 5 levels down the call stack where it can’t pass “SomethingElse” back to HTTP.jl. Or that “SomethingElse” doesn’t have a “body” property. Then I need to go up through the stack (a much bigger search space than going down) to figure out what function returned the “SomethingElse” that is causing all the issues.

This means that even when the types CAN be generic I still define the return type based off the input types. i.e. foo(a::T)::T where T.

In your documentation update you mention “…you should instead write ‘type-stable’ functions…” which is all well and good, but it’s nice to have the compiler double checking your work in case you forget to run @code_warntype on your changes to ensure the function is still type stable in it’s return.

A final note, TypeScript was created for a reason. It added types to an inherently un-typed language. I’m curious how the “don’t declare types” people feel about TypeScript? Do they feel that it was a waste of time, adding an unnecessary level of type validation to a beautifully un-typed language? Personally I have lived the hell that can be JavaScript and I fricken love TypeScript, it gives me much more confidence that my code will actually run when I try to run it.

Sorry for the long response, just my two cents on type declarations. They are not needed for performance, agreed, but they can provide a level of confidence about the function and the program actually having a shot at working.

6 Likes