Live data from Hacker News

Tests aren’t enough: Case study after adding type hints to urllib3

sethmlarson.dev

181–190 of 205 posts

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#181
post #151

Earlier quoted context omitted.

> Sufficiently advanced static typing is indistinguishable from dynamic typing. Static typing type checks are compile time, dynamic typing doesn't. I don't see how these two could be indistinguishable, in one you can't run the program with type errors, in the other you can.

This is true if you're focused on the compiler but if you include the adjacent question of what is reported to you in your editor while working it's a bit blurrier. If I write some Rust code and pass a string into something which expects an integer, I get a hard error preventing compilation. If I do the same thing in Python, however, and there's a prominent error displayed in my editor before I even run the code, how…

Both your examples are the same static typing. One just has better IDE integration than the other.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#182

Earlier quoted context omitted.

> I hate having to waste time figuring out the type of every variable and hold it in my head every single time I read a piece of code. If a codebase doesn't have static types, it damn well better be set up to be highly grep-able. Including dependencies and frameworks. This is why Rails pisses me off so much. No static types to help you out, and you can't grep (can barely google, even!) methods and properties that are…

> ... grepable ... This is so important. It is also the reason why I like global variables. They are accused of making a spaghetti mess but ... in my experience the opposite is true. Fancy patterns are way worse to reverse engineer than simple flat long functions accessing globals. Easy to debug too!

I agree with that. I despise all the DI things where I can't "goto" to the definition of the actual dependency that was injected, but only to the interface. So frustrating. It makes understanding what is going on so difficult for me.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#184
post #166

Earlier quoted context omitted.

He just did derive it from the halting problem. In words: It's impossible to statically check the type of a function that takes a program P as its input, and returns the integer 1 as its output if P halts, and returns the string "1" if it does not halt. It would require solving the halting problem, which is undecidable.

How does that follow? The input type would be vague, e.g. ByteArray or Program or something.

It's the return type that isn't decidable. You can't statically check, in the arbitrary case, whether the function returns an int or a string.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#185
post #184

Earlier quoted context omitted.

How does that follow? The input type would be vague, e.g. ByteArray or Program or something.

It's the return type that isn't decidable. You can't statically check, in the arbitrary case, whether the function returns an int or a string.

No, but that isn't required for a static type system. Most languages would just unify to the top type.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#186
post #166

Earlier quoted context omitted.

You are probably thinking of Gödel's incompleteness theorems. I do not think that you can trivially derive it from the halting problem.

He just did derive it from the halting problem. In words: It's impossible to statically check the type of a function that takes a program P as its input, and returns the integer 1 as its output if P halts, and returns the string "1" if it does not halt. It would require solving the halting problem, which is undecidable.

The theorems predate Turing's theorem. As for the halting problem, it is solvable with an oracle, unlike the incompleteness theorems.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#187

Earlier quoted context omitted.

Sounds like a brilliant case for multiple-dispatch.

Right so we have: function find_user(person: string) and also: function find_user(person: Object) how long before someone writes this: find_user(person: { name: "dave" }) meanwhile, someone else, not suspecting that they'll be handed a weird half-formed `User` object adds `person.id` somewhere in the body of the Object version of `find_user` and now we have a weird edge-case where very rarely `find_user` panics becau…

Somebody downvoted you, I'm guessing because they think this is a silly example and have never actually seen something like this. I have, in a production code base.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#188

I love static typing/type hints if for only 1 thing - code maintenance. Even code I wrote six months ago. Not having to dig through 6 functions deep to try to figure out whether "person" is a string, or an object, and if it's an object what attributes it has on it etc. is huge. And not to mention that some clever people decide - hey, if you pass a string I'll look up the person object - so you can pass an object or a…

> some clever people decide - hey, if you pass a string I'll look up the person object - so you can pass an object or a string - which makes all sorts of convoluted code paths Do you have hints on how to avoid being one of those 10x clever programmers while programming a prototype? I find that I am most likely to write functions like that when there's some variables that I don't want to pass 5 layers down the call st…

I don't really, but I guess I could say that I have developed in statically typed languages and dynamically typed languages (professionally) for over a decade and I've always found that using the "power" of dynamic languages always ends up causing (me) more frustration in the long run- basically classes of bugs or time wasted that simply doesn't occur with statically typed languages. So for me, I tend to spend a little more time up front to try not to waste (my) time in the future.

> I find that I am most likely to write functions like that when there's some variables that I don't want to pass 5 layers down the call stack

I agree for a prototype, there are some tradeoffs to be made. However, very often prototypes can end up becoming production. Temporary decisions often become permanent ones. Just something to keep in mind.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#189
post #157

Earlier quoted context omitted.

Vararg functions also have limited use. Especially considering that most of the time, your args will all have the same type, and therefore could just be passed in an array or similar. The one mainstream exception I know of is print functions, and we have* ways to statically check those. Your toy example, even generalised, has no practical use. If I can write this: compose(f, f1, f2, f3) Then I can write that instead…

This still technically reduces the generality of the given function since you are specifying that each function cannot have multiple overloads. let f be a overload set matching the signatures {a -> b, i -> j} let g be a overload set matching the signatures {b -> c, j -> k} compose(g, f) could be given a to return c or i to return k

> This still technically reduces the generality of the given function

My point was that we are almost never hurt by that reduction.

> you are specifying that each function cannot have multiple overloads

Haskell has type classes, and if we restrict ourselves to local type inference it's fairly easy to have C++ style overloads without even that. So no, I'm not specifying such a thing.

Re: Tests aren’t enough: Case study after adding type hints to urllib3

#190

Earlier quoted context omitted.

Vararg functions also have limited use. Especially considering that most of the time, your args will all have the same type, and therefore could just be passed in an array or similar. The one mainstream exception I know of is print functions, and we have* ways to statically check those. Your toy example, even generalised, has no practical use. If I can write this: compose(f, f1, f2, f3) Then I can write that instead…

> Vararg functions also have limited use. This is only because people are using statically typed language that place arbitrary restrictions on such functions and make them harder to use. In dynamically typed languages, vararg functions are widely used and enable patterns that are pretty nice.

Perhaps. But then I want to know what those patterns are, what are their actual benefits compared to not using them, and most of all I want to know if such benefits outweigh the significant costs that comes with the lack of static analysis¹.

[1] The need to test much more, the need for a better, more accurate documentation, the higher cost of refactoring, even the higher prototyping times (I prototype faster with a REPL that has static typing, because I don't to debug type errors).

Post reply on HN