Static vs dynamic typing

Found an interesting discussion:

Comments?

4 Likes

Every program is explicitly or implicitly typed.

Even in a dynamically typed language, our brains loosely statically type check the code as we write it.

I am a big fan of Rich Hickey (he had a talk defending Clojure’s position) but he’s fighting a valiant but doomed-to-fail fight.

Computers are amazing things. The type checking maths is straightforward.

Why wouldn’t we use them both to help us make our code better?

1 Like

A Large-Scale Study of Programming Languages and Code Quality in GitHub (2017-10-22)

that static typing is better than dynamic;

In general I prefer static typing - but I’ve noticed there seems to be a growing segment in the industry:

  • who will not consider any language which isn’t statically typed
  • don’t scrutinize the actual quality of the type system that is enforced
  • derive a false sense of security from code compiling without errors - to the point that they get sloppy with their automated tests

“static typing” can be a useful tool in your toolbelt and it may even be desirable but I don’t think it’s necessary in all situations.

Anyone who believes that static typing is necessary would have to dismiss languages like Erlang and Elixir out of hand and miss out on some other opportunities.

Beginning of the year Robert C. Martin’s Dark Path contemplated the rigidity that some static type systems can impose on an implementation - and received a lot of criticsm.

In Types are like the Weather, Type Systems are like Weathermen Matthias Felleisen discusses the hybrid approach of “gradual typing” where early on a system can be dynamically typed but eventually types can be introduced into the portions that are stable and well explored (i.e. well known). But he is also very clear that the presence of any dynamically typed code has a significant impact on the “type safety” of the overall product.

Neither “dynamically typed” nor “statically typed” dogmatism is helpful (dogmatism never is).

4 Likes

Elixir uses the gradual type approach, but IMO it’s necessary in a clustered system. Otherwise every node that connects to the cluster would have to exchange contracts with every other node on the cluster for consistent behavior.

It would be like forcing web APIs to use WSDL instead of REST.

2 Likes

I’ve mostly written software in dynamically typed languages. And I miss static typing there. I’ve had bugs in my code, or found in other’s people code, that could be avoided very easily if the code was a statistically typed. Also nils/nulls everywhere instead of options, not sure if you can enforce exhaustive matching in dynamically typed languages.

On the other hand wrote I wrote in statically typed languages I didn’t really miss the “freedom” of dynamically typed languages at all. I wrote a bit slower, but the code was, I think, more thought through, because I created much more stucts/types instead of just using hashes/dictionaries/maps everywhere.

1 Like

C, C++, Java, Go, all are statically typed and all of them suffer from the NULL problem.

So this is not a problem related to static/dynamic typing, this is about how expressive a typesystem is.

3 Likes

Here’s an interesting paper on the subject written by Erik Meijer and Peter Drayton https://pdfs.semanticscholar.org/c803/59566e9feb4d8e2f39a3883148082c57a191.pdf : “Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages”
Robert C. Martin alias Uncle Bob I cannot take serious. He is a biased salesmen/guru trying to sell TDD at all cost (“You don’t need static type checking if you have 100% unit test coverage”). Read about “the guru problem” here http://darkagilemanifesto.org/dark-side-of-agile-janes-succi-splash-2012.pdf

