Hacker News new | past | comments | ask | show | jobs | submit login
Why I Prefer Dynamic Typing Over Static Typing (2017) (smashcompany.com)
29 points by porjo 64 days ago | hide | past | web | favorite | 106 comments



> For the programming that I do, I am often creating new architectures. Therefore I need dynamic typing.

He seems to consider static typing equivalent to "locking down" an architecture, that when you use static typing you're locked in to a certain way of doing it, and you're stuck with it. In my experience of working with large codebases with both dynamically and statically typed languages, the opposite is true.

Static typing frees you up to make changes to interfaces in a way that dynamic typing does not. For instance, if i want to add or remove a parameter to a function in a statically typed language, it's trivial. I just do it, and the compiler goes "ok, this function is called from these 4 places, so just fix those" and you now are assured that everything will work.

That doesn't work in dynamically typed languages. There's no reliable way to change an interface and be confident that you haven't broken anything (+/- extremely good linters, but those aren't perfect in the way a compiler is). This leads to a "never change this function, you can break all sorts of things" attitude that simply doesn't exist with static typing, where the compiler can just tell you what you need to fix.

There are perfectly valid arguments in favor of dynamic typing (it's arguably easier, often faster to work with etc.) but this particular one is extremely silly. The exact opposite is true.


Good test coverage and test-first philosophy can make this problem go away, but it always requires that you didn’t make an error in your tests. I always found this argument bizarre: I write tons of tests but I know that I’m fallible, and writing such tests is time-consuming. Why not let a static type checker do the work for me, with less chance of error?


That's another reason I like (good) static types, it's a bunch of compiler-included documentation and testing that I don't need to write!


Also a good reason for defining and using the most specific subtypes possible. In some domains, "this arg is a string" is useless for validation or documentation because everything is a string. Is it really a URL? a UUID? a serialized timestamp? a property name?


That's called something being stringly typed, and it's a code smell. You make URL classes, UUID classes, timestamp classes, enums, etc to replace the strings.


Elixir's pattern matching seems to handle this case quite well, despite having dynamic typing. This approach feels like the best of both worlds to me.


Keep in mind that pattern matching can be dangerous. Change something and suddenly your code could be flowing in new unexpected ways without notifying you with a runtime error. I like pattern matching too but it has bitten me


Sure, but that's the same issue you have in a dynamic language anytime you use an if statement, or a switch statement.


> [change is] trivial. I just do it, and the compiler goes

You are talking about the ability to refactor. In my experience with major refactors, you need a test suite, not the type checker. Why so specific? Very simple, when I did this in the past, the compiler tended to be happy way, waaaaayyyy before the test suite. Had I relied on just the compiler, I would have been in a very bad place.

> "locking down" an architecture

Simple refactors are not "changing the architecture". Static type systems tend to be fairly specific about the kinds of architectures that are expressible, and they tend to be "you can have any architecture you like, as long is it's black, er, call-and-return". Now we tend not to notice this, because we are so used to everything being call-and-return that we don't even notice it.

"We Don’t Know Who Discovered Water, But We Know It Wasn’t a Fish" -- Marshall McLuhan

Once you do notice, and you do want to build alternative architectures, the straight-jacked becomes very constricting.


> Static typing does not live up to its promises. If it did live up to its promises, we would all use it, and the fact that we don’t all use it suggests how often it fails.

https://en.wikipedia.org/wiki/Argumentum_ad_populum


What a bizarre argument. You could replace "static" with "dynamic" and you would have an equivalent argument that would just as strongly (i.e., in fact, weakly) argue against dynamic typing. This logical hole is obvious enough to drive a bus through. I don't understand how the author wouldn't have noticed it.


The logical hole is not obvious. If it were obvious, we would all notice it, and the fact that the author didn't notice it suggests it's not obvious.


I guess this is what happens when everyone gets a trophy.


There's a joke about not checking his types in here somewhere.


The whole article is full of those. The best part is that the author tried calling out other fallacies in the article.


PHP, Python, and Perl are commonly used. It does take more discipline to avoid the downsides of dynamic. Static languages better protect you from Monday morning fopas, but one can develop faster and farther in dynamic when firing on all cylinders.


> Monday morning fopas

One benefit of static typing is that it's like a spell checker. It can't catch all errors but there's a whole class of errors it prevents you from making.


Using that analogy, it could also be compared to a forced spell-checker such that you cannot submit your document at all unless every word passes the spell-check. Some words are not in the dictionary; you may need invented or new words at times.

I always wanted something that's in-between both: an "analyzer" that warns you of oddities, but doesn't prevent running the program. You could put indicators to stop notices about things you know will be otherwise flagged.


> Some words are not in the dictionary

Indeed. Like fopas.


Depends how you define "dictionary". See below.


> fopas

Did you mean "faux pas", or it is something I didn't know?


I always thought "faux pas" was the "old school" way of spelling it, similar to "neighbour" versus "neighbor". Spell-checkers usually accept "fopas". Hmmm, interesting linguistic mystery.


"Neighbour" vs "neighbor" is not "old school". One is the correct way to spell it in British English, the other is the correct way to spell it in American English. "Faux pas" comes from French and so is spelled the way it is spelled in French. There's no linguistic mystery, "fopas" is just not a word.


Tell that to spell-checker companies, or at least the Google Chrome team. And UK English is considered "old school" by some, similar to the "old world" versus "new world" labels. But arguing over words and words about words is probably off topic.


Written on chalk board:

I will not participate in Hacker News Static vs Dynamic typing debates.

I will not participate in Hacker News Static vs Dynamic typing debates.

I will not participate in Hacker News Static vs Dynamic typing debates.

I will not participate in Hacker News Static vs Dynamic typing debates.

I will not participate in Hacker News Static vs Dynamic typing debates.

Stay strong, Me


The problem with the debate is that it's all based on personal preference and anecdotes, all of which are subject to cognitive biases. What we really need is a proper study, but they are notoriously hard.

The debate fundamentally comes down to 'under what circumstances is the extra cost of working with a static type system worth it for the benefits'.

For a 15 line helper script of the sort I've just written, Python with its dynamic typing is (to me - a proponent of static typing) the fastest thing to work with due to the low overhead. To me there is a threshold of project complexity where the cost-benefit ratio flips. Is that actually true? Does that vary for all people?


> What we really need is a proper study, but they are notoriously hard.

Here you go: "A large-scale study of programming languages and code quality in GitHub"[0]. I've only read the abstract (are we OK on sharing sci-hub links? [1]), spoiler alert, according to this research some languages are more defect prone than others but the effect is small.

[0] https://cacm.acm.org/magazines/2017/10/221326-a-large-scale-...

[1] sci-hub.se/10.1145/3126905


I'm aware of this study, and a couple of others. They are all only looking at one area of productivity though, because that's the available data. In this particular case, there's no indication of development time required to achieve that level of bugginess. Maybe in practice all projects do enough work to reach an average level of reliability, but then what's interesting is how much developer time is required to get there.

It's a total cost analysis that's interesting - and there's a lot of costs. Cost of development, how that varies depending on required time to market, cost of bugs (fixing them, and loss of sales due to customer reliability concerns), cost of complexity as software has to be maintained over time.


> but then what's interesting is how much developer time is required to get there.

Yeah, good point. I read an old research where they tried to test the "productivity" offered by different languages, but then it became difficult to asses the experience of the different developers...


I actually don't think a study is needed, because it's not a one-size fits all debate, I think which you agree with, too. I could argue either side for different teams, companies, velocity, goals. Just like your example, I'm a believer in dynamic for quick tooling, smaller teams, earlier product life cycle, etc. And static for larger products, with dynamic team composition, and longer life cycles, etc...


This is actually pretty key - we're all familiar with the debate. It's like walking into a church and saying god doesn't exist. Or if you prefer, walking into an athiest's home and saying he does. ;)

