Hacker News new | ask | show | jobs
by marta_morena_28 2049 days ago
> Two decades ago, it was widely argued that dynamic programming languages were more productive because you didn't have to spend time dealing with type signatures. The only reason, then, to use a statically typed language, was for better performance.

This boggles the mind. I am using typed languages since I can think. I never once recall an instant where I was saying "Uh uh, this type signature is driving me craaazy". Like seriously, I don't even know what articles like this are talking about. Types are not your enemy, they surface issues early. Yeah you can whip something up in Python and JS, but ultimately you DO have to deal with types, except now you don't have a compiler doing this job anymore, you have to do it yourself... Somehow.

The only thing typed languages need is something like `dynamic` from C#, which automatically boilerplates untyped access with reflection, without cluttering your code. I.e. duck typing is one of the things some languages like Java need to get better at. But the situations in which I yearn for this are far and few between.

You don't think about types, unless you are new to typed languages... It's really that simple. I never have to think about types. Perhaps its subconcious, but its definitely not slowing me down, its making things faster through robust refactoring, auto-complete and welll doh: TYPE SAFETY!

12 comments

Languages like Java (which was THE statically typed language around that time) were extremely verbose and inexpressive. It's hard to write anything in Java without metric tons of boilerplate and repeating the type of every value over and over and over again.

On top of it, with OOP languages it's very easy to box the code in deep layers of ridiculous inheritance taxonomies, making it pretty much impossible to refactor anything after business requirements changed. Barely any escape hatches and absolutely no flexibility.

And type-safety is kind of pointless when everything is of a given type "OR NULL".

I was always proponent of typing but after working with Java, I can totally see why so many people back in the day considered static typing as not worth it.

Statically typed languages without Sum Types (aka tagged unions aka enums) which includes Java, C# and C++ amongst others drive me crazy: they have no ergonomic way to express "or" types. This is a massive expressive hole which (along with lacking type inference) I believe is responsible for a lot of the hate towards statically typed languages.
This is one of the joys of TypeScript.

Some of my coworkers complain about being required to use TS instead of JS, and I just wonder why in the world you would want to use JS in a massive codebase.

It is, although the syntax for proper sum types (it calls them "discriminated unions") is really verbose in Typescript. I wish they'd make it more terse so people didn't use untagged sum types and hacks like `typeof` all the time.
Sealed classes in Kotlin largely solve that problem for me, and Java is getting those. It's not quite the same, but most of the time I find that if I'm trying to do Int|String, it's primitive obsession and there is actually a better sealed type hierarchy I'm missing.
If you care about the exact underlying memory layout such high-level types are way too blackbox-y. I doubt that historically this specific feature was responsible for any "static typing hate" (because languages with such high-level type systems were quite obscure 10 or 20 years ago). I have the impression that this hate was specifically a web-dev thing because many Javascript developers never experienced what it's like to work with a statically typed language until Dart and Typescript showed up (and then it suddenly was the best thing since sliced bread).
> Statically typed languages without Sum Types (aka tagged unions aka enums) which includes Java, C# and C++ amongst others drive me crazy: they have no ergonomic way to express "or" types. This is a massive expressive hole which (along with lacking type inference) I believe is responsible for a lot of the hate towards statically typed languages.

Union types coming in Scala 3

Yes, totally agree. It's the lack of statical type systems like this one that makes people hate them - for good reasons.
These languages have far better type systems than languages like python or javascript, that's not a reason to hate them.
We are talking about user experience here. In that regard, comparing python/javascript with Java/C++ is comparing apples with oranges.
We are talking about Python and JavaScript from the top of this comment chain, and the 'user experience' of writing Java/C# is closer to Python and JavaScript than to, say, Haskell.
Yes, but I find that the user experience of writing Rust or Swift is closer to that of JS than C# and Java.
Modern versions of these languages have these features to a varying degree.
std::variant or std::any don't count? Overloading doesn't count? Templates don't count?

Seems like you should play with C++ a bit more.

