Hacker News new | ask | show | jobs
by mijamo 947 days ago
I think it vastly depends what you're writing. Any kind of function that does not have a fixed input and output gets a lot more complex with static types. And by extension any code that depends on that also gets more complex.

I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up. It is a bit extreme but when you work with an API from an ERP for instance you can get very very complex and extensive types that are not in your control and not very well specified.

Another good example is how complex all ORM internal code get once they try to add static typing. The typing in the ORMs code feels like black magic because they would really really need types as code but don't have it so have to rely on a bunch of crazy generic combinators.

4 comments

> Any kind of function that does not have a fixed input and output gets a lot more complex with static types.

If you don't know what kind of data people give your function and you don't know what's supposed to happen, how can you write that function? I think many people use too strict of a type system. If your function works with any object that has a toString()->string function, then just write an in-line interface that defines it.

I actually love TypeScript here. It allows for `any` if you're prototyping, lazy or simply don't care. It allows mapped types, where the next dev can see how a type came into being - for example, Mutable<T>, Readonly<T>, Required<T>, Partial<T>. The names actually speak for themselves! And it eliminates the Java-style verbosity of creating classes and files all just for a type.

I prefer dynamic types when I prototype and hack on code.

I'd prefer if dynamic languages would converge to gradual typing support, and static languages to gradual dynamic support. TypeScript is an example of the later, and PHP of the former.

You perhaps know, but I believe one should prefer the "unknown" type in TypeScript in such scenarios. Of course, then you need to check what its type actually is to make use of it, but this time TS checks that you do.

Btw, the equivalent in Python (and MyPy/pyright) is object.

> I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up.

You can always deserialize things as `serde_json::Value` instead of making types for everything to get similar behavior out of Rust.

The perceived difficulty of static typing depends on the type system itself. For example, there was a version of Swift where it became extremely painful to work with String and Substring, or Array and ArraySlice, which you’d intuitively just pass around whenever you’re making smaller pieces of collections but which the compiler complained about during type-checking when you are substituting one type for another. They solved the problem by just defining a protocol such as StringProtocol (and just reusing Sequence for arrays I think) and using that protocol wherever parameters are passed around, so it became possible again to swap those types for each other.

So then there’s more code for the language devs to write of course, but that’s just the cost of safety, which is highly desirable if you want the technology that you are building to be attractive for use in systems where correctness is critical, which also tend to be highly valuable. As a working professional it’s in my best economic interests to have such valuable tools in my skillset.

Elixir dev here, just to put the context in place first hehe.

Couldn’t that thing be typed as the web format? A nested set of string props with either string or number types in the leaves.

Then use those types to traverse and pull into «real» types?

I like to put structured data into structs in elixir too and the above is essentially what I would do in Elixir.

I don’t know rust well enough to see if I am missing some nuance

You can do that in every language, even in Java 1.0, by just using a hash maps of objects, and cast those objects to whatever you like at runtime before accessing them.

But then, you are basically throwing out your static type checks and just using it as a dynamic language, but with much more verbosity, cruft and additional ways to should yourself in the foot.

Yep. It’s awkward. The language fights you every step of the way and it becomes hard to read and write your code. x.foo = 6 becomes x.set(String(“foo”), Num(6));. When you read that value back you’ll need to unwrap the type you expect before you can do anything with it. It would be utterly miserable. You’d be much better off just using Python, JavaScript or Ruby.

You also lose all of the performance benefits typing brings, and gain nothing in return. In JavaScript land, V8 moves heaven and earth to guess what your types are and optimistically compile your code behind the scenes assuming its type annotations are correct. Then it dynamically deoptimises and reoptimises at runtime with that new information, while your program runs. As well as being ugly, the equivalent “dynamically typed” rust program would have none of V8’s smarts. It would run dog slow compared to normal rust and still way slower than the (much cleaner) JavaScript equivalent.

Like wood, programming languages all have a grain. If you program in harmony with the language’s design, everything will seem easy. Compiler errors make sense. The standard library will seem useful and well designed. Program against the language’s design and you’ll hate every minute of it.