News for hackers. Stuff that matters.
Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @12:01PM (#23284001)
I've used Elixir since 2015 and I find Elixir to be unusable for any kind of intelligent domain modelling, but that's primarily because it's dynamically typed and has no concept of real sum types, etc., not necessarily because it's any worse at this than Ruby.

Any codebase beyond fairly small will be harder and harder to work with to an unreasonable degree, in my experience, and any perceived "velocity" gained from the dynamic nature of it is paid for doubly so by the lack of safety you get beyond toy projects.

I'm only slightly more for Erlang as a choice mostly because it's simpler than Elixir and doesn't have as much obfuscation of logic added to it that Elixir does, but in reality it's also a bad choice for any bigger system. The runtime is absolutely great, but the languages on it are generally not good enough.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @12:10PM (#23284078)
I'm a bit confused by this comment. Having used both Ruby and Elixir (more Ruby) both languages have type systems which are quite capable of modeling domains[1]. They lack static type checking, but I find that a thorough test suite catches most type errors anyway. And while creating a thorough test suite is costly, static types in most languages[2] don't reduce this burden much: there isn't an alternative to thorough testing.

[1] This looks fine to me? https://elixir-lang.org/getting-started/typespecs-and-behavi...

[2] I have limited experience with Haskell, but my impression is that the type capabilities do actually allow you to forego testing in a lot of cases. The next best static type system I've used is C#'s, which I used professionally for years, and in C# I think automated testing is still very necessary.

EDIT: I regret even talking about type checking here--that's not my point. My point is that for modeling domains, Elixir's type system is totally adequate. I'll agree that Elixir's type checking could be better, but that's not what the comment I was responding to said.

Re:Ask HN: Who regrets choosing Elixir? by james-mcelwain on Saturday May 23, 2020 @12:19PM (#23284163)
When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages. I don't think this should be confusing.

Specs/contracts are cool but ultimately don't afford the same kind of descriptive and expressive power that a static type system does.

> static types in most languages[2] don't reduce this burden much: there isn't an alternative to thorough testing.

However, there definitely is a burden about how much testing you have to write. I generally don't want to have to test every branch of my program to make sure a string doesn't slip through where an int should be or that variables are initialized and not null, etc.

Re:Ask HN: Who regrets choosing Elixir? by alexbanks on Saturday May 23, 2020 @12:45PM (#23284379)
I see that language parroted all the time - "With thorough enough testing a dynamic language shouldn't be a problem", and I have never understood it. Arguing to build what is essentially a build-time type checker in the form of automated tests seems twice as cumbersome for half the benefit. Instead of building tests that check each branch of a program's types, why not use a language that forbids dynamic typing? You should still have tests, but IMO tests that are just checking that a string is a string are A.) Time consuming, and B.) largely useless beyond type validation.
Re:Ask HN: Who regrets choosing Elixir? by smoe on Saturday May 23, 2020 @01:27PM (#23284739)
Not GP, but I have done plenty of TDD development in dynamic languages and not once have I written a test that checks whether a string is a string. You get that implicitly because others test will fail if the types don't match.

While I personally prefer certain statically typed languages over dynamic ones for new projects, In practice, for small to medium sized projects, runtime type errors is in my opinion much less of an issue as some people make it out to be. Except for null exceptions they rarely make it into production and if, are easy to track down and fix.

Interestingly, a lot of the people I have seen constantly running into type problems in say Python, are the ones coming from statically typed languages that keep insisting doing thing the way they are used to instead of embracing the duck.

Re:Ask HN: Who regrets choosing Elixir? by pavel_lishin on Saturday May 23, 2020 @03:19PM (#23285591)
> I see that language parroted all the time - "With thorough enough testing a dynamic language shouldn't be a problem", and I have never understood it.

"If you drive carefully enough, a car without seatbelts shouldn't be a problem!"

Re:Ask HN: Who regrets choosing Elixir? by alexbanks on Saturday May 23, 2020 @03:33PM (#23285693)
Exactly
Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @10:03AM (#23291575)
Analogies are a great way to explain things, but not so much a great way to prove things.

If you're writing software that's life and death critical like wearing a seatbelt, you should absolutely be using a strong, statically typed language, because catching errors at runtime is completely unacceptable. But incidentally, none of the proponents of static types on this thread have talked about any languages that I would actually use for this situation. Java or C-family languages certainly aren't strongly typed enough. Type systems aren't a magic bullet.

But in the vast majority of modern software, it mostly just matters that you catch and fix bugs quickly--whether you catch those bugs at compile time or runtime is usually not as critical.

Re:Ask HN: Who regrets choosing Elixir? by pavel_lishin on Monday May 25, 2020 @05:12PM (#23305041)
> Analogies are a great way to explain things, but not so much a great way to prove things.

What are we proponents of static types being asked to prove?

> But in the vast majority of modern software, it mostly just matters that you catch and fix bugs quickly--whether you catch those bugs at compile time or runtime is usually not as critical.

I would argue that catching bugs at compile time, before you ship them, is vastly preferable to catching them at run time.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Monday May 25, 2020 @11:53PM (#23307257)
> What are we proponents of static types being asked to prove?

Your arguments for why you think static types are better.

> I would argue that catching bugs at compile time, before you ship them, is vastly preferable to catching them at run time.

I would argue that you're only doing the benefit part of a cost-benefit analysis, which isn't very useful.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @12:56PM (#23284483)
> You should still have tests, but IMO tests that are just checking that a string is a string are

The correct completion to this sentence is "irrelevant.", because that's not what anyone is proposing.

The fact is, behavioral tests catch a lot of type errors even without intending to, and more to the point, if you test all the behavior you care about, then you don't care if there are type errors, because they only occur in situations where you don't care.

Re:Ask HN: Who regrets choosing Elixir? by jfim on Saturday May 23, 2020 @02:05PM (#23285016)
Having static type checking avoids errors caused by typos, missing match branches, and other brain fart-style mistakes. For example, in Elixir:

  f = fn
    {:ok, message} -> "It worked #{message}"
    {:eror, message} -> "There was an error #{message}"
  end
Running this

  iex(2)> f.({:ok, "yay"})
  "It worked yay"
  iex(3)> f.({:error, "oh no"})
  ** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/1
This kind of error isn't caught if all of the testing doesn't cover the error paths.

Contrast with Scala, where using Either (which can be Left or Right):

  def f(x: Either[String, String]) = x match {
      case Right(x) => s"It worked $x"
      case Left(x) => s"There was an error $x"
    }
If for example one forgets a branch:

  scala> def f(x: Either[String, String]) = x match {
       |     case Right(x) => s"It worked $x"
       |   }
                                          ^
         warning: match may not be exhaustive.
         It would fail on the following input: Left(_)
Or to follow the Elixir tuple pattern more closely:

  scala> sealed trait Status
       | case object Ok extends Status
       | case object Error extends Status
  trait Status
  object Ok
  object Error
  
  scala> def f2(x: (Status, String)) = x match {
       |     case (Ok, msg: String) => s"It worked $msg"
       |     case (Error, msg: String) => s"There was an error $msg"
       |   }
  def f2(x: (Status, String)): String
  
  scala> def f2(x: (Status, String)) = x match {
       |     case (Ok, msg: String) => s"It worked $msg"
       |   }
                                       ^
         warning: match may not be exhaustive.
         It would fail on the following input: (Error, _)
  def f2(x: (Status, String)): String
The typo also gives an obvious type error:

  scala> def f2(x: (Status, String)) = x match {
       |     case (Ok, msg: String) => s"It worked $msg"
       |     case (Eror, msg: String) => s"There was an error $msg"
       |   }
             case (Eror, msg: String) => s"There was an error $msg"
                   ^
  On line 3: error: not found: value Eror
Caveat: still learning Elixir and my Scala is rusty, so there might be better ways of doing the above. :)
Re:Ask HN: Who regrets choosing Elixir? by pavel_lishin on Saturday May 23, 2020 @03:20PM (#23285599)
> if you test all the behavior you care about, then you don't care if there are type errors, because they only occur in situations where you don't care.

If I test all the situations I care about, the one situation I thought I didn't care about is going to fuck me in production.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @12:25PM (#23292584)
If you test all the situations you care about and statically type check, the one situation you thought you didn't care about and that wasn't caught by the type checker is going to fuck you in production.

It's not useful to talk about a binary "bugs versus no bugs", because "no bugs" isn't plausible in most codebases.

It's also not useful to talk about "more bugs versus fewer bugs" because that's only part of the picture: the other parts of the picture are how much development effort was necessary to achieve the level of bugs you have, and whether the number of bugs you have, and when you have them, is acceptable.

If it's a life or death application where any bugs at runtime are unacceptable, then of course we want static types, but static types aren't enough: I'd also want a theorem prover, fuzzer, a large number of human testers, and a bunch of other things that require way too much effort to be useful in an average software project.

The vast majority of software projects, runtime bugs are acceptable as long as they don't lose data, cause downtime, or expose private information. If you catch these bugs during unit testing instead of 30 seconds earlier at compile time, that's fine. Static types might catch a few more bugs, but it is very much not in evidence that the level of effort involved is lower than equivalent unit testing in situations where reliability requirements are typical.

Re:Ask HN: Who regrets choosing Elixir? by _t0du on Saturday May 23, 2020 @01:46PM (#23284884)
My personal real life experience with Ruby developers disagrees with you, but I accept that I could just have experienced a set of developers that weren't very good at testing.
Re:Ask HN: Who regrets choosing Elixir? by peferron on Saturday May 23, 2020 @06:24PM (#23287107)
Trust your experience.

It's impossible to defeat the claim that "with good tests you don't need static type checking", since every counter-example can be dismissed by arguing that better developers would have covered that test case.

I can claim just the same that "with correct code you don't need tests", and dismiss every counter-example by arguing that better developers wouldn't have made that mistake.

Obviously we know that developers sometimes make mistakes, and sometimes these mistakes are in the tests themselves. So trust your experience regarding how this all works out.

Re:Ask HN: Who regrets choosing Elixir? by _t0du on Saturday May 23, 2020 @06:39PM (#23287222)
Yeah. You formulated my opinion much more elegantly than I could've - in my experience it's always the "Well if the tests didn't catch this, we just aren't testing enough." Which in my experience is a losing strategy, you'll never test "enough" in languages like Ruby.

In my experience this idea always brings a strawman, "Well in statically typed languages you still have to test", which is obviously true. But the type of tests and the content of the tests is very different.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @09:52AM (#23291508)
> Yeah. You formulated my opinion much more elegantly than I could've - in my experience it's always the "Well if the tests didn't catch this, we just aren't testing enough." Which in my experience is a losing strategy, you'll never test "enough" in languages like Ruby.

Maybe someone is saying that, but I didn't say that.

My question isn't whether you can test enough to catch all bugs. My question is whether time spent wrangling types gets you more value than time spent writing tests.

> But the type of tests and the content of the tests is very different.

Are they? How so?

Again, unit tests of the form `assert isinstance(foo, type)` are an antipattern--that's not what I'm proposing.

Re:Ask HN: Who regrets choosing Elixir? by alexbanks on Sunday May 24, 2020 @01:19PM (#23292981)
> My question isn't whether you can test enough to catch all bugs. My question is whether time spent wrangling types gets you more value than time spent writing tests.

Yes, by a tremendous amount, in my experience.

> Are they? How so?

Tests are only as good as the person writing them. I could see a model working where the person that wrote the code isn't the person that writes the test, but that's definitely not how most development orgs work. If a dev is good enough/capable of writing comprehensive enough tests to accurately test the correctness of their code, that's great, but almost none are (I say almost because I actually mean "actually none" but am leaving room for my own error). If you're an average dev, you'll write average tests (neither of these are insults), but that means you still won't catch everything (by a lot).

I think another comment of yours on my posts actually summarizes the core disconnect between your thinking and mine.

> But in the vast majority of modern software, it mostly just matters that you catch and fix bugs quickly--whether you catch those bugs at compile time or runtime is usually not as critical.

I couldn't possibly disagree more with this statement.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Tuesday May 26, 2020 @12:28AM (#23307420)
> > My question isn't whether you can test enough to catch all bugs. My question is whether time spent wrangling types gets you more value than time spent writing tests.

> Yes, by a tremendous amount, in my experience.

Well, then I'd have to ask what your experience is that causes you to believe this? I don't mean years, I mean what languages, and what, more specifically, you observed.

> Tests are only as good as the person writing them. I could see a model working where the person that wrote the code isn't the person that writes the test, but that's definitely not how most development orgs work. If a dev is good enough/capable of writing comprehensive enough tests to accurately test the correctness of their code, that's great, but almost none are (I say almost because I actually mean "actually none" but am leaving room for my own error).

Static types are also only as good as the person writing them. C's type system, for example, lets through a wide variety of type errors. And users of a type system can easily bypass a type system or extend it poorly: I've written a lot of C#, and while C# has a type system which, when effectively used, can be extremely effective, I've also seen it used with dependency injection to cause all sorts of tricky bugs.

I don't think we can conclude much from bad programmers doing bad things except that good programmers are better, which is practically tautological.

> If you're an average dev, you'll write average tests (neither of these are insults), but that means you still won't catch everything (by a lot).

So? "Catching everything" isn't a thing--if you're talking about that, you're not talking about reality. There are two systems I've ever heard of which might not have any bugs--and in both cases an absurd amount of effort was put into verification (far beyond static types), which, even late in the process, still caught a few bugs. Static types aren't adequate to catch everything either.

> > But in the vast majority of modern software, it mostly just matters that you catch and fix bugs quickly--whether you catch those bugs at compile time or runtime is usually not as critical.

> I couldn't possibly disagree more with this statement.

shrug Okay... To be clear, "runtime" doesn't mean "in production".

Re:Ask HN: Who regrets choosing Elixir? by alexbanks on Tuesday May 26, 2020 @06:54PM (#23317419)
> Well, then I'd have to ask what your experience is that causes you to believe this? I don't mean years, I mean what languages, and what, more specifically, you observed.

Probably 20 Rails developers across 3 companies

> So? "Catching everything" isn't a thing

The "everything" I'm referring to is less about "all bugs", and more about "Type errors, spelling mistakes, missing imports, etc". All code has bugs. Not all languages allow remedial spelling errors to make it into a build.

> shrug Okay... To be clear, "runtime" doesn't mean "in production".

It sure does not. I'm not sure that changes anything. It seems like being difficult for the sake of it to argue that it's the same value to catch potential bugs now vs. later. Obviously the answer is now.

Re:Ask HN: Who regrets choosing Elixir? by bryanrasmussen on Saturday May 23, 2020 @01:04PM (#23284548)
type errors are generally the lowest common denominator error, thus tests that catch higher level errors will also catch whatever typing error is related to the actual error you are testing for.

Not to say I haven't had benefits from catching type errors but generally not as great as those I have from having an automated GUI test running.

Re:Ask HN: Who regrets choosing Elixir? by JohnBooty on Saturday May 23, 2020 @12:47PM (#23284397)

    However, there definitely is a burden about how much
    testing you have to write. I generally don't want to 
    have to test every branch of my program to make sure 
    a string doesn't slip through where an int should be 
    or that variables are initialized and not null, etc.
This has not been my experience!

I've been writing Ruby full-time for about six years (including one of the largest Rails apps in the world) and I don't find this particular aspect of Ruby to be a problem whatsoever relative to statically-typed language.

Ruby is famously easy to write tests for. Creating mocks in a dynamic language is such a breeze. There are plenty of problems with Ruby but an increased test suite burden is NOT one of them. "Confident Ruby" by Avdi Grimm is a great read in this vein; not about testing specifically but writing confident Ruby code in general.

Part of it is simple, human-friendly code hygiene. Give your arguments descriptive names and use keyword params when possible. If you have a method:

    foo(user_name:, height_cm:)
...then you'd really have to be asleep at the wheel to write something like this elsewhere in your code:

    foo(user_name: 157, height_cm: "Smith")
And so you don't need to write your code or your tests with any real extra level of paranoia. If somebody does pass a string to `height_cm:` it will return a runtime exception, just like it should.

Of course, I do get type errors all the time in Ruby, but that's when I'm parsing JSON or something and that's generally not something static typing's gonna help you with anyway.

Now... there ARE places where I miss strong typing in Ruby.

One, I miss having extremely intelligent IDEs like you can have with Java or C#. I absolutely loved Visual Studio and Resharper in the C# world. The amount of reasoning it can do about your code and the assistance it can give you is absolutely bonkers.

Two, obviously, there is a price in runtime execution speed and RAM usage to be paid for dynamic typing. I don't find raw execution speed to be much of a bottleneck in a Ruby app because Postgres/Redis/etc are doing all my heavy lifting anyway. RAM usage and app startup times with large applications is more of a real-world issue.

Re:Ask HN: Who regrets choosing Elixir? by phtrivier on Saturday May 23, 2020 @01:38PM (#23284825)
My counterpoints would be:

First, if you're writing any kind of big code, than somewhere, in your code base, someone else is writing a code where the user name is spelled `username`. Or `user`. You don't have to be "asleep at the wheel" to not remember, or not know, which is which. So you're going to type the wrong one (not necessarily on purpose), and you'll get a runtime error. Not that bad, sure, but you'll get it.

Also, at some point, you'll realize that a string is not the ideal way to represent a user name [1], and some of the functions that deal with users are going to start returning a Struct %User{first_name: ..., middle_name: ....}. Or will it be a Map %{"first_name" => ...} ? And surely you're going to track all the calls of `foo` to fix them. And all the calls of all the calls of `foo`, because, who knows ? And suddenly you're doing the mental job of a static type checker. Surely you're not "asleep at the wheel" anymore, because you're doing the work of the wheel by manipulating the gears by hand.

Bottom line: I'll gladly admit that I'm too old and stupid to do that anymore. I had typechecking in the 90s. Give it back.

[1]: https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-...

Re:Ask HN: Who regrets choosing Elixir? by JohnBooty on Saturday May 23, 2020 @03:04PM (#23285483)
Thank you for the thoughtful reply!

    So you're going to type the wrong one (not 
    necessarily on purpose), and you'll get a runtime 
    error. Not that bad, sure, but you'll get it.
I agree with your facts but not your conclusion here. This certainly happens, but this is trivially caught by your integration tests.

Now, it's certainly true that in a static language, your compiler would catch this for you. In a decent IDE it would be pointed out to you while you type.

However, static or dynamic, you're going to be writing tests anyway, so I can't view this as some sort of increased burden when it comes to writing tests.

    Also, at some point, you'll realize that a string is not the 
    ideal way to represent a user name [1]
I have loved that article since it came out! It's one of those things I saved as a PDF just in case the original goes offline someday.

I don't think your examples are realistic, at all, though.

1. If you replace `User#first_name` and `User#last_name` with `User#name` (which returns a `Name` object) your test suite is going to blow up all over the place every time you call the deleted `User#first_name` or `User#last_name` methods anyway. And now you have a list of places where you need to fix your code.

2. But, what if you update the internal structure of `Name` over time? Some of the above applies. But also callers of `Name` shouldn't know too much about `Name` anyway - it should be providing some kind of `Name#display_name` or whatever function that handles all of the complexity and returns a dang string anyway.

Everything I've written here presumes the existence of a test suite, of course. Which of course takes time to write and maintain. But any nontrivial project needs one anyway regardless of language or type paradigm, right?

    Bottom line: I'll gladly admit that I'm too old and 
    stupid to do that anymore. I had typechecking in 
    the 90s. Give it back.
Absolutely the same here. But, I seem to miss it in different places than you.

I miss static types when I'm writing code. I want my IDE to tell me the types and type signatures when I type, and draw a little squiggly line under my code when I get it wrong. In Ruby, I wind up having 10 different files open at a time in my text editor so I can see what various methods are expecting.

This is mitigated somewhat by simply bashing out a lot of my code in irb/pry directly, since pry's `show-source` can at least tell me stuff.

Re:Ask HN: Who regrets choosing Elixir? by theonething on Saturday May 23, 2020 @11:50PM (#23288928)
> I wind up having 10 different files open at a time in my text editor so I can see what various methods are expecting.

Huh, I thought this was normal. Not everyone does this?

Re:Ask HN: Who regrets choosing Elixir? by phtrivier on Sunday May 24, 2020 @06:56AM (#23290684)
No. Something like "intellisense" has existed for decades. It relies on the static type system to "guess" what functions make sense in a given context. You Ctrl-Space your way to writing the code , ans get Brain cycles back to actually think about stuff.
Re:Ask HN: Who regrets choosing Elixir? by JohnBooty on Sunday May 24, 2020 @12:32PM (#23292622)
Yes. This is the scenario in which I truly miss a good old-fashioned static type system and a big ol' intelligent IDE. Specifically, because of what you said: it frees up brain cycles for me to think about the real problems.

My highly subjective belief and experience is that Ruby and its ecosystem has enough other perks to make up for this loss. But, I definitely accept others might feel otherwise.

Re:Ask HN: Who regrets choosing Elixir? by ianamartin on Saturday May 23, 2020 @12:45PM (#23284381)
>> When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages.

Really? You're going to go with "most languages implement static typing"?

That seems like a bold statement.

Re:Ask HN: Who regrets choosing Elixir? by james-mcelwain on Saturday May 23, 2020 @12:59PM (#23284512)
I'm not making a claim about all languages, I'm talking about languages that support any kind of extensible type validation, whether statically or at runtime.
Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @10:00AM (#23291562)
If you're willing to include dynamic types, then I really don't know what you're even talking about. Literally no language I know of doesn't do validation at runtime: assembly does type validation at runtime (try dividing by zero).
Re:Ask HN: Who regrets choosing Elixir? by mapcars on Saturday May 23, 2020 @12:46PM (#23284386)
>Specs/contracts are cool but ultimately don't afford the same kind of descriptive and expressive power that a static type system does.

What exactly dialyzer type checking lacks compared to static type systems?

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @12:52PM (#23284450)
> When people refer to "typing", it is almost certainly reasonable to assume they are referring to static typing, as implemented by most languages.

I don't think that's a reasonable assumption at all. Even if, as you assert, the average person doesn't understand that types exist in dynamically-typed languages, I don't think that means I have to conform to common misconceptions.

> Specs/contracts are cool but ultimately don't afford the same kind of descriptive and expressive power that a static type system does.

True, but not what I was talking about.

Could you explain what descriptive and expressive power is missing here?

    class Square(Rectangle):
        def __init__(self, side_length):
            self.side_length = side_length

        @property
        def height(self):
            return self.side_length

        @property
        def width(self):
            return self.side_length
Re:Ask HN: Who regrets choosing Elixir? by uryga on Saturday May 23, 2020 @02:24PM (#23285165)
> Could you explain what descriptive and expressive power is missing here?

tldr: i haven't seen a runtime typechecker that handles generics and function types in a satisfactory manner.

i've used various Python libraries for runtime type-checking (based on `typing` annotations) like `typeguard`. and they work okay for simple types, but suck for anything involving generics and function types. checking if something is a `List[int]` every time it's passed as a parameter is too expensive, because you have to go through the whole list (and you're out of luck if it's an Iterator[int] - can't traverse that without exhausting it). runtime typecheckers don't have enough information to check if something is a valid `CustomList[int]`. and they have no way of checking if e.g. a function (passed as a parameter) is actually a `str -> int`, at best you'll find out when you call it.

and runtime checkers, at least the ones i've used, often end up requiring more annotations than i'd have to write in a type-inferred language. it might be possible to work around that to some degree, but I think that's a fundamental limitation – unlike a static checker, they only have info about code that already ran. so you'll have to annotate code like this:

  f xs = cons 'a' xs
because a runtime checker can't "look into the future" and tell that based on the usage of `cons`, the only sensible type for `xs` is List[Char], so `f` must be of type `List[Char] -> List[Char]`.
Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @10:40AM (#23291814)
> i've used various Python libraries for runtime type-checking (based on `typing` annotations) like `typeguard`.

Let's just stop right there, since it's immediately clear you aren't answering the question I asked. You're talking about type checking, not descriptive and expressive power.

The topic is whether dynamic types are suitable for domain modeling, not whether dynamic types provide static type checking. We all agree that dynamic types don't provide static type checking.

Re:Ask HN: Who regrets choosing Elixir? by uryga on Sunday May 24, 2020 @11:21PM (#23297464)
alright, just to clarify, from the comment that introduced expressive power into the discussion:

> Specs/contracts are cool but ultimately don't afford the same kind of descriptive and expressive power that a static type system does.

i understand that as "the ability to describe/enforce the domain's rules".

now, i guess i made a bit of leap, jumping to runtime typechecking. my thinking was that while modelling your domain, you might want to specify that e.g. `width` and `height` must at least be numeric (i know i would!); `typeguard` et al are a concise way of doing that in Python, but have their limitations. so static types can be more "expressive" if the tools i mentioned (generics and function types) are useful for describing your domain model, which i often find to be the case.

looks like i missed the mark there; but in that case, i'm not sure what point you're making with that Square class. it's hard to say what's missing (or not) because there's not a lot there.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Tuesday May 26, 2020 @11:30AM (#23312371)
Well, let's be clear here: the code already expresses that height and width are numeric. You read the code and knew they were numeric; QED. In fact, if you think a bit deeper, you probably know a few more things about the type of those variables: they're positive, for example.

And if you're using a mainstream statically typed programming language, you probably aren't actually going to express that it's a numeric using the type system. 90% of the time someone will just throw `int` on there and call it a day, and that type expresses a bunch of lies about the height and width: it says it can be negative, and it says it can't be a decimal, and it says it can't be greater than the INT_MAX of you machine. `unsigned long` and `double` are both a little better, but are still expressing a bunch of lies. And that's if you are in a more modern language: in C, for example, you're telling the compiler that it's totally cool to add the side_length to a char* and (depending on you settings) not even warn about it.

So I have to ask, where exactly is this expressive power you're talking about? You're only gaining the ability to express things to the compiler, not humans, and it doesn't actually give you the ability to express what you want to express to the compiler. You've eliminated the narrow class of bugs where:

1. The code passes in a non-numeric.

2. The bug occurs on a path not traversed in normal testing.

And you've done this at the cost of your code not being able to handle a lot of the numeric values you might want to be able to handle.

Re:Ask HN: Who regrets choosing Elixir? by uryga on Tuesday May 26, 2020 @04:47PM (#23316196)
honestly, if this is going to be about static vs dynamic typing in general, i'm going to peace out because this argument has been rehashed about a million times. and we seem to be talking past each other anyway

i just wanted to make a point about how checking types at runtime doesn't mesh well with generics and functions, so it's always going to be limited on that axis. and perhaps there's a dynamically typed nirvana where you just handle that differently, but it's a problem i personally had

[edit: removed unnecessary snarkiness]

Re:Ask HN: Who regrets choosing Elixir? by james-mcelwain on Saturday May 23, 2020 @01:08PM (#23284585)
> the average person doesn't understand that types exist in dynamically-typed languages

Again, this is needlessly uncharitable as to what people mean when they talk about type systems, which is obviously about the capabilities of defining new types for program analysis, not that the runtime has an internal conception of types.

> Could you explain what descriptive and expressive power is missing here?

Sure! Looking at this, I have no idea what the size of side_length is, whether it's possible for it to be negative, or whether it's possible it to be null.

Of course, unless you're writing purely square based software, most domains are more complex than this. But I still think it's pretty helpful to know the properties of the parameters being passed to build your square are!

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @09:54AM (#23291529)
> > the average person doesn't understand that types exist in dynamically-typed languages

> Again, this is needlessly uncharitable as to what people mean when they talk about type systems, which is obviously about the capabilities of defining new types for program analysis, not that the runtime has an internal conception of types.

There is nothing "internal" about the example I gave. That's valid Python code that creates a type.

My definition (which happens to be the actual definition of the word) charitably assumes that people know dynamic type systems exist, so I don't think you can really accuse me of being uncharitable. If anything I'm being too charitable, as evidenced by this conversation.

> Sure! Looking at this, I have no idea what the size of side_length is, whether it's possible for it to be negative, or whether it's possible it to be null.

> Of course, unless you're writing purely square based software, most domains are more complex than this. But I still think it's pretty helpful to know the properties of the parameters being passed to build your square are!

Do you really not know whether side_length can be negative or null? Or are you just saying that to be argumentative? If we're pretending we don't know obvious things, why not just go all the way and pretend we don't know that side_length is a number?

As for not knowing the size: why would you want to have to know the size? The fact that this square will work with any numeric type is a feature, not a bug.

Now, consider this (disclaimer: my C++ is rusty, and I didn't syntax check this):

    class Square: Rectangle {
      private:
        double sideLength;
      public:
        Square(double sideLength) {
          this.sideLength = sideLength;
        }
    }
Let's evaluate this based on your complaints about the Python example:

1. The size of sideLength. Well, yes, this example does tell you what size it is. Which is rather annoying, since now you have to cast if you want to pass in an integer, and you might overflow your bounds. This is an annoyance, not a feature.[1]

2. We know that sideLength can't be negative because we know what squares are. The type doesn't enforce that. You could enforce that by using unsigned int, but then you can't handle decimals. And in either case, you can't use very very large numbers. I haven't worked in a static typed codebase which has an unsigned BigDecimal type, have you?[1]

3. We know that sideLength can't be null because we know what squares are. The type system technically also tells us that, but the type system telling us what we already know isn't particularly useful.

[1] Haskell's numeric type can actually handle this much more cleanly than C++, as I mentioned upthread. But in typical Haskell, you'd probably just let the types be implicit in a lot of cases.

Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @12:20PM (#23284167)
> I'm a bit confused by this comment. Having used both Ruby and Elixir (more Ruby) both languages have type systems which are quite capable of modeling domains[1]. They lack static type checking, but I find that a thorough test suite catches most type errors anyway.

Most of this is incorrect, both for and against your argument. Elixir has a very incapable and incomplete type system. It's optional but can be checked via `dialyzer` but never confidently and exhaustively checked because `dialyzer` will sometimes plain not work, sometimes be foiled by bad library specs and sometimes fall back to "Everything must be OK because I can't prove this incorrect".

All in all it's not a useful substitute for a real type system used to model things.

Type specs aren't useful for domain modelling but serve mostly as extra documentation more than anything.

Testing is important no matter what language you use (except maybe dependently typed ones, I don't know?). It's not a substitute for a good type system. Even disregarding type-directed property tests with automatically generated test cases, there's a lot of value to be had in tests that actually just test logic, not basic types.

Re:Ask HN: Who regrets choosing Elixir? by mapcars on Saturday May 23, 2020 @12:50PM (#23284424)
Erm, you can setup dialyzer to be as strict as possible. This might not catch all the errors because of the nature of messages, but this is a pretty small part of a system usually and can be covered by tests.

>All in all it's not a useful substitute for a real type system used to model things.

>Type specs aren't useful for domain modelling

Can you give me some examples?

Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @01:18PM (#23284672)
> Erm, you can setup dialyzer to be as strict as possible.

No. This is just plain false. Having used dialyzer since 2016 I can tell you it's not useful as a substitute for statically checked types via a compiler, with real strictness (which includes "When I don't have enough info, that's a type error").

> This might not catch all the errors because of the nature of messages, but this is a pretty small part of a system usually and can be covered by tests.

Not only will it not catch obvious type errors, it will also report false types when the core team doesn't use dialyzer in their libraries (because it doesn't work). These will bubble up to you instead and while you're mad they're not using dialyzer you'll still have to admit you understand why they don't.

I'm not sure what you mean by give you examples of how Elixir type specs aren't useful for domain modelling. They're ad-hoc, serve as documentation at best and even if they had structural power enough to express basic things they aren't checked at all, so you're getting none of the guarantees you would get in a statically checked language where your model changes and you can safely go forward by seeing what needs changing additionally to adapt.

Re:Ask HN: Who regrets choosing Elixir? by mapcars on Saturday May 23, 2020 @02:15PM (#23285067)
>They're ad-hoc, serve as documentation at best and even if they had structural power enough to express basic things they aren't checked at all

What they are is how you use them, can you show how you can model something with static types and how it is different from dialyzer?

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @12:57PM (#23284495)
Modeling your domain using types and checking your types are two different things.

Could you explain where you think the Elixir type system falls short for modeling domains? Your post only gives examples of problems with type checking.

Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @01:13PM (#23284623)
Elixir doesn't have any concept of real tagged unions or sum types. Modelling is intimately connected to checking because when we change something (as we are wont to do) we want to have that change bubble out into the rest of the system safely. This just isn't reliable at all in Elixir.

The most potent data modelling tool you have in Elixir is a `struct`, which is just a `Map` with `atom`s for keys. You can then associate this map with an ad-hoc `atom` tag in some return value if you want, and that's as far as we can go.

Modelling behavior in Elixir is easier and better, with processes, but having absolutely zero guarantee that what you're doing makes sense when it comes to data hierarchies and composition is just not useful when trying to outline what data represent and how it can be represented.

Re:Ask HN: Who regrets choosing Elixir? by mapcars on Saturday May 23, 2020 @02:19PM (#23285108)
>Elixir doesn't have any concept of real tagged unions or sum types

What about this?

  -type int_or_str() :: {a, integer()} | {b, string()}.
Re:Ask HN: Who regrets choosing Elixir? by ed25519FUUU on Saturday May 23, 2020 @12:17PM (#23284148)
> They lack static type checking, but I find that a thorough test suite catches most type errors anyway.

Maybe ruby is different than python in this regard, but with python I see a lot of “assert isinstance(arg, dict)” in functions which would not be necessary with type checking.

Feeding an unexpected type into a function, and having it carry on as normal, is really scary.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @01:04PM (#23284550)
I've seen this too, but I tend to think of it as an antipattern.

The fact is, in most cases a Python function won't carry on as normal if you feed it an unexpected type, because while Python's type system isn't static, it is fairly strong. In general I am a fan of strong types and I would like it if Python's type system were a lot stronger.

But ultimately this isn't what my post was about: I'm talking about modeling your domain with types, not type checking.

Re:Ask HN: Who regrets choosing Elixir? by alexilliamson on Saturday May 23, 2020 @03:49PM (#23285796)
What do you mean it's fairly strong? Not challenging you, I'm just trying to get my head around all the type stuff.
Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @11:58AM (#23292392)
As hwayne said, most of the time Python won't do implicit type coercion. What this means is, if you try to do something that doesn't make sense based on the types, it will throw an error rather than go on. For example:

    ~/$ python
    Python 3.7.4 (default, Oct 12 2019, 18:55:28) 
    [Clang 11.0.0 (clang-1100.0.33.8)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> hello = 'Hello, world'
    >>> one = 1
    >>> hello + 1
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can only concatenate str (not "int") to str
To put this in context, type systems can be roughly divided into 4 categories along the strong/weak and static/dynamic axes:

1. Strong static types (makes a lot of assertions about type, checks these assertions at compile time; Haskell, ML, OCaml, Rust, C# are reasonable examples--Haskell folks would probably laugh at me including C# here, but it's the only example in widespread non-academic use). Example (C#):

    var hello = "Hello, world";
    var one = 1;
    var result = hello + one // Doesn't compile
2. Strong dynamic types (makes a lot of assertions about type, checks these assertions at run time; Python is the best example I have, but to be honest, it's not a great example--I think the type system could be a lot stronger). See the Python code above for an example.

3. Weak static types (makes few assertions about type, checks these assertions at compile time; C, C++ are good examples, although it's arguable that C actually does more checking at run time than at compile time). Example (C):

    char* hello = "Hello, world";
    int one = 1;
    char* result = hello + one; // Happily compiles
4. Weak dynamic types (makes few assertions about type, checks these assertions at run time; JavaScript is a great example of this). Example (JavaScript):

    >>> var hello = "Hello, world"
    undefined
    >>> var one = 1
    undefined
    >>> hello + 1
    "Hello, world1"
In general, I have a slight preference for static types over dynamic types, but I think that difference is overrated. I care a lot more about my preference for strong types over weak types.
Re:Ask HN: Who regrets choosing Elixir? by alexilliamson on Wednesday May 27, 2020 @04:43PM (#23329697)
Awesome thanks!
Re:Ask HN: Who regrets choosing Elixir? by hwayne on Saturday May 23, 2020 @04:28PM (#23286115)
Most of the time Python doesn't do implicit type coercion.
Re:Ask HN: Who regrets choosing Elixir? by neilwilson on Saturday May 23, 2020 @12:26PM (#23284231)
"Feeding an unexpected type into a function, and having it carry on as normal, is really scary."

That is how duck typing works. Generally you shouldn't use "is instance" but more use a set of "callable" checks to make sure the structure has the required functions.

Things like Go Interface types are, of course, a formalisation of duck typing and is what has helped static typing come back into fashion.

Re:Ask HN: Who regrets choosing Elixir? by takeda on Saturday May 23, 2020 @01:31PM (#23284773)
This still produces a runtime error, to make code maintainable you want to be able to check the types without having to run the program. The type annotations help with that, they allow to spot bugs in the code and make an IDE to correctly refactor code and provide autocomplete.
Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Sunday May 24, 2020 @12:09PM (#23292471)
> This still produces a runtime error, to make code maintainable you want to be able to check the types without having to run the program.

I strongly disagree. There are plenty of ways to write maintainable code. Static types can help, but it's quite possible to write maintainable code in dynamically typed languages.

And, for the record, running unit tests doesn't require me to run the whole program.

And, even if I never explicitly test types (assert isinstance(foo, str) is an antipattern anyway), behavioral tests of my code will turn up most type errors.

The obsession with checking types at compile time rather than 30 seconds later while running the unit tests doesn't serve anyone.

Re:Ask HN: Who regrets choosing Elixir? by ed25519FUUU on Saturday May 23, 2020 @01:39PM (#23284831)
Type checks don’t actually enforce anything though, and as far as I can tell don’t even produce a warning in vscode unless everything is typed (a typed var fed into a typed function signature).
Re:Ask HN: Who regrets choosing Elixir? by takeda on Saturday May 23, 2020 @02:14PM (#23285059)
Correct, the annotations in python don't enforce anything, although there are packages that make them produce errors, but again, those errors are at runtime.

You can run mypy which will list problems. Also PyCharm understands the annotations and does all the things I mentioned it do: proper autocomplete, proper refactoring functionality and highlighting errors

Re:Ask HN: Who regrets choosing Elixir? by neilwilson on Saturday May 23, 2020 @12:22PM (#23284189)
Type systems are really a set of comprehensive tests you don't have to write yourself that cover a subset of the things you need to test for.

Static languages fell out of favour last time round the dynamic/static merry-go-round because the typing started to get in the way. You ended up writing more type boilerplate than actual code - and not breaking your methods/functions down into smaller functions to avoid having to write out even more type boilerplate.

I often wonder whether type annotations that allow a processor to generate tests that can integrate into your test suite would be a useful thing to have. Sort of like a C preprocessor.

Then you could add ML type headers to Elixir functions and get a set of ExUnit tests back.

Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @12:28PM (#23284243)
> I often wonder whether type annotations that allow a processor to generate tests that can integrate into your test suite would be a useful thing to have. Sort of like a C preprocessor.

We already have this in things like `Arbitrary` type classes, `QuickCheck`, `Hedgehog`, etc.. Hundreds of automatic test cases generated so that you don't focus only on "I thought of these 5 test cases" type of testing.

There is a PureScript compiler called `purerl` for the BEAM which can be used to write BEAM code in a ML derivative. It works and I personally would use it if I had to deliver BEAM code next week. For the most part it's the answer to the "you can only write BEAM code in bad languages" issue.

Re:Ask HN: Who regrets choosing Elixir? by kerkeslager on Saturday May 23, 2020 @01:00PM (#23284523)
> Type systems are really a set of comprehensive tests you don't have to write yourself that cover a subset of the things you need to test for.

Maybe in a very strongly-typed language, but having used a pretty wide variety of statically-typed languages, I can confidently say none of them had strong enough type systems that the assertions made by the type system could be considered "comprehensive". You still need a test suite.

Re:Ask HN: Who regrets choosing Elixir? by crazydoggers on Saturday May 23, 2020 @12:29PM (#23284257)
I agree, but I think it’s a common misconception. Having used many languages, both for very large and small projects, languages with compile time static type checking and run time dynamic type checking, I find it’s easy to rely too much on static type checking. I think what happens for a lot of programmers is that static type checking uncovers a lot of basic bugs and typos, so they feel like it has a major advantage over dynamic. The problem though is that it’s a false sense of security because you’ll always end up with complex logic bugs that no compile system is ever going to catch, so you end up needing test suites anyway.

Static type checking does have some advantages, it can ease some of the low level testing burden. For instance, using a tool like Dialyxir (dialyzer) is helpful in elixir to give you that extra security of static type checking.

For me it’s always ended up being that I’m more productive with dynamically typed languages and the flexibility they offer.

Re:Ask HN: Who regrets choosing Elixir? by eropple on Saturday May 23, 2020 @12:42PM (#23284357)
This may sound like a dismissal, and in a way it is, but: get a better type system, and really understand it. The kinds of logic problems that you describe can be greatly limited—without wasting one’s time—with a more expressive type system. This is one of the reasons I lean so heavily on TypeScript today; I can express my data in the forms it actually should be expressed in, pretty easily, and use that to constrain the logic involved. I can then use features like assert guards (“if this method returns then the listed argument must be type T”) and type guards (if returns at all, the single passed argument must be type T”) to strengthen my understanding of the processes resulting in that data. I can then use a much thinner and much faster to write set of unit tests to proof cross-cutting concerns and integration tests to prove the end-to-end case.

It’s not a false sense of security; it’s automation to cut out the stupid bottom 75% or so of boring-to-write, disastrous-to-screw-up test garbage that we all have better things to do with our time than duct-tape together.

(Also, Dialyzer is pretty bad by comparison to a real type checker. At best it’s spotty and inconsistent, it fails open in weird ways, and libraries rarely implement it. Elixir has an argument for “the least worst dynamically-typed language in common use” but Dialyzer ain’t it.)

Re:Ask HN: Who regrets choosing Elixir? by crazydoggers on Saturday May 23, 2020 @12:46PM (#23284391)
At the end of the day, it’s about can you deliver that project on time and with limited bugs. Everyone’s experience will be different, so maybe accept that different programmers work better with different systems.

I can tell you with 20 years of programming experience that static type systems don’t make me more efficient... and I’ve used them all.

And just because I can see the reply coming, I’ve worked with programmers using static type checking that have turned out horrible bug ridden code. It’s just not a cure all.

So can we please accept each other’s choices about type systems. “Can’t we all just get along”

Ultimately if it matters to you, then choose what works. But don't assume or try and tell everyone it makes one language definitely better than the other, because things aren’t that simple.

Re:Ask HN: Who regrets choosing Elixir? by eropple on Saturday May 23, 2020 @03:14PM (#23285559)
Put frankly: I’m not going to “accept” that because I’ve watched programmers with twenty years of experience (woe betide me and my mere thirteen!) tank projects through this kind of arrogance. And it is arrogance, to dress up the limitations of a meatbag as a positive against the tireless specificity of the machines.

Then those meatbags realize that they have to refactor their code and the world ends.

The computer is infinitely better at crossing the t’s and dotting the i’s than you are. Or I am. Relying on conscientiousness when you have tools to measure and correct is a sucker’s bet. And I will go so far to say that with the wonderful tools available to us in 2020, dynamically typed languages put “on time” and “limited bugs” in an unnecessary tension.

Re:Ask HN: Who regrets choosing Elixir? by crazydoggers on Sunday May 24, 2020 @02:38PM (#23293560)
Wow... talk about arrogance! I think you’re unclear about the definition of that word. I’m suggesting that developers have choice in what works for a given project. It’s arrogance to think only your choice is correct.

You’re the type of programmer that tanks projects because of that arrogance and an inability to work with other “meatbags”. Maybe for you it’s all about code perfection, but for the rest of humanity it’s about making a product that works, solves a problem, makes the world a better place, or earns a profit.

Too bad my suckers bet has paid off with success and money. Best of luck with your attitude in life.

Guess these Github meatbags have made a suckers bet on a dynamic language. No way they could be efficient or successful maintaining or refactoring a project of that scale. (Yes that’s sarcasm for the sarcastically impaired)

https://github.blog/2019-09-09-running-github-on-rails-6-0/

Re:Ask HN: Who regrets choosing Elixir? by joelbluminator on Thursday May 28, 2020 @10:04AM (#23337330)
Put frankly: you are talking out of your own experience and extrapolating onto the world. What a shocker that as a Ruby dev I have different views than you, who would have thunk...
Re:Ask HN: Who regrets choosing Elixir? by 59nadir on Saturday May 23, 2020 @12:36PM (#23284317)
> Static type checking does have some advantages, it can ease some of the low level testing burden. For instance, using a tool like Dialyxir (dialyzer) is helpful in elixir to give you that extra security of static type checking.

Dialyzer isn't an answer to static type checking. It barely works half the time and cannot be relied on to check things exhaustively. It's so bad that even libraries created by core contributors have type spec errors in them regularly. Why? Because they don't use it, because it's not reliable.

Both `Ecto` and `StreamData` had these issues several times and I can only assume you could find many more if you were even more invested in using larger parts of the eco-system.

Re:Ask HN: Who regrets choosing Elixir? by gedy on Saturday May 23, 2020 @01:11PM (#23284607)
This resonates with me as the first 10 years of career was using static typed languages, and saw that I and others in my circle were mostly using it as a very basic type of unit testing. This is helpful but at the cost of extra code and boilerplate. Some folks were incredulous that I shifted to languages like JavaScript and was fine with the weak typing, but tbh I'm a much better at unit testing than in the past. I've never really experienced the "omg no types" reaction that many people do. Different strokes I suppose.
Re:Ask HN: Who regrets choosing Elixir? by dnautics on Saturday May 23, 2020 @04:27PM (#23286108)
I think there's a eye-poppingly large part of the community won't write tests unless they're dragged into it kicking and screaming and it gives them to "not have to write tests". I get it. Tests can feel like you're writing your code twice, and, they can add a bit of drag when it's time for refactor (a good thing IMO). If I am permitted to be cynical, a testing culture discourages "think about it really hard and then pull a solution out of your nether regions"-driven programming, which is a culture that is promoted by hiring practices at... Certain well known companies, which, in turn, is cargo-culted by startups.

Also most PLs/frameworks have very bad testing ergonomics, so that doesn't help.

You can't publically admit to "hating tests" because that has very bad optics. So, being a static typing zealot is the next best thing (after all, it will protect you from some classes of errors that are covered by testing). You pay for not writing tests in a bit of boilerplate, but boilerplate doesn't feel like you're writing code twice.

Re:Ask HN: Who regrets choosing Elixir? by eropple on Saturday May 23, 2020 @04:54PM (#23286340)
I don't agree with this at all. I am about as hardcore a static-typing advocate as you'll find--and I love tests. I write tests before I write code whenever I can do so.

But I also like writing tests to prove logic and rules, and not tests for data validation--because computers are incredibly good at nitpicky stupid shit, they can and should and must do it for me, and I have more important things to care about than "did they pass an int when I wanted a string?".

Modern statically-typed languages elide a great deal of that boilerplate you refer to, while still providing protection against foolish errors. And given that the rest of it acts as a runtime-introspective set of documentation for what you're doing, the rest of what you're describing as "boilerplate" provides other value as well. (The web framework I use, for example, uses your declared data types both as HTTP validation and to generate OpenAPI documentation for both humans and other computers. In a dynamically-typed language I'd still need to define these things as JSON Schema or the like--which is what happens under the hood here, it just actually provides for me dev-time and not just runtime benefits.)

Re:Ask HN: Who regrets choosing Elixir? by dnautics on Saturday May 23, 2020 @05:03PM (#23286422)
The sorts of errors I'm talking about that typing will never help you with are object ownership (in non-rust, non-gc languages), use-after-free (ok rust helps with that too), array bounds-checking, use of optionals, incorrectly labelling functions (fn add(a, b) = a - b), race conditions, non-pointer resource cleanup (e.g. file descriptors, connection objects), paralellism errors (noncommutativity of operations), mutex deadlocks.

Basically all of these things (or their rough equivalent) are easily testable in Elixir.

Your point is taken in the large (I wrote a zig NIF library that reads zig types and automatically generates the code that performs the data deserialization from erlang terms), but in the specific case you noted, if you're using type annotations to create your OpenAPI spec, you're doing it backwards. Best practice is to OpenAPI spec to generate endpoints that you code for. (I'm aware that phoenix-openapi does not do this correctly)

Also, I want to point out that I wrote a generalization, not an absolute statement about typing zealots. I think you're rare. I like types and even wrote an (unpublished) typing library for elixir (proof: https://github.com/ityonemo/typed_headers) that engaged during tests, with the intent to make it compile time checks. But almost every typing zealot I have worked with absolutely hated tests.

Re:Ask HN: Who regrets choosing Elixir? by eropple on Saturday May 23, 2020 @05:46PM (#23286789)
TypeScript, just as an example, does help with a lot of those, though. Object ownership is a lot less of a thing when you hand `DeepReadonly<T>` to things outside of your bounded context. Use of optional constructs is also de rigueur in TypeScript (whether or not you're using an option type or `undefined`/`null`) and the compiler will happily yell at you about it.

The rest--yeah sure, but you can write tests for those things in anything. What you must test is then only a subset of the things that yeah, you do really have to bust your ass to test in an Elixir or a Ruby or a Python, and then it really is boilerplate--just less useful boilerplate overall.

> Best practice is to OpenAPI spec to generate endpoints that you code for.

I disagree with that. Every project where I've ever done that has immediately shat down its leg when the spec of an endpoint changed because refactoring from external sources is bad even in languages where refactoring isn't a disaster from the word 'go'.

IMO, the code is the canonical source of functionality; the spec should reflect it. It's why my CI system for my current project builds new releases of libraries for major languages are pegged to the version of the OAS3 spec being emitted. If you want to go off-road and use a language I don't actively look at, you can still do that, and the semver of the spec (which remains a manual problem in either case, though you could probably get clever enough to make a good guess as to whether it should be major/minor/patch) will tell you as a consumer when you need to upgrade.

A semantically versioned spec is required whether or not you write the spec first or the application first

> But almost every typing zealot I have worked with absolutely hated tests.

Slices both ways pretty easy, tbh. Almost every dynamic-typing pusher I've worked with was an active danger to a project with more than one committer--the best and most effective developers on such projects have always been folks with the requisite fear and acknowledgement of their own fallibility and the absolute danger that comes with using dynamically-typed languages for anything you care about; the starry-eyed Ruby idealists (I had that phase too) are just going to be too clever by half and then you get to eat the resultant shit later.

Re:Ask HN: Who regrets choosing Elixir? by joelbluminator on Thursday May 28, 2020 @09:56AM (#23337255)
Not sure why you were downvoted, guess saying you think dynamic types are good is counts for a downvote these days. Oh well.
Re:Ask HN: Who regrets choosing Elixir? by dnautics on Saturday May 23, 2020 @12:50PM (#23284430)
> Any codebase beyond fairly small will be harder and harder to work with to an unreasonable degree, in my experience, and any perceived "velocity" gained from the dynamic nature of it is paid for doubly so by the lack of safety you get beyond toy projects.

How does pagerduty deal with it, I wonder.

Re:Ask HN: Who regrets choosing Elixir? by cplanas on Saturday May 23, 2020 @02:00PM (#23284978)
Or Shopify. Or Zendesk. Or GitHub.
Re:Ask HN: Who regrets choosing Elixir? by bitwize on Saturday May 23, 2020 @06:08PM (#23286988)
Unit tests. Lots and lots and lots and lots of unit tests.
Re:Ask HN: Who regrets choosing Elixir? by AlchemistCamp on Saturday May 23, 2020 @12:52PM (#23284449)
Or Discord.
Re:Ask HN: Who regrets choosing Elixir? by joelbluminator on Monday May 25, 2020 @11:34AM (#23302082)
Or Gitlab