Not a C++ developer, but from what I read, it says: "A variant is not permitted to hold references, arrays, or the type void". These are quite some limitations and don't really give a "smooth" experience.
None of those types make sense in variants. This is obvious to C++ programmers.

With all due respect, if you're not qualified to make assertions about something, perhaps refrain from labeling it as "quite the limitation".

Can you explain why it makes no sense for it to hold an array or void? I'm really curious and will take back my claim.
You cannot trivially compare or move an array. Note that `std::array` is still allowed in `std::variant` - just not C-style arrays.

As for references, you cannot re-bind references. Rationale here: https://stackoverflow.com/a/27037871/510036

As for void, apparently the reasons I had in my head are not the reasons in real life. I thought it might be because of a destructible requirement on the type, but it turns out there really isn't a good reason why they disallowed it, and that a future standard might allow it.

In any event, there are a multitude of variant implementations that allow all sorts of things depending on the behavior you want. Nothing is forcing you to use the standard library.

std::variant is basically a parody of everything wrong with modern C++.
Please elaborate because I strongly disagree with you.
>This boggles the mind. I am using typed languages since I can think. I never once recall an instant where I was saying "Uh uh, this type signature is driving me craaazy".

You might not, but this was a common sentiment (not saying it is necessarily a valid one, mind you, but it was common). Were you programming 2 decades ago and/or paying attention to the average sentimeντ expressed in blogs/etc re types and dynamic languages (and the general tone up to around 2012 or so even in HN)?

Another common sentiment was that "who needs types when you have TDD".

The people who have problems with types and think removing them makes programming easier are the same people who have problems with syntax and think that replacing text with some kind of graphical representation makes programming "easy for non-programmers".
Without types, TDD can become TTD.
> I never once recall an instant where I was saying "Uh uh, this type signature is driving me craaazy".

Is that sentiment based on modern languages, though?

While modern in its place in history, but adhering to older principles, I frequently hear exactly that from people evaluating Go. Languages with more complex type systems bring tools to help alleviate those concerns. Not all of those concepts were widely available looking back two decades ago. Java, for example, which was probably the most popular typed language of that time did not provide even generics until 2004. Being able to write a function once and use it for many (dynamic) types was no doubt seen as a big improvement for many use cases.

Type systems are back in fashion now largely because they are much more usable now, especially outside of the academic languages.

> This boggles the mind. I am using typed languages since I can think. I never once recall an instant where I was saying "Uh uh, this type signature is driving me craaazy". Like seriously, I don't even know what articles like this are talking about.

This was OVERWHELMINGLY the sentiment on hacker news a decade ago. Strongly statically typed languages were NOT WELCOME on this website.

A lot of that can probably be attributed to major advances in type system ergonomics. A verbose, clunky type system with poor inference can easily be worse than none at all. Ten years ago, there just weren't that many popular, practical languages with really good type systems. Now there are quite a few.
I share the same sentiment, the only dynamic language I put up with is JavaScript, and PHP when dealing with my own site.

Tcl, Smalltalk, Lisp, Prolog, while great to program in the small, have taught me that I really want types when working in a team.

Python, Ruby and Perl, I really don't see the use beyond learning to program or grown up shell scripts, given their lack of attention to performance.

The vast majority of code ever written is not performance-sensitive, but is very sensitive to getting produced rapidly.

If you need to quickly perform some statistical analysis, you'd be hard pressed to be more productive in anything else over Python+NumPy or R.

Statistical analysis is a domain I am more than happy not to care about, it was already enough what I had to bare with during my engineering degree.

Still, given that Python and R are just glue languages for C, C++ and Fortran libraries, I rather use the source directly, or bindings to typed languages.

Modern C++, .NET, Java or ML based languages are just as effective,.

And here is a fun fact, I have spent 4 years working for life sciences companies, where several researchers I got to know, would do statistical analysis in Excel + VBA, eventually using VB.NET as well for more complicated stuff.

Where dynamic typing helps a lot is for creating frameworks, like Django, RoR, etc.

Because the framework is working on a level above the application, it can easily deal with objects without worrying about what is inside them.