Besides, this thread still has only 65 comments and it will likely have thousands before the day is out:

https://news.ycombinator.com/item?id=19190349


On a serious note, the arguments made in the opening paragraph seem like pretty broad reaches on why corporate america does or doesn't use static typing. I'm pretty sure regulatory has nothing to do with it. I work in an environment of high compliance, though we use a lot of Java, we also use Python, Ruby, .NET, NodeJS, etc...


Alas, developers, not corporate america, decide which languages are used. If stakeholders had any idea it mattered, the landscape may have looked very different.


This is one of the technical topics I've organized into a group I call "Topics that have launched a thousand flame wars."

That being said, every now and then I find them a good refresher in software politics, with a side of insight.


I do think it's a good topic for engineers to discuss, though, because you can tell a lot about various peoples backgrounds, etc. on how dogmatic they are one way or the other, or even if they have more pragmatic attitudes on the topic.


I suspect (but cannot prove) that some peoples' brains are wired such that static types fit them better, and other peoples' brains are wired such that dynamic types fit them better.

I suspect the same about procedural vs. functional programming.

And I suspect that's why discussions about them wind up the way they do. It's just obvious which one is better - to you. It's so obvious that it doesn't even seem to need proof. And therefore it seems that everyone who sees it differently must be ignorant, an idiot, or a troll.