Agile Methods have been conceived and refined by gurus,
e.g., Extreme Programming by Kent Beck, Crystal Clear by
Alistair Cockburn, and Scrum by Ken Schwaber. This
might be one of the intrinsic reasons for the problems we
mentioned before: the language of the gurus must be persuasive
and often elusive.
The guru is the person with wisdom – he or she knows
what, when, and how things should be done to achieve the
desired goal. It is the interest of the guru to hide the assumptions
on which the rules are based, on which previous
works he or she based his or her findings, how he or she
verified that what is claimed really works. For example, it
is not clear – reading the Agile Manifesto – why it is good
to focus on individuals and interactions over processes and
tools: it is not stated why and how software development
should benefit from it. The guru speaks using luring metaphors,
fascinating analogies, taking words from poems. The
disciples are fascinated, appreciate that he or she earns a lot
of money, and simply tries to replicate the teachings without
going in deep.
The guru has no advantage in making his or her followers
independent adults, otherwise his or her role as a guru
would vanish. In this way, the adopters remain dependent
on the guru: the adopters need the guru to continue to use
the method in cases not described by the guru up front, e.g.,
how it can be extended, in which order the different practices
should be adopted, etc.
Let us look more in detail at, for example, the concept of
emergent design. In Agile the architecture of a program is
not defined up front but “emerges” as the functionality is
developed. This is indeed a very tempting idea. It gives us
the hope to push the cost of change curve down even for
architectural decisions. However, this approach does not
work in all possible situations, but it requires an object
design philosophy that is based on the structure of the problem
domain [46]. This is not always the case. The guru
does know when it is the case and has several consulting
opportunities. So he or she picks smartly only those where
such approach is suitable and winning. Unfortunately, the
poor consultant does not fully appreciate the scope of applicability
of emerging design and does not have so many
job opportunities, so he or she simply applies this concept
throughout all her or his possible endeavours.
Altogether, the result is that the market is dominated by
a few “enlightened” gurus that keep the knowledge secret
among themselves, followed by many quacksalvers.
The described strategy of the gurus works because a
precondition is met: the followers of the guru – programmers,
managers, requirement engineers, project managers –
are looking for a silver bullet: they want a simple, safe
method that solves their problems. And gurus are willing to
give it to them. [etc etc]
1 Like

What I tried to write is that null's are problematic, and you can deal with them in statically typed languages (not that all of those deal with them); a statically typed language can and some do enforce that null's are checked properly where they may occur. But I’ve never seen a dynamically typed language that deal with them, and I don’t really see how can they deal with it properly :thinking: And that’s one of the reason I wish I could write everything in statically typed languages. There are of course any other reasons why I don’t, but they don’t have anything to do with type system :slight_smile:

3 Likes

In all the 4 languages I listed, you are not enforced to deal with them, you have to check x == NULL and you have to remember it.

This is not different from eg. Ruby or JavaScript, where you also can check for NULL.

So having a static typesystem per se does not save you from having errors because of NULL.

And even Haskell or Rust are not perfectly saving you from this.

A simple catch all clause is added easily, which just panics. Its just to have something running quickly. We can do proper handling when the customer has seen the product running in the labs. But you now what? Humans forget, software gets complex, and there will always remain some of those catch-alls which slip into the production software and they will trigger there, Costing a lot of money and time!

So as long as there are ways to postpone those checks or proper handling, they will slip to prod.

This is nothing typing can get rid of, this is were we need linters that get mad with us when we use panic!() (rust) or undefined (haskell) or similar.

2 Likes

In that particular post he also raised the issue of coupling introduced by static typing which Hickey also addresses.

And ultimately the dissenting “static typing fanatics” oversell their point of view in much the same way as Martin oversells TDD. Static typing isn’t a panacea either (but it definitely has it’s uses).

1 Like

That may be, but he - as loud voiced salesman/guru - can be expected to only name everything that supports his business. I’m not interested at all in Bob’s articles. Erik Meijer and Rich Hickey have more balanced views I find.

1 Like

I don’t know about Haskell, but you can’t write code with catch all clause that catches None and do something ‘None’ can’t do. I mean you can, but it won’t compile.
https://play.rust-lang.org/?gist=4ed6c05d904539bc796827e4750fe5b8&version=stable

Anyway,

Does not, but can if you choose one that has proper semantics. And dynamic languages can’t, at all.

The difference is that in dynamic languages is to find all places that might have NULL's, very hard. And in statically typed languages with proper semantics all you have to do to search for places where there is a catch-all match and it’s easy, often boils down to simple search.

And you can factor in humans into dynamic vs static dispute. Because sloppy programmers will be sloppy no matter what, but with careful ones you can catch whole category of bugs early and save tremendous amount of time you’d loose on bug fixing. I write it from my experience. Really, being able to write in a statically typed language once in a while is like a breath of fresh air, because if there is a bug there it’s a logical one(*), and those you can’t avoid anywhere.

So once again, when you deal with statically typed language you can choose one that gives you a lot of guaranties. But there is no dynamically typed language, that is even close to guarantee some things dynamic one can give you. And the speed of development has much more to do with familiarity of a language and codebase then type system.