However, people got caught up in this no-type nonsense and took it to all corners of every app development.

When you are creating, say web apps, you may not create types in dynamic languages like python, but you sure as hell will use known variables in those types.

There are a few edge cases, where dynamic types allow you to build logic on user-defined sets of data, but those cases are few and far between. Even those can be solved using generic data containers or custom data protocols such as XML.

> Because the framework is working on a level above the application, it can easily deal with objects without worrying about what is inside them.

Even for that there is no need for dynamic typing anymore. This problem has been solves with type parameters (aka generics) and type-classes.

Not true.

In Python and Ruby it's an extremely common pattern to return a dictionary with a half-dozen entries at most that will be consumed at a single location.

Defining an entire class for this sort of extremely common use case is for the most part a waste of time.

These languages allow for the formalization of those types by creating classes out of them, but looking at what 50% of my functions do in web dev code, they're returning tuples, small dictionaries, or standard library objects.

What makes you think that statically typed languages don't have (type-safe) tuples or dictionaries?

Maybe you can give a minimal code example of what you mean and I'll show you how I would solve that in a statically typed way. :)

Which mainstream language supports anonymous structural types? C# is the only one that comes to mind and it's not a standard pattern AFAIK.
Wait a moment! Since when are we talking about only mainstream languages? And how is that even defined?

That's not fair play

> Types are not your enemy, they surface issues early.

Not only that, but they document the code.

When working with a new framework or library in Python or JavaScript I never know what I can do, I have to look at the documentation constantly.

Not seldom I'm still left scratching my head or doing stuff like "print(dir(result))" to figure out what I can do with whatever that function returned.

With a static typed language I can see what type the function expects and what it returns. If I don't know a type I can discover what it can do in a few clicks in my IDE.

> The only reason, then, to use a statically typed language, was for better performance.

Uhh, someone please correct me if I'm wrong, but aren't statically typed languages about reliability (e.g. testing, mutability)?

EDIT: in addition to performance, not solely.

Statically typed languages only eliminate SOME things you'd otherwise have to test. In the end, you can eliminate almost anything besides logical errors, however, those are unfortunately a pretty big portion of bugs :D.

So while I would always use statically typed languages for anything that needs to be reliable, I do not see how this is in any way a necessity. You CAN write reliable programs without type safety, you just have to test things you normally wouldn't have to test (i.e. the lack of type safety introduces a whole bunch of null-pointer style scenarios where you get something your code totally didn't expect but has to deal with).

As for performance. Statically typed languages are usually faster, mostly because we do not have the technology yet to make dynamically typed ones as fast (in the general case). Not because there is something inherently different about them.

However, I imagine the technology to make them on par with statically typed languages will take another few decades. Mainly because untyped languages need sophisticated transformations to be fast. That is the job the human normally does for the compiler in typed languages. Things just fit together and play nicely. With dynamic languages, your get one big spaghetti soup with no structure and now the compiler has to figure out the "intended" types and compile for different estimated function signatures, etc. all while honoring the JIT-style performance considerations (fast startup, low overhead during runtime). This is a gargantuan task that probably will require advanced machine learning before it really takes off.

> I do not see how this is in any way a necessity.

Right, but that's not my point. My point is that using a static type language isn't JUST about performance. If I define foo as a string and call it as an integer in my program, my compiler is going to catch it, whereas in a dynamically type language I may not discover the bug until it hits production.

Statically typed languages typically have better performance.

In C, i++ is one or two machine instuctions. In javascript, we don’t know if i is an int, or something that overrode ++ to download wikipedia. So, it ends up being a function call in naive JavaScript. Fast forward a decade, and dozens of PhD theses mean that ++ is usually a machine instruction in JavaScript, but it is not guaranteed.

Two decades ago, dynamic languages were more typically scripted / interpreted, and statically typed languages were more typically compiled. Scripting does allow for quicker iteration (especially if compared to a language with a slow compiler) and compilation usually does produce faster code (at least pre-dating sophisticated JIT compilers).
A dynamic language is not just a statically-typed language where all type labels are removed -- it is the wrong mindset -- don't try to write Java programs using Python syntax.

