The common argument is that it becomes hard to maintain giant dynamically typed applications with millions of lines of code. However, I find that there is very little value to building monolithic software in the first place. Breaking things up into independent components facilitates code reuse and makes it easier to reason about what each component is doing.
This is true, but strictly typing things is useful not just internally in your code, but even for talking to outside services. For example all of the objects lemmy receives from the back-end, are strictly typed in the front end… not only does this just list them so you can see what you’re getting, but you also gain intellisense and auto-complete and all that too.
Your functional components I imagine also still need a structure to the data they’re receiving (is this a bunch of dogs, or car doors), to be able to work with it. Strict types give you compile-time errors when its the wrong function argument.
I can’t tell you how many times I’ve been saved by accidentally forgetting a field that was marked as required, at compile time.
I’m sure repl driven development can help, but its also nice to be able to have my typescript compiler list every error / warning in the project, in an easy to view list, and see code errors / warnings in place.
I use Reitit for routing on server side, and it leverages spec to generate APIs, do validation, coercion, and even produces a Swagger test page for the API. Here’s an example of how that looks:
The completion will of course be better with static typing, but you can get surprising amount with a dynamic language as well via static analysis. At the same time, completion isn’t really as much of a problem in a functional language because you’re just using the same set of common functions to transform any kind of data. With OO, each class creates its own ad hoc API in form of its methods. And this makes completion really important since knowing how one class behaves tells you nothing about the next.
Your functional components I imagine also still need a structure to the data they’re receiving (is this a bunch of dogs, or car doors), to be able to work with it. Strict types give you compile-time errors when its the wrong function argument.
I find that the code that cares about concrete types tends to live at the edges, while a lot of the code in the application is just routing the data where it needs to go. For example, if I pull some records from the db, the code that sends those records to the client doesn’t care about the content of the payload. It only becomes meaningful when I go to render it in the UI. Unfortunately, static typing can easily introduce unnecessary coupling where the code that shouldn’t care about the types ends up being tied to the specific types it operates on. An analogy here would be having delivery trucks that you can only put specific types of packages into. The truck shouldn’t care about the content of the package it’s delivering.
With runtime contracts I can decide where the type checks will provide the most value and add them there. Most of the projects I end up working on the specs end up being applied around the API level, and act as a specification for what the component is doing. If the specs pass at the API level, then the code behind the API necessarily has to be doing what’s intended as well.
And you can use spec driven development along side the REPL driven workflow as seen here, so that works quite similarly to type driven development except that you get live feedback as you’re working. The key advantage is that you can build up the state of the application as you’re working on it incrementally without having to restart it to see changes.
I find the problem is that most people just haven’t used a decent dynamic language with good tooling around it. Pretty much everybody has experience with languages like Js or Python, and I would much rather use a statically typed language than either of those as well.
I’d argue that the overall language design plays a far bigger role than the type discipline, and it’s misguided to treat it as the defining feature of a language. In practice, there are great languages using both static and dynamic disciplines and vice versa.
Also there’s no reason whatsoever why a dynamically typed language cannot be strongly typed
but you also gain intellisense and auto-complete and all that too.
I don’t believe this has anything to do with types at all
I can’t tell you how many times I’ve been saved by accidentally forgetting a field that was marked as required, at compile time.
There’s no reason why an implementation of a dynamically typed language cannot check for things like this either, this is just a common misconception brought about by the way some interpreters work.
This is true, but strictly typing things is useful not just internally in your code, but even for talking to outside services. For example all of the objects lemmy receives from the back-end, are strictly typed in the front end… not only does this just list them so you can see what you’re getting, but you also gain intellisense and auto-complete and all that too.
Your functional components I imagine also still need a structure to the data they’re receiving (is this a bunch of dogs, or car doors), to be able to work with it. Strict types give you compile-time errors when its the wrong function argument.
I can’t tell you how many times I’ve been saved by accidentally forgetting a field that was marked as required, at compile time.
I’m sure repl driven development can help, but its also nice to be able to have my typescript compiler list every error / warning in the project, in an easy to view list, and see code errors / warnings in place.
I use Reitit for routing on server side, and it leverages spec to generate APIs, do validation, coercion, and even produces a Swagger test page for the API. Here’s an example of how that looks:
["/plus" {:get {:summary "plus with spec query parameters" :parameters {:query {:x int? :y int?}} :responses {200 {:body {:total int?}}} :handler (fn [{{{:keys [x y]} :query} :parameters}] {:status 200 :body {:total (+ x y)}})}}]
The completion will of course be better with static typing, but you can get surprising amount with a dynamic language as well via static analysis. At the same time, completion isn’t really as much of a problem in a functional language because you’re just using the same set of common functions to transform any kind of data. With OO, each class creates its own ad hoc API in form of its methods. And this makes completion really important since knowing how one class behaves tells you nothing about the next.
I find that the code that cares about concrete types tends to live at the edges, while a lot of the code in the application is just routing the data where it needs to go. For example, if I pull some records from the db, the code that sends those records to the client doesn’t care about the content of the payload. It only becomes meaningful when I go to render it in the UI. Unfortunately, static typing can easily introduce unnecessary coupling where the code that shouldn’t care about the types ends up being tied to the specific types it operates on. An analogy here would be having delivery trucks that you can only put specific types of packages into. The truck shouldn’t care about the content of the package it’s delivering.
With runtime contracts I can decide where the type checks will provide the most value and add them there. Most of the projects I end up working on the specs end up being applied around the API level, and act as a specification for what the component is doing. If the specs pass at the API level, then the code behind the API necessarily has to be doing what’s intended as well.
And you can use spec driven development along side the REPL driven workflow as seen here, so that works quite similarly to type driven development except that you get live feedback as you’re working. The key advantage is that you can build up the state of the application as you’re working on it incrementally without having to restart it to see changes.
I find the problem is that most people just haven’t used a decent dynamic language with good tooling around it. Pretty much everybody has experience with languages like Js or Python, and I would much rather use a statically typed language than either of those as well.
I’d argue that the overall language design plays a far bigger role than the type discipline, and it’s misguided to treat it as the defining feature of a language. In practice, there are great languages using both static and dynamic disciplines and vice versa.
what is a strict type?
Also there’s no reason whatsoever why a dynamically typed language cannot be strongly typed
I don’t believe this has anything to do with types at all
There’s no reason why an implementation of a dynamically typed language cannot check for things like this either, this is just a common misconception brought about by the way some interpreters work.