Or so I suspect.


i started to add my thoughts elsewhere in the thread, wasn't quite sure how to word it and then thought of your comment, deciding you are right and dropping the matter...


> In a dynamic language I could simply work with a deeply nested data structure of maps and lists, and I’d handle the casting at the very end of the process. In a dynamic language, I could treat everything as a string till the very end, and then cast to integers or dates or floats or strings as needed. In a dynamic language, I could write the code faster, with less errors, and with less code.

Nothing described is impossible, or even hard, for a statically typed language to do.

Perhaps I misunderstand them, but author seems to be under the impression that static typing doesn't allow for type conversions.

> In static-type languages such as Java, I’m forced to go with either #1 or #2, and they are both bad options.

That's simply not true.


I have experienced the same pain as the author many times, and, though I mostly work with Java by day these days, when possible I would much more happily reach for Python when I'm needing to hack on a REST API.

But I don't think this particular issue has much, if anything, to do with dynamic vs. static typing. It's mostly about how clean and elegant Python's way of handling JSON is compared to the black hole of viral enterprise-y overdesign that is Jackson, Java's de facto standard library for dealing with JSON.

With Python, JSON is deserialized to, in essence, a dictionary that maps keys to values, where the values are either strings, arrays of values, or dictionaries.

With Jackson, it's exactly as awful as TFA describes.

But I can easily imagine a Java library where JSON deserializes to some "JSONEntity" type that can act as either a string, a list of entities, or a string->entity map. And then I could interact with that in the same loose, don't-force-me-to-worry-about-details-I-don't-currently-care-about way that I do in Python. Perhaps one even already exists. It doesn't seem a far-fetched dream - I've used similar libraries for other static languages.

TBH, I haven't looked, because, even if I found one, I'd still be compelled to use Jackson, anyway. Because Jackson has been around forever, and Jackson is now so deeply entrenched that nobody working in the Javaverse can even fathom life without it. Suggesting such a thing would be heretical.


Jackson supports a workflow like you describe.

https://fasterxml.github.io/jackson-databind/javadoc/2.2.0/c... and related classes/functions.


"Static typing tends to be used in areas where legal regulations create needs that outweigh programmer productivity."

This is rather a broad generalization that doesn't seem accurate to me. It's at least misleadingly phrased if it's not intended to imply that this is the main reason or primary domain where static typing is used. Performance is a major reason static typing is preferred in many domains like games development for example where legal regulations are largely irrelevant.


I mostly use static typing because I don't want the intended behavior of the program to be described solely in my head.


That may be asking too much of a programming language not intended for AI.

What I see between each approach is tradeoffs. Which one has the net benefit may ultimately depend on personality, domain, and shop practices. It's one of those architectural holy wars that may never end.


I do the vast majority of my programming in Rust and Python. I love both of those languages, but the fact is, the problem that static typing causes me in Rust is that I have to write a lot more code, but it is all pretty much rote. The problems that dynamic typing causes me in Python is that I have to evaluate large chunks of the program to figure out what it means. These are totally different kinds of frustration, but I can put up with the rote stuff because it doesn't distract me from thinking, but having to question what the code I'm looking at can do requires much more creative thinking and detective work that leaves me less able to passively think about anything else.

They're both manageable, really.


"Which one has the net benefit may ultimately depend on personality, domain, and shop practices."

I think personality is often the biggest issue. Some people like dynamic, some like static. You can make some rational arguments for your preference but in the end we know that successful projects have been written with either paradigm.


Very well said!


Static typing is fantastic in a closed system. It's predictable and reliable.

My problem is nearly every type system breaks down when you try communicate with something outside of the closed system (e.g. API calls, 3rd party integration, etc).

An API returns an unexpected data type, Missing a field that's supposed to be required, Starts returning a number as a string because they changed their ID system, etc.

It always seems to end up in types where every field is optional - defeating the purpose of having types in the first place.