*Provided you use a language with good semantics, and not abominations like *errors.errorString: runtime error: invalid memory address or nil pointer dereference Golang :wink:

2 Likes

This is something that so many people get wrong so very much…

No, you do not need to exchange contracts. Yes you can even hot-code swap systems and convert data formats. All of this while being fully typed. You just have to blockbox the data somehow (lots of ways), then parse out what you need, and this could easily be a, say, match language construct (or could be as trivial as json or ETF or something).

Likewise. Static typing is not a ‘safety net’, it is not for security, it is for catching the trivial stuff that is easy for a human to miss but trivial for a compiler to see, in addition if the final code generation is type-aware then it can generate substantially better/faster code as well. It is just a method of giving the compiler more information about your code instead of having to just guess everything.

like take the BEAM, last I checked its internal’s it knew squat about specs. It could generate some ‘slightly’ better code if it could infer a given binding was always of a given type inside a body, but that was about the limit of its type-optimize code generation. If on the other hand it was ‘specs’ aware and generated code that followed the spec then it could generate much better code overall, however it would still require a ‘default path’ that would be slower since someone can just apply/3 anything to something (among other ways), and that testing overhead may not even save the time. If however, something like Core Erlang was strongly typed then enforcements could be made and the compiler could be certain something is always good, and as such the dynamic calls would have to do their own checks on the inputs, thus the cost would then be with them, not the function. And it is still not only entirely possible to have a dynamic language compile to a typed one, but in doing so it can still be made even more efficient overall.

And ‘this’ is my favorite part about coding with statically typed languages, it makes me think through how my ‘data’ is structured, and thus functions become transformers of one data form to another, which improves how good my code looks, how well it acts, and how readable it is. Even in Elixir I try to do the same (structs everywhere!) but doing so has a slight performance cost (structs are not as cheap as, say, a tagged tuple, but are more readable) and I still end up writing my functions like they are doing processing instead of just transformation, much as I try to prevent myself from doing so…

They are all statically and ‘weakly’ typed. And yes the NULL problem did not need to exist in them, that was a mis-design in all of them. Compare that to Rust, no null’s, it’s null is just the empty Option, but that type propogates around and you have to test for it before you can use it, OCaml does the same, and Kotlin, and as do many others, it is overall a better design than having these magical weakly-typed 'NULL’s all over the place (and notice, those languages are not weakly typed, they are strongly typed, well unless you break into unsafe in Rust or magic in OCaml or so ^.^;). :slight_smile:

Egads that sounds horrifying! o.O!

Monadic operations is the usual dynamic way you’d deal with those. Elixir could really use a good Monadic interface (Enum is sooo close, but it is not).

This is not even so much a ‘null’ problem that you are speaking of now, but rather this issue could happen with, say, an if branch that the programmer does not want to handle yet so it just panics there, nothing to do with null’s but rather just having a language-level ‘TODO’ (which Scala has a better one ???, love it, it warnings on every compile and throws a TODOException when used ^.^).

The null problem is that, say, a pointer can be silently null and it is trivial to forget testing for that, where something like Option enforces checking for it in one way or another, just to catch one of the most trivial and *most*common* mistakes (if the compiler can do that for you, then it should!!!). Sure it will not catch all, but catching 99% of them still means a substantial bug reduction considering it is the most common bug. ^.^

You only couple tightly if you did not program well to start with. There are plenty of ways to have loose coupling, OCaml is rife with examples as well.

Well…
Static typing generates better machine code, TDD does not.
Static typing can be used to ‘generate’ code (like say property tests scaffolding), which makes TDD much more succinct.
Static typing forces you to think about the structure of the data and how it flows, TDD does not.
Static typing can significantly shorten code as you do not need to specify things that the compiler could otherwise infer (like take Elixir’s Enum.into/2, that is just a ‘typed’ declaration that the compiler could otherwise infer based on where the value is being put in to).
Static Typing makes very difficult if not some outright impossible many classes of very common bugs (90% of my bugs with my Elixir code just *would*not*happen* if it were strongly statically typed, the rest is most logic bugs, and even most of those I myself could help prevent with even more types).
Etc… etc…

As well, in statically typed languages you can easily have a ‘dynamic’ type too, like if(when?) I make a full statically typed language that compiles to the BEAM, I would definitely make a dynamic type that accepts anything, but to use it you would have to match out what the data in it is (of the supported BEAM types), this is what allows you to ‘blockbox’ the data. :slight_smile:

Go is just not a good language, like at all… >.>

3 Likes

Heh, lot of good quotes in that Reddit thread, but this one is a big one for me. ^.^

Personally speaking I’m nothing but relieved when something I’ve written doesn’t type check. It’s immediate proof that I’ve made a mistake and can hopefully learn from it.

2 Likes
lot of good quotes in that Reddit thread

Hehe, likie from the SuperDuperOvermind. :wink:

1 Like

I’ve not commented there?

1 Like

In terms of the contract, I’m not wrong there’s a misinterpretation.

You can send REST API calls to a statically typed language all day long. What you don’t get is the benefit of optimizing the client to send that call based on the type of the server unless you have a contract that clearly defines it. From the point it’s received on in you get the benefit but there’s not benefit at all during ththe exhange without that contract.

With the BEAM since any cluster can connect to any other and there is no guarantee about the code running elsewhere on the cluster you experience exactly the same thing. I can hop on and make a call to another node but without a contract in place I’m not getting a single benefit of optimizing to make that call.

The interchange doesn’t benefit from static typing.

1 Like

Except that you can build such contracts (F# has an especially interesting system for that as one example, Scala has another) to basically ‘predefine a structure that you want to match out’, then the ‘expected’ case becomes trivial and you can then do whatever you want for the unexpected format (either parsing out that you’d have to do in dynamic anyways, or error’ing because they sent you a wrong format, or launching the earth into the sun, or just ignore it by doing nothing, or whatever).

1 Like
My expert beginner opinion, with a pinch of humor. :)

I believe that all errors first happen in people’s minds and then get transferred to code.
Essentially, a programmer is a misbehaving function that sometimes returns 2, but sometimes “app1e”.
Then come languages that try to build a safety net around the misbehaving function, with type checking, classes, rituals.
And then there’s extensive testing.

In comparison:
“The chicken crossed the road.”

But wait a second!
“The chicken[adjective] crossed[adjective] the road.”

Hold on a moment!
“The ch[adj] cr[adj] the r[noun].” // ch is a coward, cr is angered, r is road.

Wait, wait, wait!
“f::ch->cr->r
ch[adj] cr[adj] r[n] // ch is a coward, cr is angered, r is road.
test: did ch cr r?”

It’s amazing that written code can’t be trusted to the point that it needs all these safety nets.
It’s also amazing that people are actually encouraged to write unreadable code.
Be c it so m bett to rea thi inste of norm tex.
Then come some people who hate writing code so much, they write a variable the same as a function, because parentheses are too much typing.
Then come the “guru” people who are so sick and tired of writing code, they actually praise their unintelligible work and pp h don und a nub.
Then come the corporations who have entire languages designed to serve their “easy employee replacement model”.
And of course some academia, who love to use complicated terms, to flatter themselves.

And all these people market their “solutions” as the absolute best way to write code and avoid errors.
Instead of helping the misbehaving function, and fixing the problem at the root, people try everything else under the sun.
If I were to write English the same way some people write code, I’d be at best considered uneducated, but in programming, it’s an automatic guru status with a stand innovation(<- if only there was type checking for English).

So for me, it doesn’t matter if a language provides typing or not.
It’s far more important that the programming language encourages code to be written in a way that forces errors to become this as apparent as.
It’s far more important for names in code to carry critical information together with them, so code makes sense in people’s minds instead of relying on machine checking, because machines are so good at understanding what people mean…
Is it not possible to stop the problem at the root?
Should we all go back home at 8 and close the windows because Randy likes to drink and drive every night?

I base this on absolutely nothing, or maybe on something, but certainly not enough to be taken seriously! Thanks :slight_smile:

2 Likes

Some discussion about functional languages static vs dynami

In this episode I talk with Micheal Sperber. We talk his introduction to programming and functional programming languages, important commonalities across languages, power of syntactic abstraction, teaching programming to beginners and experienced programmers, Concurrent ML, and more.

1 Like