Hacker News new | ask | show | jobs
by watermoose 3553 days ago
> At the same time I cannot use toy languages that have no compile time type checking

This guy seems like and sounds like a serious developer, so I'm totally confused by this statement.

Dynamic languages that don't do compile time type checking are not toys.

I used to only write in Java or C++, but I think it's a stage of maturity as a developer to realize that you can develop code that can take arguments with the assumption that the objects sent in are of types that will have the behavior you need to work with them.

If you argue that the code is faster when it is compiled- that's fine, and I agree, and that's good, if it matters.

If you argue that you need types because otherwise you can't be safe, I'm sorry, but that's like being a helicopter-parent. Sometimes maybe you can't trust what is calling your code even when you give it trust, and that's valid; just like as a parent, sometimes the child really needs that level of micromanagement. But, for a lot of if not most of practical web development, you can use dynamic typing, and most children do not need that level of micromanagement.

There's nothing wrong with languages that provide type checking, but it isn't necessarily a deficiency when it's not there.

3 comments

> But, for a lot of if not most of practical web development, you can use dynamic typing, and most children do not need that level of micromanagement.

I use TypeScript because that level of "micromanagement" saves me more time in avoiding bugs than I spend adding static annotation. Hell, the improved intellisense alone means I no longer need to read docs in a lot of cases, meaning writing code is faster for me too - even ignoring bug rates. (Of course, it's sometimes prudent to check the docs for things like edge cases regardless.)

In C++-land, I've started using e.g. clang's threading annotations to good effect in catching some of the most heinous bugs to debug - incorrect multithreaded code that forgets to do simple things like lock mutexes meant to protect data structures.

I've dabbled in a toy project in Rust-land. The ability to catch and prevent data races is fascinating, and the ability to stem the tide of null dereferences at runtime seems pretty handy. Have you never had a hell-to-reproduce null deref that only occurs in your release builds? It's pretty bad when it ships to a large number of customers.

I see SQL injection vulnerabilities, and wish APIs properly segregated SQL Data from SQL Commands - two entirely different types of things entirely.

And yet for awhile I was a lot more forgiving of dynamically typed languages. Until I was able to compare JavaScript vs TypeScript - which I'd argue started as basically JavaScript with static typing tacked on as, effectively, an afterthought.

> If you argue that you need types because otherwise you can't be safe, I'm sorry, but that's like being a helicopter-parent.

If helicopter parents were as beneficial as static typing, I'd have a lot less against them.

> If you argue that you need types because otherwise you can't be safe, I'm sorry, but that's like being a helicopter-parent. Sometimes maybe you can't trust what is calling your code even when you give it trust, and that's valid; just like as a parent, sometimes the child really needs that level of micromanagement. But, for a lot of if not most of practical web development, you can use dynamic typing, and most children do not need that level of micromanagement.

This is backwards. Working without types is like walking around with your eyes closed: sure, you can do it, most of the time; if you're not doing anything particularly dangerous you can even do it reasonably safely. But it makes everything a lot slower.

The arguments against types usually boil down to either, as the saying goes "The belief that you can't explain to a computer why your code works, but you can keep track of it all in your head", or having only used languages where the explanation to the computer is so cumbersome as to not be worth doing (valid, but only in the scope of those languages, and the correct response is almost always to get a better language).

Try using a language with a decent type system some time (something along the lines of OCaml, Haskell, F# or Scala). Back when I'd only written Java and C++ I also thought type checking wasn't worth it.

I'm a huge fan of static type systems and their ever helpful checkers.

For me the most difficult argument against static types is that the sweet spot remains elusive: some type systems are too simplistic (e.g. the difficulty of writing generic print in OCaml) while some are too fancy and difficult (e.g. how many people understand even most of GHC Haskell's type system?).

There's also some real problems with compiler error messages. A great type checker needs to be able to explain problems understandably, or decoding the type errors will be more difficult than tracking down a null pointer in an interactive debugger.

I wonder about the possibility of making type checkers more interactive. It can be hard to understand them because they build up lots of implicit understanding that's not apparent.

I apologize for the swipe at "toy languages". I tried using more common languages like the usual scripting crowd, but it wasn't successful, mostly for performance reasons. Python in particular is frustrating since the very own spec prevents pretty much all optimizations and you can't even call a function without stirring the heap.

I don't advocate a full type-safe language. In Common Lisp I generally don't have to declare any types. The compiler points out obvious, unavoidable type problems that it can deduct, e.g. inside a function that has some typed things such as literals. I can then add types as I like, to both variables and function interfaces, and the compiler points out more.

Another property of Common Lisp is that if you add type declarations they speed up your code if you compile with speed==high and safety==low. But you can also compile your code with safety set higher than speed. In that case a compiler like SBCL turns your declarations into runtime type assertions.

Then you run your automated tests in both modes and you have higher confidence in the code.