The problem here is not static typing or its interface to the outside world. The problem is most mainstream static typed languages have shit handling for Sum Types. With proper support and proper syntax static typing would actually help you ensure you handle both possibilities of your "option" type. (Any language which defaults to any reference type may be null, at any time, is the opposite of properly handling option types.)

Let me turn this around: if you're saying possibly-missing fields inevitably propagate throughout the types in your codebase, it sounds like you're saying malformed input propagates arbitrarily deeply into your core logic. Wouldn't you rather catch that at the boundary?


> if you're saying possibly-missing fields inevitably propagate throughout the types in your codebase, it sounds like you're saying malformed input propagates arbitrarily deeply into your core logic. Wouldn't you rather catch that at the boundary?

Possibly. If it's a key part of the application, like Credit Card processing or auth - absolutely. If it's simply auxiliary or supplemental information - probably not. The thing for me is the type system shouldn't decide whether or not a certain piece of information is critical to the system. That typically falls to deeper logic in the system. If the type system isn't deciding, then it's pretty much meaningless (as everything would be optional).

For example, I'm using a Stripe JS integration to allow customers to manage credit cards in app. Stripe messes up or changes something without me paying attention. Instead of returning a complete object, Stripe starts returning only the credit card ID.

This isn't a big deal if we simply need to know that a record exists. We can still tell the user has a card and we have an ID to attempt a transaction against server side. We might not be able to display details about the card, but users could still submit a transaction (likely against their last used card).

However, it is a big deal in a credit card management interface. Without supplementary data, all of the cards would look exactly the same and the UI might break if expected fields aren't present.

----

I don't want my type system deciding what the use case is or how important one case is compared to the other. The actual implementation needs to decide if it has the information it needs to do its job.


> The thing for me is the type system shouldn't decide whether or not a certain piece of information is critical to the system.

No, that is in fact the stated purpose of the type system. If you don’t want to make such a decision statically, you mark a field appropriately (e.g. via an Option type).


I understand that's the stated purpose. I'm demonstrating how I feel types can pretty much become useless when integrating with an outside system.

If everything is optional, then you might as well not use a type system in the first place.


Again, there’s virtually never a reason to make everything optional/variant. It’s a conscious design choice and should be used judiciously (otherwise the API becomes difficult to use, and the same is true in a purely dynamic system).


    data Stripe1_0 = {
      field1: type1
      field2: type2
    }

    data Stripe2_0 = {
      cc_id: str
    }

    data Stripe = Stripe1_0 | Stripe2_0


Static type systems are just a tool. The type signature describes what _your_ module is capable of handling. If other modules pass incorrect data, your module will fail, whether statically or dynamically typed, albeit harder to debug in the dynamically typed case. If every field ends up being truly optional, it's going to be hard to change your module, because of the sheer weight of the combinatorial explosion of field subsets that may or maynot be set when third party modules interact with your module.

Most of the time optional fields:

* Encode that your module doesn't care about such-and-such fields, so the parser / type checker should just ignore them.

* Are used to encode variants of the same data that slightly changed in another module [id changed from number to string], so you should use an union type.

In practice, designing a statically typed ecosystem for wire data is hard [0]. Grpc has basically gave up on validating field presence altogether [1]. These failures are directly caused by the immaturity of the ecosystem [deep decode batches of unrelated messages in middleware, WTF?]. It would be a mistake to throw the baby with the bathwater and blame the mathematically sound idea that your module can only process data of a certain shape, encoded by a suitable type signature.

[0] https://capnproto.org/faq.html#how-do-i-make-a-field-require...

[1] https://github.com/protocolbuffers/protobuf/issues/2497#issu...


I agree with you that static typing can create more work on the boundries of a system.

However, the problems you describe also happen in dynamic languages and they have just as much potential to cause problems. The biggest issue with dynamic languages is that you don't get immediate errors when something changes. The system will just keep doing its thing, until it doesn't and you discover that something has changed and has already been propagated to other parts of the system.

I don't think dynamic languages are always better in these cases. They basically let you defer the error/change handling, but with the potential of much bigger data integrity/quality problems when things eventualy do go wrong because of changes in an integration.


The API problems you cite aren’t prevented in dynamically typed systems. If anything they are worse, because they could lead to silent failures, whereas a statically typed API statically checks and guarantees the contract. Contrary to what you imply, a statically typed API can’t return an unexpected type. That’s an advantage.

