Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Types really start pulling their own weight as the size of an application increases.

In order to catch problems in dynamic type languages you end up needing a bunch of additional tests to, ironically, verify the expected type. And even then, those tests don't and can't tell you how a method is actually used throughout the program.

Consider the following class

   class Human
     def initialize(name)
       @name = name
     end
   end
Now imagine you want to refactor this class to something like this

    class Human
      def initialize(first, middle, last)
        @fullName = "#{first} #{middle} #{last}"
        @first = first
        @middle = middle
        @last = last
      end
    end
All the sudden you've got a problem on your hands. You have to find everywhere that referenced `name` on a `Human` object (And don't mess that up, it could be `name` on the `Pet` object) and change them over to full name, or figure out if they are doing something tricky like trying to extract the first name from `name`.

Types make refactoring this sort of code somewhat trivial. You simply change the fields and let the compiler tell you ever position which relied on that field.

This extends into all sort of circumstances, like letting the user of a method know what types are expected. For example, the above ruby code doesn't really guarantee that `first` is a string. In fact, it could be an int or even an object and the code would likely handle it just fine. Types expose interface contracts in a quick and easy way for programmers to understand what they are dealing with.



The classical counterargument to this is that, if you have good test coverage then eliminating @name should lead you directly (via failing tests) to where the name field was being used. This works especially well in codebases which enforce what I tend to call "pseudo"-type systems, for example via clojure's spec and Racket's contracts. Where the shape of data is enforced structurally at runtime.

To be honest, the argument in favor of static typing that I find more compelling is the IDE argument. It definitely is a much richer experience browsing code in an IDE with the benefit of hovering over values and knowing their type, ctrl-clicking to go to where something is defined, et cetera. The equivalent of this interactive experience for dynamically-typed languages was supposed to be the REPL. But I feel like true REPL-driven development has mostly fallen by the wayside, and most environments don't have great support for it.


Yes, the type system basically replaces a degree of unit tests. You no longer need unit tests that are basically just type checking. And it's more comprehensive too. It's much easier to have incomplete test coverage without knowing it than an invalid type system. With such a type system, the app will fail to compile. Of course, you still need unit tests for many other things, but the type system does remove a class of them.

Whether typechecking or unit tests is "better" is really a question of taste.


It’s an interesting example, knowing when to make a breaking change is really tricky in codebases like these.

You could avoid it by leaving “name” and just adding the additional fields. Maybe that’s the “right” thing to do if you have a ton of consumers and spotty test coverage. But if there’s a lot of fragile code out there (parsing “name” in subtlety different ways, etc.) it’ll never be fixed/improved. Things can get gnarly over time because there’s multiple ways to do something, and everything starts to feel like “legacy code”.

I tend to think that for private codebases, it’s important for breaking changes to be easy.


> let the compiler tell you

That's really the crux of it. Types are a way to talk to the compiler and it will be your primary target. Humans will also benefit somehow, but it's secundary and they won't be the one who'll give you a tough time.

I see it:

- strict types guarantee the compiler is happy but you'll need to bend yourself to make sure it actually matches your intent

- loose types help you properly express your intent, but you're one the hook to make sure the interpretor does what you said.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: