Hacker News new | ask | show | jobs
by Vaguely2178 1125 days ago
Or in other words, the presence of a static typing ecosystem is one of the advantages Node has over Elixir. So while the original commenter might not care that Elixir lacks static typing, they should care because it increases productivity.
2 comments

The only reason I would want types is for specific error types that I could ideally match against instead of them being raised (in Node.js or Typescript).

In Elixir you have the option of calling functions that raise vs functions that return an error tuple so there's no contention there (the difference between function() (this does error tuple) and function!() (this raises).

Elixir also has this idea of a typespec and I have never felt I needed more, personally.

Typespecs in Elixir (combined with Dialyzer) give you a very limited version of what TypeScript offers. From what I understand Dialyzer is designed to only raise an error when it's absolutely certain that you're mistaken about the types in your program. While this does prevent Dialyzer from complaining about false positives, it only catches the most trivial of bugs [1].

Also even with Elixir's typespecs, static typing is only fully useful if the entire ecosystem around a language embraces it. If some of the libraries you use don't ship with type definitions, it's going to be difficult for any static analysis tool to do a decent job. Almost every major JS library either ships with its own types, or has quality third party types available via Definitely Typed. It doesn't seem like the Elixir community has really embraced static typing to the same extent that TypeScript developers have. The creator of Phoenix for example hates dialyzer [2].

[1] https://elixir-lang.org/blog/2022/10/05/my-future-with-elixi....

[2] https://elixirforum.com/t/do-you-use-dialyzer-in-your-projec...

> While this does prevent Dialyzer from complaining about false positives, it only catches the most trivial of bugs

Is this coming from experience? Because it surely doesn’t match mine

I was referring to Elixir's blog post on static types where the creator of Elixir José Valim wrote: "The Dialyzer project, implemented in Erlang and available for Elixir projects, chose to have no false positives. However, that implies certain bugs may not be caught. At this point in time, it seems the overall community would prefer a system that flags more potential bugs, even if it means more false positives." [1]

From my experience with TypeScript, you really want your type checker to be eager about complaining about type issues, which is why so many people turn on strict mode. In fact, occasionally I'll have to suppress a false positive error with a @ts-expect-error comment.

But even assuming Dialyzer is as good as TypeScript, have you found that the libraries you use actually have quality type definitions? The few times I've used a JS library without type definitions it ended up breaking type inference, and infecting the codebase with the any type, which renders the type checker basically useless. How has your experience been in regards to that with Elixir?

[1] https://elixir-lang.org/blog/2022/10/05/my-future-with-elixi....

> have you found that the libraries you use actually have quality type definitions?

I have some experience with Typescript and it was way better than vanilla JavaScript. Typescript mappings we’re available for most libraries, though for a couple they were not up to date. Similarly for Elixir, the coverage for nearly all APIs is pretty good but also has some holes. In my experience it hasn’t been a big deal either. Any serious library developer puts types alongside their function signatures/implementation.

> The few times I've used a JS library without type definitions it ended up breaking type inference, and infecting the codebase with the any type, which renders the type checker basically useless. How has your experience been in regards to that with Elixir?

Being a functional language, Dialyzer can easily make inferences on untyped code based on ‘success typing’ (what Jose talks about), though it can make for some very obtuse and verbose warning messages. This inference is in addition to safety provided by typespecs which every Elixir library developer typically intermingles with their API surface.

If I would level criticisms at dialyzer it would be its sometimes difficult to read warnings, it’s speed (despite being multithreaded) and the race conditions in the VS Code plugin (which is looking for extra maintainers – if I had time I would help). For the weird warnings I find I just need to add extra typing to my code to narrow it down, which I should be doing anyway

> If I would level criticisms at dialyzer it would be its sometimes difficult to read warnings, it’s speed (despite being multithreaded) and the race conditions in the VS Code plugin (which is looking for extra maintainers – if I had time I would help).

One of the advantages of TypeScript is that VSCode is written in TypeScript, and both VSCode and TypeScript are developed by the same company, so there's a really nice synergy there. I imagine Kotlin users feel the same way using Jetbrains products, and Swift users feel the same way about XCode.

Dialyzer looks interesting, but I can't imagine giving up on the expressiveness of TypeScript. Some of the things you can do with generics, mapped types, intersection types, template literal types, conditional types, and utility types are almost mind boggling. It's difficult to reap all of the benefits of static analysis without some of these advanced type operators. The type manipulation section of the TS manual is really underrated.

Someone for example wrote an SQL parser in TypeScript that requires no runtime code [1]. It can infer the types of an SQL query's result based on an SQL string without any runtime code execution. There was a similar project where someone built a JSON parser entirely using the type system [2]. There's also an ongoing discussion on Github about the the fact that TypeScript's type system appears to be a Turing-complete language with some other cool examples [3]. My point is that the type system is incredibly expressive. You rarely run into an idiom that can't be typed effectively.

[1] https://github.com/codemix/ts-sql

[2] https://twitter.com/buildsghost/status/1301976526603206657

[3] https://github.com/microsoft/TypeScript/issues/14833

> But even assuming Dialyzer is as good as TypeScript, have you found that the libraries you use actually have quality type definitions?

Strictly speaking, Dialyzer has two big benefits over more traditional type systems:

1. It doesn't require type definitions to be present, it can type check code having none at all.

2. "Dialyzer is never wrong", i.e. it never returns false positives, i.e. it's an underapproximating checker.

These are the design decisions taken by the tool authors. There's rationale behind them, though the experience of using checkers for other languages might not be 1-to-1 applicable because of that. These decisions come with downsides, of course, some of which are covered in this thread, so I won't repeat them, but in general they were taken deliberately due to characteristics of the language(s) (it was originally created for Erlang, not Elixir) and the state of type system theory at the time. Please bear in mind Dialyzer was created in 2006, some 6-7 years before TypeScript.

If you're into trying out static typing in Elixir, please check out https://github.com/esl/gradient. It's still experimental, but already functional. We're happy to get any feedback or, better yet, contributions.