> It always seems to end up in types where every field is optional

“Always”? Not by a long shot. These situations where this is the case can be isolated and dealt with explicitly. You may object to the explicitness but — again, for reasons of robustness — proponents of static typing prefer this.


> whereas a statically typed API statically checks and guarantees the contract

I didn't work much with static typed languages lately, so I'm really puzzled by your comment. If I expect an int in the age field of a JSON response and the server suddenly sends me a string, maybe with value "NaN", how do you check for that at compile time? I expect the program to either crash or manage the error at run time (try/catch, die-and-restart a-la-Erlang, etc)

Maybe JSON doesn't count as "statically typed API", but how many of them do common Internet services expose to the public? And how to we make sure that the server or any in between proxy doesn't misbehave and violates the contract?


There are different kinds of APIs. You seem to be talking about inherently dynamic ones, such as your JSON blob example. Of course you cannot statically guarantee their contents, which is why statically typed JSON layers provide ways of asserting a schema. Using such schema checkers is best practice even in dynamically typed languages.

Either way, you need to handle such failures, both in statically and in dynamically type-checked languages. The only difference is whether the handling happens explicitly throughout your code or automagically by an API that gives you back a well-behaved object. And both of these ways are possible in both static and dynamic languages (but static languages tend to go for the latter, whereas dynamic languages tend to make you do the former).


The way this works is, when you say “please turn this JSON string into a data structure”, it’s a fallible operation. So, if that JSON string does not have what you expect, the serialization operation will fail. You can “check at compile time” by the system ensuring that you handle the success and failure cases. Additionally, it means that if you have an instance of that data structure, it is always valid; it is checked (at runtime) upon creation.

Does that make sense? I can show you some code if you’d like.


There's nothing stopping a dynamically typed system from using something like grpc or graphql that can check for missing fields. Or something like json schema to check for missing fields in a lot of those scenarios. A type system doesn't necessarily catch missing fields, but a communication framework of some kind, does.


I entirely agree, see my orthogonal comment reply.


Option types do not defy the purpose of typing. Optionality as a type constraint is a reason for static typing.


This is likely going to lead to an error in both statically and dynamically typed languages.

In statically typed language, at least when troubleshooting it's an easy guess that the error is highly likely to be at the external boundary of your application code since the rest of it type checked.


If the API you rely on breaks, you have to change your code. This is exactly how catastrophes happen.

It's more of an issue that you have unreliable 3rd party vendors that you buy from/use.


> It's more of an issue that you have unreliable 3rd party vendors that you buy from/use.

It happens very, very rarely - but the problem is when it happens it can happen suddenly and be very, very hard to address properly.


I saw a talk by an npm developer who dismissed type checking as "just another kind of unit test" for your code (and advocated instead dynamic typing and manual unit tests). It bothered me enough to think about what was wrong with what he said long after the talk. I realized the difference is type checking takes the place of infinite numbers of unit tests: unit tests only assert an "exists"; type checking proves "forall".

The linked article, however, is a whole other level of incorrect thinking and drivel.


It's a fallacy to think that all statically typed languages are the same, and all libraries in the statically typed languages are the same. It seems the author is making these fallacies. My experience programming C, Java, and Haskell---all statically typed languages---is vastly different.


I have three personal reasons to prefer static compiled over dynamic interpreted

1. Refactoring. In, say, c++, you change a signature, or a member name, and your IDE provides you with a neat, comprehensive list of errors to fix, if you're even performing the change manually. Contrast that with python, for instance, and I have to rely on what appear to be heuristics if I use an IDE to propagate a change, or otherwise repeatedly hit run to change everything that I've broken, and pray I didn't miss any code paths that'll bite me later. Maybe I'm just not writing pythonic code, but I find it rather difficult to maintain large codebases in python for this reason.

2. Focus. I realized that having a constant stream from a trusted linter makes it really easy to stay on task. I can throw out a bunch of scaffolding and then fill in the blanks based on the constant stream of errors, pre compilation. Sure, in pycharm I can run code analysis to get a list of probable errors, but given the nature of dynamic languages, there'll be plenty that's missed and plenty that isn't necessarily right, and not having a project wide linter in real time isn't the same.

3. Understanding APIs and library internals. There is a TON of use information that comes for free with explicit static typing, especially for scientific/numerical code. In python I frequently find myself having to look up simple function use because arguments, names, and returns can be ambiguous. In a typed language, I know exactly what goes in, what goes out, and how to structure my data appropriately. The difference in coding speed is huge, and I don't have to run the code nearly as often to make sure I'm doing things right.