On type safety: Python is a strongly typed language unlike e.g. C:

  >>> "%d+%d=%d" % (2, '2', 4)
  Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
  TypeError: %d format: a number is required, not str
vs:

  #include <stdio.h>
  
  int main(void)
  {
    return printf("%d+%d=%d\n", 2, "2", 4) < 0; 
  }
Funny, that's one of the things that drives me nuts about Python. It knows each types, it knows function to convert to each type, but... it doesn't do the conversions! So frustrating! Why do I have to care about types in these dynamically typed languages??

Also, is sprintf-style string formatting the best example here? I think that feature is type strict in a lot of languages, after all you are declaring the types you want in the formatting string. I imagine most implementations of % in dynamic languages pass to sprintf internally?

>It knows each types, it knows function to convert to each type, but... it doesn't do the conversions! So frustrating!

It surprises me that you are incapable of thinking one step ahead. Implicit type conversions undermine the type system and make your language completely unpredictable. Pretty much everyone regrets this feature in C++ and it is still a huge source of bugs because you have to opt out of it.

You want things to fail with a loud bang instead of continuing and destroying things along the way.

> It surprises me that you are incapable of thinking one step ahead.

Seriously, what is this? You don't know me. Lay the fuck off.

My thoughts on the matter are either that a language should be strongly typed, with type declarations and enforcement at the compiler level, or dynamically typed in such a way that I shouldn't have to worry about types except for specific circumstances. Dynamically typed languages should know their coercion capabilities and perform them losslessly when needed. In reality what ends up happening is that some type coercions are automatic and some aren't, and if you're a polyglot then this is yet another one of those stupid arbitrary details you have to memorize for each language you work with. (I really would like less of those, there are too many different languages for doing the same thing)

One of the benefits of dynamic languages is that they handle type stuff for you. Which I interpret as, "cool, I don't have to worry about types!"

Yeah I know python is all about being obnoxiously explicit, and that is one of the things that I really do not like about that language. Now that I think about it maybe Python should have been strongly typed, its "no implicit behavior" opinion works much better under such a regime

Some of those things in Python reflect its history as a better language between Bash and C, and the gotchas of those languages became verboten in Python.

Elsewhere in eg NumPy conversions between number types are automatic as long as they don’t lose information.

Python is biased towards "explicit is better than implicit". It would rather fail with a TypeError than silently coerce types and risk masking logic/type errors.

> Why do I have to care about types in these dynamically typed languages?

Because Python is strongly typed, and types determined behaviour.

> I never once recall an instant where I was saying "Uh uh, this type signature is driving me craaazy"

For example, this is ugly in Python:

def handler(on_error: Callable[[int, Exception], None]):

Alternatively a Protocol can be used instead of Callable

  from typing import Protocol

  class ErrorHandler(Protocol):
      def __call__(self, p0: int, p1: Exception) -> None: ...

  def handler(on_error: ErrorHandler): ...
It doesn't matter if you have the types ascribed explicitly or not. In the end, the developer needs to know the types in both cases anyways. Otherwise, if they don't know the types, they will pass in a callable that expects the wrong types (for example they mix up [int, Exception] to [Exception, int]) and now you just have a runtime error.

If anything, having type signatures like that are a good thing! If you think they are too complicated/ugly or driving you crazy, then you have an incentive to improve them. In many languages, callbacks are now considered bad style and that's good! Hiding the type signature does not make the problem go away, you just move it into the future where it will bite you even more.

What's the alternative?

No type signature? Or documentation in another file somewhere else guaranteed to be out of sync, difficult to find and not enforced by the compiler? No thanks to either of them.

> This boggles the mind. I am using typed languages since I can think.

And therein lies the problem. It's a tradeoff: prototyping speed/readability vs longterm reliability. Modern languages have greatly improved the tradeoff, but it still exists, whether purists believe it or not.

I personally find the highest productivity in adding the majority of tests and typing later, after a design solidifies, not before.