I often see people say static typing slows them down and I'd really like to know why that is because for me it's the exact opposite, I really don't like not knowing what format data is in. I'd much rather have to write slightly more verbose code and have a vast number of possible errors caught at compile time instead of having things go wrong in production when someone inputs something a bit weird with nothing so much as an error.
mijamo|2 years ago
I tried at some point to use Rust for an API but then I depended on making calls to a very complex API. In JavaScript I would have just gotten back a complex object where I can then pick whatever I want progressively through object access methods. In Rust I ended up with more than 500 lines of type definition for the API and it still wasn't enough so I gave up. It is a bit extreme but when you work with an API from an ERP for instance you can get very very complex and extensive types that are not in your control and not very well specified.
Another good example is how complex all ORM internal code get once they try to add static typing. The typing in the ORMs code feels like black magic because they would really really need types as code but don't have it so have to rely on a bunch of crazy generic combinators.
knallfrosch|2 years ago
If you don't know what kind of data people give your function and you don't know what's supposed to happen, how can you write that function? I think many people use too strict of a type system. If your function works with any object that has a toString()->string function, then just write an in-line interface that defines it.
I actually love TypeScript here. It allows for `any` if you're prototyping, lazy or simply don't care. It allows mapped types, where the next dev can see how a type came into being - for example, Mutable<T>, Readonly<T>, Required<T>, Partial<T>. The names actually speak for themselves! And it eliminates the Java-style verbosity of creating classes and files all just for a type.
mdx97|2 years ago
You can always deserialize things as `serde_json::Value` instead of making types for everything to get similar behavior out of Rust.
rTX5CMRXIfFG|2 years ago
So then there’s more code for the language devs to write of course, but that’s just the cost of safety, which is highly desirable if you want the technology that you are building to be attractive for use in systems where correctness is critical, which also tend to be highly valuable. As a working professional it’s in my best economic interests to have such valuable tools in my skillset.
olivermuty|2 years ago
Couldn’t that thing be typed as the web format? A nested set of string props with either string or number types in the leaves.
Then use those types to traverse and pull into «real» types?
I like to put structured data into structs in elixir too and the above is essentially what I would do in Elixir.
I don’t know rust well enough to see if I am missing some nuance
wofo|2 years ago
toolz|2 years ago
In my experience, static typing seemed to lend itself to poor testing, maybe some sort of belief that static types were good enough to not need tests that can prevent regressions. So from my point of view the static typing is negative value. It prevents such a low value class of bugs while seemingly incentivizing people to be lax with the most important classes of bugs.
solidninja|2 years ago
d3ckard|2 years ago
On the other hand, sometimes I feel like it has a lot to do with test writing. I feel people enjoy static typing, because you can get a feedback loop catching certain things without writing any tests. If you do write tests, all the type errors get caught pretty immediately anyway, so I just don't see the benefit.
Personally, the biggest advantage of dynamic typing for me is the ability to skip formalities for a time. If I want a function that can modify any struct with field "val" in (by, let's say, setting it to zero), I can - and I don't have to do multiple definitions, I don't have to define an interface. Just a function and I am done. If I want to skip error handling for now and only code the happy path, I can - and my program will work (and crash on error, but in some cases it's ok).
As the projects get more complex and require higher safety guarantees, static typing helps in ensuring nothing got broken - but nothing beats dynamic typing for prototyping.
josephg|2 years ago
I’m spitballing on the reason - I don’t know why it’s like this. But maybe it’s because static typing encourages you to write & plan your types first. When you know the data types, all the functions kind of flow around your types and everything feels like it obviously flows from that. With dynamic typing, it’s the reverse. I find myself writing my functions first (top down or bottom up) and then backfilling what arguments and data everything needs to pass around. I run my code a lot more as I develop it to stop bugs creeping in. And because I can run my code at any time. There’s no type checker stopping me from trying things out.
spion|2 years ago
Lots of statically typed languages are very strict about their types and have too many of them. You have to admit, when you're trying to build something difficult and focus on getting the business logic part of your program right, the last thing you want to be thinking about is e.g. whether you need a String, ByteString, LazyByteString or any of the other types of strings, and which library decided to accept which one. At some level its definitely useful to distinguish between those, and I'm sure a lot of libraries make sensible choices. But initially in the development of the program its just unnecessary busywork that distracts you from the important bits.
In the past, typed languages also made it a bit harder than necessary to create new types, especially in situations where you have serialization and deserialization. And finally, we had to do all this work, and for what? To be unable to prevent the most basic of errors i.e. NullPointerException? You have to admit, it was a hard sell.
A lot of things have changed, however. TypeScript makes it really easy to define types, anywhere - inline on the function in the argument, or right above it. You can pretend the type is correct at deserialization time, or you can use libraries like `zod` to both define a validator and a type in the same syntax - its up to you. Rust similarly has powerful and easy to use tools like serde - structs and enums are easy to define, and easy to attach metadata to them quickly to (de)serialize them accurately. Huge differences from the old world of getters and setters and NPEs.
When using dynamic languages, there are techniques to make things easier. There is the often mentioned testing, which does help verify a large subset of code paths. Lesser known and more subtle technique is coming up with and following a strict naming convention for properties, for example, and to keep things as consistent as you can in general. This is why you often see so much focus in code reviews about conventions, linting and so on.
Nowadays I guess it mostly depends on how good your dynamic language techniques (at the team level) are, as well as what your treshold for type system annoyances is. There are still some annoyances even in the best type systems, but its gotten way, way better.
aerhardt|2 years ago
ra|2 years ago
I've wondered if that's a thing. It seems to be.
swader999|2 years ago
camgunz|2 years ago
rishav_sharan|2 years ago
I would definitely use type safety if I had a lot of external data sources. or if there are lots of people working with me. Otherwise, I am beginning to go back to dynamic languages at least for web dev.
hosh|2 years ago
Typescript does not solve the fundamental problems of JS. I'm not convinced it really solved the issues related to ingesting data from many different data sources. The data quality issues were still there.
If I were rewriting the whole thing, I'd rewrite it with Elixir (of course), if only to have a sane way of handling errors.
MrJohz|2 years ago
For me, Typescript is more useful, the more of the codebase I "own", because it means I can be more confident that all the types reflect the true types of the runtime data, which means I can change things more confidently and quickly. Do you find that you're refactoring and changing things less with dynamic languages? For me, I think that's the number one magic feature that I miss when I use languages without explicit type systems.
sensanaty|2 years ago
I jumped into some code I haven't touched in half a year the other day so had 0 recollection of any of it, thankfully cause of the types I knew exactly what to pass where and what to expect back without even having to read any of the code other than the type definitions.
I love me some dynamic languages, but damn if it isn't nice to have that kinda power available to you.
Kiro|2 years ago
mstipetic|2 years ago
lucasyvas|2 years ago
The author's joy will also be short-lived because static typing is coming and will likely win out if the implementation is solid.
sph|2 years ago
I'll say types are cool again before I get routed by angry static typing zealots.
prophesi|2 years ago
keep_reading|2 years ago
https://github.com/Qqwy/elixir-type_check
pleoxy|2 years ago
These two patterns allow you to write most code, type free, that gracefully handles anything you throw at it while always doing the right thing.
Making changes to such a system is easy and friction free.
Not many type advocates speak of the downsides of type systems, always pitching the net win and ignoring the actual cons.
When you refactor, make a change, or try to add new functionality, and end up fighting the type checker. That's friction to change you are experiencing and that experience is optional.
I get that having discipline in code patterns and the required robustness is a difficult ask at some organizations and some devs. In that circumstance it's better to have a minder in a type system that enforces base the conventions for everyone.
lolinder|2 years ago
I don't really see that as "fighting the type checker", I see it as the type checker doing its job and warning me of the places where my refactor broke things. The alternative isn't usually that my refactored code magically works, it's that I have to manually grep through the codebase looking for all the places where I might have broken something, and get runtime errors if I don't catch them all.
In that sense the experience of struggling to make a refactor work isn't optional—the choice you get is whether you want the compiler to assist you with it or not.
I realize there are exceptions for certain types of refactors to certain types of functions, but the vast majority of patterns I've ever seen in any codebase—static or dynamic—are patterns that are difficult to refactor without a type checker and trivial to do with one.
To be clear, there are other reasons to prefer dynamic typing, and I'm not trying to say you're wrong to prefer it, but you're not going to get very far trying to persuade a static types fan that refactoring of all things is better in the dynamic world.
Munksgaard|2 years ago
I'm not sure exactly what you're saying. If your language is strongly typed, you'll get type errors no matter what. The only difference is whether the type errors happen at compile time or run time. Let's take a hypothetical example:
Let's say I have a programming language called Foo. There are two ways to run programs written in Foo, using the interpreters A and B. A and B are identical, except for that fact that on startup, A will check that the given program is well-typed (static type checking), while B defers such checks to runtime (dynamic type checking).
Given a well-typed program X, I can run X with A or B without ever encountering a type error. Now, I make some changes, like you suggest, and I attempt to run it again. If the resulting code is not well-typed, I will immediately know when trying to run it with A, but with B I have to be lucky enough to hit the specific case that isn't well-typed.
If I understand you correctly, you're saying that you can easily make changes in a dynamic language without _ever_ causing run-time type errors. If that's the case, you would have _exactly_ the same experience whether you ran your code using A or B.
cglan|2 years ago
That’s the same argument people always use. “If you account for every case and also have 30 billion unit tests you can avoid all the problems”. The reality is, people don’t. They cut corners, they forget, or they simply make mistakes.
Not only that, debugging a system without types is a terrible experience, and IDEs don’t offer nearly the same level of refactoring support for untyped languages bc it gets very hard or impossible to infer what’s going on.
If it’s a personal project or a small script, untyped languages are fine. Any other scenario you should be using types
passion__desire|2 years ago
jb1991|2 years ago
whalesalad|2 years ago
the creator of the language has a fantastic talk on this https://youtu.be/giYbq4HmfGA?si=LgSHZupSuR-kMXmj
magicalhippo|2 years ago
I can easily see what is passes or returned, and if I'm unsure about the details of the type the answer is a click away, or a short web search away at worst.
Significantly reduces my mental load, allowing me to be vastly more productive.
Dowwie|2 years ago
The cost of this mild inconvenience is still far less than the cost of satisfying types.
This aside, I want typed elixir.
bradrn|2 years ago
It’s happening: https://elixir-lang.org/blog/2023/06/22/type-system-updates-...
epiccoleman|2 years ago
One of the best features of type systems is they make editor completions and navigation work better. Elixir's LS is pretty good, but editor support just isn't nearly as good as what you can have in a good (read: Jetbrains) IDE with a strongly typed lang like C# or Java.
realusername|2 years ago
They are working on typing it now from the blog posts I've seen and they will probably be successful because the language is well suited for that in my opinion
peoplefromibiza|2 years ago
Which is orthogonal to what the type is
The shape of the data is much simpler to handle in Elixir than in, to name one, Java.
> a vast number of possible errors caught at compile time
if it's a vast number, usually it's because either:
- you're not familiar with the code base (and you'll make a vast number of other kinds of errors)
- you're making a huge refactory and you're used to rely on a compile-driven workflow, but there are so many alternative ways to handle them
> things go wrong in production
the usual wisdom applies here: static typing does not replace input validation, be it user provided data or function parameters
solidninja|2 years ago
csan_gonzo|2 years ago
jwells89|2 years ago
Having grown accustomed to static typing, not encountering errors until runtime, or worse having errors manifest as type-related misbehavior and potentially not be immediately apparent is much more frustrating than it used to be.
gampleman|2 years ago
Then you of course have global inference, where you can write code as tersely as in a dynamic language, but still benefit from type checking and add annotations later as a form of documentation for readers.
It also changes the way you code. The best experiences from static typing come IMO from doing type-driven development, where you sketch out your problem first at the type level, then fill out the implementation at the value level. In dynamic languages, you can't program like that. So if you use the same mindset you will find the language limiting.
dartos|2 years ago
Weak typing is what causes all sorts of issues.
With dynamic strong types, you can still have a tool like dialyzer figure out potential type issues before shipping, but weak typing means anything goes.
threatofrain|2 years ago
I've seen a lot of authors do crazy type things to get around the type system (like typing out recursion to the n-th level by hand), and I think many open source projects are slowed down by the lack of a type wizard on their team.
curtisblaine|2 years ago
liampulles|2 years ago
But part of doing the correct version is clarifying spec, and prototyping can help with that - so it is a weakly held opinion.
mrcwinn|2 years ago
And nothing slows a developer down more than accruing technical debt as they build. It's like having tar stuck to your shoes. You will work the fastest when you have nothing to pay back because your mental model of the application is aligned with the intention of your program.
(That said, I don't think you necessarily need a strong static type system to achieve these aims.)
andrewstuart|2 years ago
hahn-kev|2 years ago
jacquesm|2 years ago
But once that honeymoon phase is over you usually realize that types and tests were invented for a reason and beyond a certain level of complexity they are absolute must-haves if you want to have high confidence it all works as advertised and to be able to effectively refactor your code.
weatherlight|2 years ago
artdigital|2 years ago
No matter how much pattern matching you do, and how many typespecs you add to get a better understanding of what's behind a variable, you'll still run into issues at runtime frequently that could have been avoided if it was statically typed.
Dialyzer is great but typespecs and pattern matching only get you so far. You'll always run into situations where the shape of data is not clear, and you have to open a REPL to do an IO.inspect somewhere
ryanjshaw|2 years ago
I can't imagine building something like this in a dynamically typed language. The way I see it, static typing is like writing inline unit tests to save yourself many, many headaches later.
jddj|2 years ago
unknown|2 years ago
[deleted]
mib32|2 years ago
unknown|2 years ago
[deleted]