Why anyone would choose python for large projects eludes me!


> Why anyone would choose python for large projects eludes me!

"Mypy is an experimental optional static type checker for Python that aims to combine the benefits of dynamic (or "duck") typing and static typing." [0]

[0] http://mypy-lang.org/


I parse a lot of JSON in surprising and inconsistent formats and what works best for me is to immediately sanitize the object (option 1 that they describe) so that the rest of the code that operates on it can stay consistent

I'm interested in what an implementation of option 3 would look like. Is it just some regex to find the relevant characters in the string?


If I'm lucky, for web stuff, I can just write a typescript interface definition or 5 to describe the JSON format, and suddenly I have working intellisense, protection from typos (after the first), etc.


That doesn't protect you from inconsistent input. You still may have to sanitize.


I think option 1 is a take on "be liberal with what you accept and conservative with what you send."


No, that’s orthogonal: Option 1 can mean either working around unexpected input, or failing in some way (and the same is true for the other options, but creating systematic, handle-able failures gets harder).


I'd paraphrase as "for the case of consuming an external API, using generic maps and arrays is more useful than strictly 'decoding' the data to a type earlier than necessary". That kindof makes sense.

It seems a bit flame-y to see this as "dynamic typing is better than static typing", though. -- It's more of a suggestion that a technique like "cast to a type" where you don't need all the info in the type risks breaking when it doesn't need to. It's better to make fewer assumptions when relying on things you don't control.

If the external API changes, code breaks whether you were "dynamic" or "static". "Just change the code" is as applicable to code in either case.

That said, it's kinda weird that an API can be both unreliable enough as to not conform to a schema, but still reliable enough to trust the data you want to get out of it.


> I have dealt with terrible APIs that were outside of my control. When I worked at Timeout.com, we had to pull in data from Ticketmaster and also Booking.com. These APIs were inconsistent, and they would change over time. They also left out fields, so all fields had to be treated as an optional, which it made it difficult to enforce a meaningful contract.

Wait what? Why would you ever work directly with the data that you grab in some foreign API? You map the data that you actually need into some datastructure of your own making, that you have control over, and that hardly ever changes - unless you want it to. So when the API changes (or even worse, you have to exchange it for whatever reason - it's foreign after all and not under your control), all you have to do is change the mapping process, and voilà, you're back in your own safely typed world.


One thing that annoys me about static typing is that most of the CRUD programming I do merely martials data back and forth between the screens and database. Only a fraction is processed, or should be processed by the application.

Things like null-ability, base-type, and max length should be supplied by the database and therefore not echoed in source code per the Don't-Repeat-Yourself principle (DRY), unless a custom deviation is necessary.

If the screen validation needs to know such info, it can get a majority of it from the database dynamically. But, our stacks don't typically do this for unknown reasons, and thus we reinvent the field attribute wheel in app code.

I posted a question similar to this on HN recently: https://news.ycombinator.com/item?id=19146439


All of your data structures have types, whether you declare them or not. Your code expects things to be a certain way, and if it's not, things break. Static typing just means that you annotate you code with your expectations so you can get some automated error and consistency checking.

Automation is good, right?

With dynamic typing, you need to manually write more unit tests to get the same level of confidence. That's just not worth it for anything important.


Static typing just means that you annotate you code with your expectations so you can some automated error and consistency checking.

And in languages with type inference, you largely don't even have to do the annotating.


> All of your data structures have types ... Static typing just means that you annotate ...

Programs have (static) types, data does not. Static typing removes correct programs from the language. Try this in some ML-like language:

    let selfapply f = (f f) in
    let identity x = x in
    selfapply identity 42
If you transcribe this to (e.g.) Lisp, it will return the number 42. The program is short, simple, and safe, but well-regarded static type systems can't cope.


Any static constraint is likely to rule out good and bad programs. The tradeoff is how irreplacable those good programs are vs. how dangerous those bad programs are. "endofunction over either integers or endofunctions over integers (or over endo…)" is cute but I wouldn't lose a lot of sleep from underconstraining that domain.


It's pretty obvious what you do if a field in a JSON object is optional, you use an optional type. Any good statically typed language has that.


If real world API is as chaotic as he mentioned, how can he even know the data is trustable?

From his Java's example, I can't see how he can fix with dynamic language. He still needs to validate the API response and throw exception even he uses dynamic language. Unless he uses something like functional "Maybe", so he can safely process the response.


I think the crux of the issue is that the way formats like JSON and XML are typically handled in Java forces you to validate more than you need to, earlier than you need to.

It makes it very difficult to comply with Postel's Law.


> It makes it very difficult to comply with Postel's Law.

Not really, since “handling” doesn’t mean “throw errors”. But regardless, Postel’s Law is often seen as a failure in hindsight. See the “Criticism” section on its Wikipedia page. In general you don’t want to comply with Postel’s Law.


Handling shouldn't mean "throw errors".

But the whole process of creating Beans or immutable POJOs and then decorating them with annotations seems to invariably lead you down a path where, if you're dealing with a particularly hoary API, you've either got to create a ridiculous number of single-use DTOs to handle all the edge cases, or define a manageable number of DTOs that unfortunately also place more stringent requirements on the input data than are strictly necessary.


Well Java is just an incredibly bad poster child for static typing. But even in Java you can do better by using modern sum types. Defining a “ridiculous number of single-use DTOs” isn’t actually a problem in languages that support this well (e.g. by allowing you to create anonymous tuples). But as you’ve said yourself: this only applies to “pretty hoary APIs”. Why not take the opportunity to create a better API (through a wrapper, if you have no control over the original API)?


Dynamic language proponents make the case about programmer productivity being better with dynamic languages. That may be the case but I have found that integrating systems where one system is coded in a dynamically typed language and others are written in statically typed languages is a nightmare.


One thing that annoys me about static typing is that most of the CRUD programming I do merely martials data back and forth between the screen and database. Only a fraction is processed, or should be processed by the application.

Things like null-ability, base-type, and max length should be supplied by the database and therefore not echoed in source code per the Don't-Repeat-Yourself principle (DIY). If the screen validation needs to know such info, it can get it from the database dynamically. But, our stacks don't typically do this for unknown reasons, and thus we reinvent the field attribute wheel in app code.

(I posted a question similar to this on HN recently: https://news.ycombinator.com/item?id=19146439 )


I am a big friend of static typing but I agree that there should be a better connection between the types in the database, the types in the programming language and the UI validation logic. Some ORMs help but I think this could be simpler.


ORM's have a big learning curve, especially troubleshooting, and tie your stack to an ORM brand. But the worth of ORM's are probably another topic.

I'd like to see a data-dictionary-driven approach where most of field info comes from a data dictionary, and only deviations need to be defined locally. (Or perhaps create and mark dummy columns in the data dictionary that are slated to be used for local customization.)

I suppose one could push a button and have static classes or definitions generated for the source code from the data-dictionary, and thus still have a statically typed system. It's still duplication of field attribute info, but at least it's systematic duplication.

I used to use systems/tools that integrated the database, business logic, and UI; and they reduced the amount of typing and code rework by a large amount. The multi-layered approach may give us cross-vendor flexibility, but at the cost of more code diddling to wire up the interfaces between all the layers. Layer independence seems to increase duplication of field-related info. Back then I could spend more time on requirements and analysis and less on code wiring and re-wiring. Now we waste too much time dealing with low-level repetitious grunt work.


There is a good talk I just watched a few days ago on this topic: Static Versus Dynamic Typing [1][2], which listed the pros and cons of different typing systems, using racket and ocaml as examples:

[1] https://courses.cs.washington.edu/courses/cse341/18wi/videos...

[2] https://courses.cs.washington.edu/courses/cse341/18wi/videos...


The best I can make of these discussions is that there is no oneand true answer. Some people prefer dynamic typing and some prefer static typing. I myself prefer static especially while I am developing something new because I feel I can be more aggressive in making changes because the compiler tells me immediately what broke. But other smart people feel the other way.

So I guess both sides are right but it’s good to think about what suits you best and then embrace that.


I type with two fingers. Would that be dynamic typing? :)


Only if you've had too much coffee.


>Why I prefer dynamic-typing over static-typing: the speed of adapting to change

Funny, that's the same reason I prefer static typing.

>In How ignorant am I, and how do I formally specify that in my code? I said that I liked to add run-time contracts to a function as I better understand it. When I first write a function, I may not know for sure how I will use it.

Which is irrelevant. You still know that the "customer_name" argument to it will be a string and the "age" will be an integer, no?

>For the programming that I do, I am often creating new architectures. Therefore I need dynamic typing.

Non seguitur.

>Consider dealing with JSON in Java. Every element, however deeply nested, needs to be cast, and miscasting leads to errors.

Another bad argument. First, if you don't cast, and expect an integer like 55 but get a string like John, your program has an error. The difference is that in a dynamic language your program will continue to run doing stupid things instead of crashing in the miscast.

>Given JSON whose structure changes (because you draw from an API which leaves out fields if they don’t have data for that field) your only option is to cast to Object, and then you have to guess your way forward, figuring out what the Object might be.

You can trivially have a JSON parser that returns a list of map of the 6-7 valid JSON types (maps ("objects"), floats/"integers", strings, booleans, null, arrays).

You don't need to deserialize to specific object structure/schema as is the default mode in some parsers, if that's what you want to avoid.

If you dislike the verbosity of getting nested elements in Java, that's a Java thing, not a static typing thing. Heck, it's very easy in Haskell (what with lenses and stuff).

With a language that supports Optionals and try or has a map index operator and list/map literals, it's more like JS or Python than Java.

If you just want to extract a deeply nested element, and not care what it is, but still use it, I'm not sure how that works.

Do you expect the object at e.g. resp["x"]["y"]["z"] to change types randomnly?

>Static typing does not live up to its promises. If it did live up to its promises, we would all use it, and the fact that we don’t all use it suggests how often it fails.

"Proper weight does not live up to its promises. If it did live up to its promises, we would all be on it it, and the fact that many are obese suggests how often it fails"

How about some uses of dynamic typing are for specific, constrained, use cases (e.g. glueing, quick scripts) and it increasingly breaks down with larger codebases and multi-developer projects?

Larger codebases and multi-developer projects either don't use dynamic typing (most huge projects the world relies on, from compilers to browsers, and from OSes, to all kinds of embedded hardware, games, desktop apps, etc, are done in one of C/C++/Java), and others (e.g. large websites) are moving towards some kind of types (e.g. Typescript and Flow).


> You still know that the "customer_name" argument to it will be a string and the "age" will be an integer, no?

I've seen integers sent as strings and others as integers in the same JSON. Datetimes stored as strings in three different formats by the same application in the same column of the same table, etc. The real world is really messy. Writing a new program is definitely quicker with a language like Ruby or Python for me (especially Ruby.) Working with Java is like walking with a cast on a leg.

But you know, every project and every developer is different, that's why we are using so many different tools. The OP accounts for that in the "There are many arguments in favor of static-typing" paragraph.


>I've seen integers sent as strings and others as integers in the same JSON.

You still need to know what they are in each case, regardless of dynamic vs static typing (it's a matter of whether the language has weak vs strong typing or overly accommodating coercion).

If you get an integer value as string for example, Python won't let you add it to another integer you got as integer. So you'll need to know what they are to treat them accordingly in your processing even in a dynamic language.

In such case, you can also read them as a variant type on a static language, that's eg. one of the 7 allowed types in JSON (you don't know whether a JSON primitive might be int or string, but you know it wont be suddenly a Date type or a Foobar instance).


> I've seen integers sent as strings and others as integers in the same JSON.

So what? Just use a veryFlexibleUint64: https://github.com/sapcc/limes/blob/d51ecdbb763318da146b9f32... ;)


> The widespread use of PHP, Ruby, Python and Javascript suggest that dynamic typing is useful. [...] If static typing lead to greater programmer productivity (via a reduction in bugs) then corporate America would only use statically-typed languages. But it doesn’t.

Yes, that is why Java and C++ are such tiny unknown little used languages


JavaScript is mostly forced via Web "standards" and probably would fade into oblivion if not for browser ties. Thus, I wouldn't include it in such a list. (Not an argument for or against either typing party.)


Same for PHP. It owes its popularity to early 2000s webhosting providers where only PHP was supported for server-side processing.


All languages that have been around a while have warts. One learns to work around the rough spots.


Dynamic typing is great for partially implementing solutions to problems that you don't fully understand.

This isn't always a bad thing, because sometimes "any implementation of a product" is vastly superior to that product not existing, and works well enough, often enough, that any edge cases can be ignored safely.


I love both for different reasons and pick my flavor according to the size and complexity of the project.

Seems fair enough?


Maybe this should be called "Why I Prefer Dynamic Typing Over Java"




Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: