119 comments

[ 4.1 ms ] story [ 175 ms ] thread
Which static language should supposedly have won?
Apparently the emergence of Go, Rust et al. is a sign that static typing has "won".

I'd more argue it's a sign that C and its derivatives are ripe to be replaced.

> Which static language should supposedly have won?

It's absolutely not that specific static languages have "won". But rather that the latest crop of static languages have proved that the oft-cited downsides of static typing, e.g. type stuttering in declarations, can be pragmatically addressed by other means, e.g. type inference. As such, the cost differential of static languages over dynamic is reduced to near-zero, and all of the benefits remain.

I don't really see an argument, or really counter-argument, in the linked post. The author complains that the current crop of dynamic languages are badly implemented, but I'm not sure that holds water when you look at e.g. Clojure. They claim the chief advantage of static languages is IDE support/integration, but that seems like a strawman to me, a fringe benefit of the real, structural advantages of an explicit type layer.

> But rather that the latest crop of static languages have proved that the oft-cited downsides of static typing, e.g. type stuttering in declarations, can be pragmatically addressed by other means, e.g. type inference.

Meanwhile, dynamic languages like Python are adding type hints, to give many of the benefits of static typing while retaining full dynamic semantics.

The lines are getting blurry. IMO a good sign.

So basically Scala and Haskell? I've tried Go but was turned off by the complexity of writing a sort function - an artifact of static typing. Seems to me you'll always end up with something like generics which becomes complicated quickly?
I mean every language has a baked in sort function, so maybe that is a bad place to start :)

Java collection signatures are not super complex but they have fundamental bugs fixed in the slightly more complex scala collections type signatures.

No I mean using the sort framework of Go. It takes several steps to set up a comparator function.

compared to list.sort(function(a,b){return comparisonResult}) that was very demotivating to me.

It seems like quite a few people have found that the simplicity of Go's type system just winds up transferring the complexity to your code base, instead of in the language implementation. I find it interesting how divided the opinions are on this.
There's no complexity involved in implementing the sort.Sort interface in Go. Some typing, but certainly no complexity.
An alternative is optional static languages like Groovy or alternatives like python Type Hints (https://www.python.org/dev/peps/pep-0484/) are better than pure dynamic languages.
I agree, I think optional or gradual typing is the future for dynamic languages.
So a big project with optional typing. How do you handle it? Each person picks a level? Or make rules that all services are strongly typed but within a method is loosy goosy?

I see the project going one of two ways. One all loosy goosy. One all statically typed. At which point what did optional typing add? Pick a side and go for it.

I see it as a gradual thing. Early in the project loosey and then as the software matures add in more typing. But yeah, everyone needs to agree on the right level for that stage in the project.
You seem to be under the impression that types are for late stage development. I find them indispensable early on. First, because they let me feel out where my assumptions conflict, often before I've gotten to writing the bit of code that will make it obvious. Second, because when my assumptions are wrong, the type checker is a tremendous help refactoring - telling me all the places my old code is incompatible with my new assumptions. Both of these mean I don't need to be quite as sure that I've got things exactly right as I start coding.
A dynamic language with optional static typing is still a dynamic language that offers its own syntax for dispatching to statically typed code. Python originally offered easy dispatch to C++ code, and Groovy to Java code. The typing guarantees aren't really in the dynamic language there if it's optional.

There's also the commercial aspects of static typing in a dynamic language. After 10 years, Groovy introduced the annotations to optionally statically compile code in order to compete with Java instead of complementing Java, which changed the business purpose of the language and their relationship with Oracle.

Won ... for what job? Dynamics have their places.
They have won in theory: they are arguably better in every way than dynamically typed languages (DTL) in the sense that they offer all the advantages that used to be unique to DTL and, obviously, also all the advantages of STL (automatic refactorings, performance, ease of maintenance, etc...).

Javascript is the last serious holdover of the DTL generation but even it is showing tendencies to be replaced by STL (Typescript, Dart). It will take a while, though, but the trend is clear.

I think what we've seen over the last decade or so is that STLs have been updated with a lot of the features people loved about DTLs, while DTLs have not been able to add the features people love about STLs.

Ultimately, I guess it was easier to add lambdas to Java than to add solid IDE support to javascript.

Replaced? I can't see that happening in the next 5 years (an eternity in this business) Supplemented with tools like Flow? That's already a huge thing, and it's part of the React and React Native tool belt.
>You can have statically compiled languages that use type inference to realize what is effectively dynamic typing.

Just because you don't have to explicitly write out the type does not make it any less static.

I believe that the usual arguments against languages with static typing such as verbosity and lack of flexibility are largely eliminated by the more modern languages such as Scala, Kotlin or Typescript (though typescript is more "optional typing" than static really).

>Just because you don't have to explicitly write out the type does not make it any less static.

No, but not having to write the type was one of the biggest attractions of dynamic languages -- a lot of us didn't care that much for being fully dynamic, but just enjoyed the less ceremony of dynamic languages.

As for not having to commit to types for some cases, STL languages can also have a "void *" or "variant" or "dynamic" type (a la C#).

There is one other undeniable advantage to dynamic languages: you can express things in a dynamic language that you can't in a static one. Static languages try to be as sound as possible, at the cost of some completeness. Dynamic languages are less concerned with soundness and can be more complete.

As an example, duck typing is usually not possible to achieve in a static language - it's really hard to allow duck typing and remain sound (I don't actually know that it's possible, but I'm not sure either way).

Having said that, I'm firmly of the opinion that static languages are much, much easier to write in and maintain once you get the hang of whatever type system they use, and the loss of completeness is acceptable for all the benefits they bring.

OCaml has duck typing for objects (strictly speaking it is "structural typing").
Oh, right, I never realised that structural typing was static duck typing! Scala has it too, even if it's frowned on. Thanks for enabling me to make the connection!
Doesn't Go have the same thing?
I know next to nothing about Go, but I think you're referring to the fact that it has some sort of implicit inheritance resolution - if there is a Reader interface with a read method, and a type A that has a read method with the same signature, then A will be considered to be a subtype of Reader, whether you marked it as such (or whether you want it or not).

I see what you mean, this feels like a static version of duck typing. I'm not sure how I feel about loosing control over what supertypes my type extends, though - well, I lie. I don't like it. But I haven't given this enough thought for a constructive, well argumented discussion on the topic.

>I'm not sure how I feel about loosing control over what supertypes my type extends, though - well, I lie. I don't like it.

Well, don't you lose that by default (and even more) with dynamic typing?

You do, and I really, really dislike doing any serious work without a solid type system.
Question is, how many real-world cases there are where duck typing is super beneficial. Usually if you need a bunch of differently-typed objects to fulfill the same contract, you can just make them implement an interface (said interface can also be documented, etc., it makes the intent very explicit).

I do believe there are cases where dynamic typing is genuinely useful, but those make up a very small portion of real-world problems.

It's not an either/or situation--or at least it shouldn't be. Static and dynamic type systems are not opposites. They're not sworn enemies. They don't necessarily have to be alternatives; it's reasonable to want both.

A couple of years ago I worked for DARPA project that was building a system designed for greatly enhanced security and reliability. It had a novel programming language designed to be able to express a rich set of reliability and security constraints in the type system. It had a rich static type system, but it also had a dynamic type system. Why? Because some important constraints simply can't be analyzed statically.

For example, a program could say that it was impossible for a given piece of information to be delivered to an unauthorized receiver. That constraint cannot be analyzed statically because the authorization status of a given agent can change at any time. The type system had to be able to check authorization, so it had to have a dynamic checker (in fact, the system was designed to be able to do dynamic checks in hardware).

Maybe this sounds like an esoteric use-case, but is that because nobody wants to be able to express such constraints, or is it because we just don't expect to be able to do so because we haven't had the tools?

The project in question is in part meant to make the case that such use-cases should not be esoteric--that one of the reasons that our reliability and security situations are so embarrassing is that we haven't so far taken those considerations seriously enough to develop the tools to deal with them. If we want to get better, maybe we should be thinking about how to integrate both static and dynamic type systems, rather than exalting one and denigrating the other.

I agree that duck typing is rarely critical, you can always work around it when you find you'd like to have it.

On the other hand, I disagree with the scenario you describe: if you have multiple types that come from an external, closed-source library, you won't be able to have them extend a new interface. If you're lucky and they've not been marked final, you'll need to wrap them in another type that extends the right interface, then unwrap them... not at all impossible, but a lot of boilerplate.

The best solution I know of is type classes, in languages that support them.

Those sound like implementation details of a specific language (C# I'm guessing?) rather than a fundamental attribute of statically typed languages.
I don't think so, but I'd be happy to be proven wrong.

If you have a function that expects a type A, and you want to pass an object of type B that doesn't have A as a supertype, I don't know of many ways to do so. Either you wrap your B in a type that extends A, or you create a new implementation of B that extends A (this is often the same solution as the first one), or you use type classes or some variant of the concept. Is there an other option that I'm not seeing?

In Haskell, you declare that a type is an instance of a typeclass, and provide implementations for the required functions. You can do this anywhere for any type. Then, you have your functions accept any type that is an instance of you typeclass you need. Go has a vaguely similar concept. This is incompatible with subtyping, but not incompatible with static typing, and is one of the reasons fans of functional programming languages can so derisive of languages that allow subtyping.
(comment deleted)
In Haskell, you declare that a type is an instance of a typeclass, and provide implementations for the required functions. You can do this anywhere for any type. Then, you have your functions accept any type that is an instance of you typeclass you need. Go has a vaguely similar concept. This is incompatible with subtyping, but not incompatible with static typing, and is one of the reasons fans of functional programming languages can so derisive of languages that allow subtyping.
Why aren't type classes the solution you're looking for?
I... don't actually understand why you would ask that question. How do type classes help, one way or the other, when the discussion is "duck typing cannot (always) be replaced in static languages by having various types extend a common interface. True or false?".

They allow you do something else, something I would argue is better (and I explicitly said so, "The best solution I know of is type classes, in languages that support them."), but are entirely irrelevant to sanderjd's point and my answer.

I know you mentioned type classes (repeatedly and positively). What I mean is that I don't see why, in their presence, there's still a problem. On careful reread, I guess you don't see them as an example of "having various types extend a common interface"? (which would make them a solution, but excluded from the discussion) (edited to add - and I find that description to fit them just find, hence my confusion)
That's exactly it: they're a good solution to the problem, but since type classes work specifically by avoiding subtype polymorphism (and are instead a mix of parametric and ad hoc polymorphism), they cannot be part of a discussion that is centered on whether or not subtype polymorphism is a good fit.

But, yes. The more I code, the more it feels like type classes are never not a good answer.

The thing is, I don't see anything actually restricting the scope of discussion to subtype polymorphism.

"The more I code, the more it feels like type classes are never not a good answer."

As they are used in Haskell, they sometimes get awkward where you where multiple instances are relevant to the same data in the same scope. You can newtype cast around, but I've been wondering (with multiparameter typeclasses) if reifying the instance we care about is 1) useful, and 2) actually still distinct from explicitly passing the dictionary as a record. Regarding 1, I've consistently leaned "yes", although without tremendous confidence. Regarding 2, I've gone back and forth over time.

As far as I'm concerned, the discussion I'm referring to started with this comment from realharo: "Usually if you need a bunch of differently-typed objects to fulfill the same contract, you can just make them implement an interface".

The way I understood that is, if you have a f(a: A), and need to pass it a B and C, neither of which are subtypes of A, you can just create a new type D, have A, B and C extend D, and modify f to expect a D. My point was that it's not always practical nor even possible to do so.

A type class would be a good way to abstract over the type itself and simply require a specific behaviour, but by the time you have f(a: A) where A is a concrete type, and you can't modify f (because it comes from an external library, say), it's too late to retrofit type classes into it.

As for your other point - type classes being awkward when you have multiple possible instances for a given type - I agree, but must say that I'm spoiled: my primary use of type classes is with Scala, where they're just, when you come down to it, parameters to functions. You can let the compiler infer them when there is no ambiguity, but when you need to pass an int to a function that expects "A with a monoid", you always have the option of being explicit about which monoid instance to use. I believe Haskell treats them as implicit parameters as well but without the option to pass them explicitly.

Finally, I'm afraid you've lost me with your last bit - reifying the instance we care about and passing the dictionary as a record. I wish I had something smart to answer, but I'm not sure I actually understand what it means. I know enough Haskell to be able to be able to read it (a necessary skill if you have even the slightest interest in FP), but not much more than that. Maybe if I knew more I'd have a clearer understanding of what you mean?

To be clear, I'm not meaning to criticize, just understand my confusion and explore terminology.

I agree with your starting point, but to my mind type classes are precisely a way to "make [types] implement an interface". I completely agree that it is often impractical to do so by defining new types.

I'll address the rest when I have a little more bandwidth - I hope you'll forgive me; between interesting projects at work, a new baby, and holiday goings on, attention is in high demand.

I didn't realise hn threads could go so deep.

I understand that we're not arguing, and find the conversation interesting: I approach it from the point of view of someone who was mostly taught OO (and learned whatever CS theory he knows by himself), where you seem to have a more solid FP and theoretical background and entirely different viewpoint.

As a new father myself, I absolutely understand that free time is scarce. Enjoy your baby and holidays!

Fleshing out my "other point":

"Passing the dictionary as a record" is a pretty common alternative to typeclasses. The way it works is if you have a typeclass:

    class Foo a where
        foo :: ...
        bar :: ...
you instead make a record that looks like:

    data Foo = Foo { foo :: ..., bar :: ... }
This works great for a lot of things, and is often preferable to typeclasses when all you're doing is defining an interface. One objection is that things look slightly less tidy, but the main problem with it (where it's a problem at all) is that there's no way of identifying individual implementors of an interface by type anymore. An example where this relevant is Set. We could define the Set operations to take a comparison function, but we couldn't be sure that all comparison functions agree across all interactions with a particular set.

What I mean by "reifying the instance" is indexing typeclasses with a (single constructor) type that identifies the instance, and then passing that around to let us select which instance we care about, even for the same underlying type.

For example:

    {-# LANGUAGE FunctionalDependencies #-}
    {-# LANGUAGE MultiParamTypeClasses #-}
    {-# LANGUAGE FlexibleInstances #-}

    import Data.Function (on)

    class ParamOrd o a | o -> a where
        pcompare :: o -> a -> a -> Ordering

    data StringsOverLength = StringsOverLength
    data StringsLexicographically = StringsLexicographically

    data IntegersInOrder = IntegersInOrder
    data IntegersReversed = IntegersReversed

    data ReversedOrdering r = ReversedOrdering r

    instance ParamOrd IntegersInOrder Integer where
        pcompare _ = compare

    instance ParamOrd (ReversedOrdering r) Integer where
        pcompare o = flip (pcompare o)

    instance ParamOrd StringsOverLength String where
        pcompare _ = compare `on` length

    instance ParamOrd StringsLexicographically String where
        pcompare _ = compare
Now we could write a new version of Set, `ParamSet o a` such that we can still enforce agreement while choosing our orderings with an argument rather than a newtype.
(comment deleted)
One place where I ran into this was when I was building an ETL framework in Scala. The scenario was that I wanted to be able to move data from one database system to another and not have the end user of the DSL have to care about the types. The use case was essentially that you should be able to show up to an arbitrary database, run a query, and then pump that output somewhere else (e.g. another DB, flat file, transformation function, etc...)

I went around in circles and ultimately concluded no amount of type inference or other things in Scala's bag of tricks would let a user of the API avoid the dreaded type cast.

I have often seen this situation whenever I have tried to write generic code in a static language that needs to interact with a database.

That sounds like a perfect use case for type classes, have you tried that? If so, I'd be interested to know why it failed, if you can find the time.
There is one other undeniable advantage to dynamic languages: you can express things in a dynamic language that you can't in a static one. Static languages try to be as sound as possible, at the cost of some completeness. Dynamic languages are less concerned with soundness and can be more complete.

They are both "limited" to being Turing complete and therefore should be able to express the same things.

Implementing the same algorithm can be cumbersome with types at times (No 1:1 representation of JSON Objects for example) but you can define types which wrap things like that to make it work anyway.

>There is one other undeniable advantage to dynamic languages: you can express things in a dynamic language that you can't in a static one.

Including a static one with a "dynamic" type like C# has?

What would that be?

'As for not having to commit to types for some cases, STL languages can also have a "void " or "variant" or "dynamic" type (a la C#).'*

Even Haskell has Data.Dynamic, though it's not often used.

It's not just "not having to write out the type". It's that the compiler can automatically insert typed unions to make the typing dynamic where you need it. If a variable can have different types at different times, that's dynamic typing.
One way of looking at a union type is "this variable can have different types at different times." Another is "this variable has a single type - the union type."

Especially if actions are restricted to those valid on all parts of the union, I'd say it is correct to consider that to still be static typing.

I think it can certainly win as the type systems / inference get better, and languages with those characteristics are ported to mature platforms with good libraries, etc.

The real appeal of what we today call "dynamic languages" is leaving type-checking up to the programmer, so in essence all programs are typed - just so happens that some don't formalize it inside the code.

A good compromise until then is gradual typing.

It seems like a reasonable argument that there has been a dramatic rise in the number and popularity statically typed languages which feature type inference: Go, Rust, C# (to a limited extent), Scala, Swift etc. They combine the performance and safety of static typing without sacrificing expressiveness.
Well, there's plenty of controversy in this one, but I think

Compared to CS students, the average web developer is not as passionate about programming, and not as skilled a programmer.

...probably takes the biscuit; I'm not even sure where to start with it really, apart from my complete failure to understand how "web developers" and "CS students" are supposed to be two distinct groups which are able to be compared.

I'll tell you as a web developer who is a CS grad: CS students are terrible at programming and software development when compared to someone who does it for a living. It takes more than participation in a course to develop a skill.

I understand the distinction: CS students get geared up to understand algorithms, languages, and theory. A web developer understands his tools, his workflow, his practice, and people's needs.

I remember my final project in my CS master's degree very fondly: I delivered a barely working piece of software in a totally arcane problem domain with a very complex set of instructions which enabled it to work, sort of, in one specific environment. My supervisor was delighted.

In comparison with my battles to get something to work in both Firefox and IE6 a few months later in industry (in order to ship something that people's jobs actually depended on), it was an absolute walk in the park.

Anecdotally, on my year around 75% of students were there just because CS was supposed to bring money. They've started CS studies while not knowing how to program, knowing nothing about operating systems or caring. For them it was a 9-17 future job, nothing more.
First time I've ever heard a 9-5 job called a "9-17" job. Decided to Google it to see how common it was, and all the results are for the Bible verse Job 9:17 -

> He would crush me with a storm and multiply my wounds for no reason.

Seems appropriate for some "9-17" jobs.

17 is 5pm expressed in 24-hour time. :)

I like your interpretation as well, though.

That quote is amazingly apt. Working in software can definitely be a "9:17 job".
Far more appropriate than Job 9:5:

> He moves mountains without their knowing it and overturns them in his anger.

Well people come from different backgrounds. I went to UIUC having taken the only programming class my High School had, QBasic. I was in wayyyy over my head in my first C class slinging pointers all over (and then LISP - whoah).

Other people came in after programming as a part time job for a few years. I think it's a little quick to say someone came in for the money because I came in not knowing a ton of programming. On the other hand if course I look at salaries when picking majors. Otherwise I would have been a sci-fi writer :) Programming is better than writing now that I learned it...

I don't have any idea which side of the divide you'd fall on, but when I was in school there was definitely a group of people more likely to say "I'm taking X because it sounds really interesting" and a group of people more likely to say "I'm taking Y because I heard it's an easy A".

Given the timing (tail end of the last bubble), I always thought of the second group as "there for the money".

As with any generalization, it breaks down in plenty of specific cases.

It doesn't help that there is this confusion that if you want to get a job as a programmer, you need to study CS, even though CS is not necessarily the best path to doing web development or writing iOS apps! This explains some of the frustration many students suffer, which makes them claim CS is detached from the real needs of programmers. This also explains articles like "the perils of Java schools" -- a "Java school" is by definition NOT teaching CS! CS is a theoretical field which has applications for the software industry (otherwise it wouldn't be very interesting), but it is "researchy" and theoretical first. It is the foundation of computing, kind of like applied maths, and not supposed to be training for your next job. Unless, of course, your next job actually requires a scientist or someone with a good understanding of the theory.

This unfortunate conflation of "CS" and "programming" is so common it's starting to become the mainstream definition of CS, much to my annoyance, and soon it will no longer make sense to push back against it :(

Not saying I agree, but there is this notion that "proper" CS students are interested in CS for its own sake - they're meant to find algorithms and data structures and programming paradigms inherently fun and interesting. Web developers are expected to be interested in the end-game, not the process - having a cool feature that works cross-browsers is something to be passionate about, the fact that it uses websockets is just plumbing.

I hasten to add that I hold no official position on the matter and merely wanted to help you see how it's possible to consider CS graduates and web designers as too distincts sets.

I hoped to have debunked, though not thoroughly, the myth that dynamic languages cannot scale to power large projects in my recent talk at Pycon CA. Just take a look at Openstack. It's powering clouds in CERN and Yahoo! Japan where it provides the infrastructure for delivering earthquake notifications to the public -- a valuable and critical service! And it's written largely in Python.

It does rely on systems written in static languages and is itself written in one... but dynamic languages are very useful for a class of problem where deferring decisions about specifics until run-time is a huge advantage. Normally this is reserved for exploratory programming but in practice it is also useful for dynamically configured systems that can introspect themselves at run-time and change that configuration or adapt to unstructured input.

Update: I'm also one of the unwashed masses that, gasp, didn't go to university and study PLT. I still have a dog-eared copy of SICP, The Dragon Book, Concrete Mathematics, et al... and started by making terrible pong clones and text adventures in BASIC on an Amiga 500.

>I hoped to have debunked, though not thoroughly, the myth that dynamic languages cannot scale to power large projects in my recent talk at Pycon CA. Just take a look at Openstack. It's powering clouds in CERN and Yahoo! Japan where it provides the infrastructure for delivering earthquake notifications to the public -- a valuable and critical service! And it's written largely in Python.

That doesn't say much in itself though. Such infrastructure for "earthquake notification" could just be a few thousand lines or even mostly "glue" code.

As you say "It does rely on systems written in static languages and is itself written in one" which kind of refutes the whole argument, doesn't it?

>It does rely on systems written in static languages and is itself written in one... but dynamic languages are very useful for a class of problem where deferring decisions about specifics until run-time is a huge advantage.

For those cases couldn't one just use a DSL or at worse an sandboxed isolated dynamic language from inside a STL talking care for the rest of the system?

There are several "business rules" systems for STL.

>That doesn't say much in itself though. Such infrastructure for "earthquake notification" could just be a few thousand lines or even mostly "glue" code.

https://github.com/openstack/neutron

I assure you that OpenStack is a little more than "glue" code.

Not sure what part of OpenStack is written in a STL, but the vast majority of its hundreds of thousands of lines of code is python.

> That doesn't say much in itself though. Such infrastructure for "earthquake notification" could just be a few thousand lines or even mostly "glue" code.

In total Openstack encompasses around +4M SLOC written in Python. How much is deployed in a given cloud depends on the configuration. However the community must still shepherd and manage all of that code and make regular, stable releases on a six-month cadence.

It's not "just" glue code.

> As you say "It does rely on systems written in static languages and is itself written in one" which kind of refutes the whole argument, doesn't it?

Not necessarily. Awk was necessarily written because querying unstructured input is a huge pain in plain C. Kernighan gave a recent example of this in one of his recent talks on programming language design.

The caveat is there is a limit at which adding more lines to an awk program becomes counter-productive. It's essentially a good DSL but a terrible language. I think Python defies that -- with the millions of lines of code managed by the community of thousands of developers a large system written in a dynamic language isn't impossible or necessarily hindered by its lack of static type analysis.

> For those cases couldn't one just use a DSL or at worse an sandboxed isolated dynamic language from inside a STL talking care for the rest of the system?

In some sense this is how I view Python and languages of its kind... but I think in practice it's more of a philosophical viewpoint. In practice dynamic languages are general purpose and much suited to certain kinds of programming that static languages are not.

Common Lisp and Smalltalk are great examples of dynamic languages kicking butt. Starting in the debugger and developing self-introspecting systems has a peculiar effect on the programmer. One tends to develop a domain language for solving a class of problems in order to make them tractable. One thing I dislike however is how divorced it can be from the machine. Some Common Lisp compilers can produce really awesome code but it does take a little more burden from the programmer to gain such efficiency from the compiler (compared to the tactical omissions of defined behavior from languages like C which allow almost trivial optimizations... with the trade off that certain errors are quite likely on my part if I'm not careful).

I think there is room for both in the world. I really enjoy OCaml, C, Python, and Common Lisp... and I would seriously consider the problem before the language. Our job after all is to transform data and not spend time writing pretty, elegant, or clever code for the code's sake.

update: grammar.

OpenStack is the perfect example of how Python doesn't work well for larger projects. It's only because of an absolutely massive investment in testing that OpenStack works at all. I think it's more accurate to say that OpenStack works despite an unsuitable choice for implementation language.
I assure you that even if you wrote it in Haskell you'd have a few unit tests and integration tests in there.
I don't think he claimed otherwise. There's a difference between a code base that makes judicious use of tests to validate business logic and one that relies on the test suite just to keep it from falling apart. I've worked on the latter, so I know ;)

I'm not making any representations as to whether or not this is true of OpenStack. I honestly wouldn't know.

I can assure you, as an active technical contributor, that the testing infrastructure in Openstack is verifying business logic, ensuring consistent coding standards, running unit tests and code coverage, and all of the usual activities associated with delivering reliable software. The difference for many projects is the scale at which it is automated thanks to the Openstack Infra and QA teams.

Any suggestion that Python code cannot possibly execute without it is an exaggeration.

the level of testing OpenStack does is the only way you can really test something like OpenStack no matter what the language.
JavaScript, PHP, Python, and Ruby are all in the top 5 spots on GitHub. Java is the only STL that made the cut. There are certainly types of work that seem to favor dynamic languages, because they have the ability to do some interesting things. ORMs, for example, far more powerful in dynamic languages as far as I've encountered
> JavaScript, PHP, Python, and Ruby are all in the top 5 spots on GitHub.

All of which are established languages created in the 90's. It takes time for languages which are rapidly gaining mindshare to gain marketshare on GitHub.

> It takes time for languages which are rapidly gaining mindshare

Honestly curious: which new languages are those?

Go, Swift and Rust come to mind. Some alternative JVM languages aren't doing too badly either.
Swift is very much an Apple language, replacing Objective-C. You won't see it replacing JavaScript, PHP, Python, or Ruby.

Same for Rust, which mostly replaces C++ and a bit of C. Maybe some Java, too, for people using Java for the safety despite really wanting something lower level.

IMHO Go isn't much competition to most popular dynamic languages, but some people disagree.

It's anecdotal, but in the absence of anything more concrete... I think every blog post I've read about Go (bar one) that has mentioned the author's previous language mentioned a dynamically typed language. That may just indicate that switching to Go from a dynamically typed language makes you more zealous and likely to blog about it something. Or it could be that lots of Go users were previously writing Python/Ruby/etc.
I would say go and rust.
> Java is the only STL that made the cut.

Because of Android.

Even PHP has trajectory toward static types. Some examples are Hack[1] and PHP7[2]. Check out the talk Rasmus gave at Etsy[3] for more about PHP7 changes but it looks like at least limited support for static or "strict" types (whatever subtle distinction that might be) has enough merit for PHP to implement after all this time.

1. http://hacklang.org/

2. http://www.php.net/manual/en/migration70.new-features.php

3. https://www.youtube.com/watch?v=MT4rRWKygq0

PHP is still a dynamic language. PHP 7 gets us scalar typehinting support, which lets us check types at run-time. There are similar annotation based solutions for Ruby as well, which ultimately rely on a lot of Ruby's metaprogramming features. The idea behind these solutions is to have proper type support where you need it.

You will have to pry duck-typing from my cold dead hands if you try to remove it from PHP/Ruby completely.

You can go far, quickly with a dynamic language and that's often what you need in a startup environment.
> Dynamic languages such as PHP, JS, Python and Ruby, in addition to being relatively poorly designed, are the languages that powered the explosion of the web

The author seems to paint a broad brush in saying all dynamic languages are poorly designed. Languages can have different design goals.

From Matz, Ruby's creator;

> Instead of emphasizing the what, I want to emphasize the how part: how we feel while programming. That's Ruby's main difference from other language designs. I emphasize the feeling, in particular, how I feel using Ruby.

( http://www.artima.com/intv/rubyP.html )

So one of Ruby's primary design goals was programmer happiness, and in that respect it isn't not poorly designed at all. The technical 'perfection' of a programming language only matters to a point, it's us as programmers people that have to speak its language all day, and optimising for how we feel doing it is a valid design goal.

I don't think it is a valid criticism to say something is poorly designed, without looking at its design goals. Every language is poorly designed in one way or another.

When I have started my carrier, it was unimaginable to use a dynamic language in a serious project. I was taught(!?) that the difference of development cost was very small.

The mentalities have evolved. People know that you can drastically reduce the development costs (of small projects) by using dynamic languages. We know also that maintenance is more costly.

Static languages are always improving to support features that used to exist only in dynamic languages. Dynamic languages evolve to support optional typing. The differences are reducing, but I think there is still a need for the 2 kind of languages.

Often they are combined in big projects. For example c++/javascript in browser or c++/guile.

In academia and corporate? Sure.

In real world? Php, Python, Ruby and Javascript still reign supreme.

Mobile is another story since main platforms are controlled by corporations, but if it were for the hobbyists neither java nor swift would have had a chance.

In what sense are academia and corporate not "the real world"?
(comment deleted)
In what sense are there no innovative projects in academia? Of all the criticisms that could be made of academic research and projects, this one just doesn't make sense!
It's worth noting that development workflow in small businesses and startups is rapidly shifting towards being more "corporate" though. Whereas a decade ago the tools necessary to write quality code needed a dedicated person to manage, now they can easily be set up and used in a few days by a single developer. That's going to drive the language of choice too - if used a typed language isn't going to be any harder than used a dynamic language then there's little reason to use a dynamic one.
Another perspective is that dynamic application programming languages were always the underdogs. Corporate Cobol/Java/C#/C++ programmers always outnumbered application programmers in dynamic languages outside the ad-hoc web scripting languages (PHP & JS).

Clojure & other Lisps, Python, Erlang, Lua, and Ruby are all application programming languages first and web languages only incidentally (1). They all have clear strengths and are miles away from the horror of JS and PHP.

I think it shows in the article that the author's thinking on dynamic languages is colored by Javascript and its propensity to hide bugs. This is worrying since it might signal that JS does this for many people :(

(1) Admittedly Ruby is more strongly associated with Web nowadays due to Rails.

No, Javascript has won, and it's dynamic.

But people are starting to appreciate static typing assurances and IDE conveniences.

This post and the one that prompted it both seem to be begging the question. I don't see greater percentage use of static vs. dynamic languages now compared to ten or twenty years ago.

There is a lot of interesting research into strong static type systems but that has been going on for ages (ML family of languages).

In fact, I'd say if anything there is a big surge every decade or so in dynamic languages when a new problem space emerges.

90s - Perl, Javascript

00s - Ruby and Objective-C resurgence

10s - ES6 and JS related languages

Once an area matures, the paranoid static type people come in and harden things. Then people realize they're getting nothing done and add DSLs on top for flexibility. And on it goes.

The C/C++ people aren't paranoid (JPL coders excepted). Otherwise they would be using something else.

Ada users are paranoid and Java users are concerned about project cost.

No, they didn't. This article is narrow minded and prejudiced. Of cause if we're talking about programming in general - static typing languages are often a better option. But programming doesn't ends there, there is technical computing, statistical computing, data analysis and so on. How about beating Python + numpy + pandas in data crunching or maybe R in statistics? In this fields underlying data types is almost always very simple, and because of this you simply can't benefit much from static typing.

This is not about expressiveness (the article author is wrong here IMO). It's all about flexibility and (more important) interactivity. I can do useful things in ipython console or in ipython notebook in the browser. It's like a tiny lab for small and moderately sized things, data munging, analysis and visualization, prototyping and all this stuff.

There is dynamic languages like Python, R and even MATLAB that's not going to disappear anytime soon. There is a new dynamic language called Julia that's only starts getting traction but IMO it's already more interesting then Rust, Go and Nim combined together.

> How about beating Python + numpy + pandas in data crunching

I'd think this sentiment misses a small bit of context.

In the above combination, Python is the glue language, which merely makes it easy to dispatch the heavy lifting. Numpy is a damn good convenience wrapper around the under-the-hood number crunching engines - which themselves are written in static languages.

I mean, have you ever tried to _build_ numpy from scratch? That thing pulls in both BLAS and LAPACK, some of the most heavily optimised libraries in the world. These fortran(!) libraries can trace their ancestry all the way to 1970's, and have benefited from aggressive optimisations done over the course of 4 decades. [0,1]

So, invoking numpy as a testament to power of dynamic languages misses a pretty important point. And I say that as someone who loves Python, and uses it as a first-choice tool in perhaps 90% of use cases.

0: https://en.wikipedia.org/wiki/Basic_Linear_Algebra_Subprogra...

1: https://en.wikipedia.org/wiki/LAPACK

> So, invoking numpy as a testament to power of dynamic languages misses a pretty important point.

I don't think so. People build Numpy in a different language to the one they expose it in because those languages have different strengths.

If Numpy's source languages (including BLAS and LAPACK) were suitable for front-end usage, Python would have never entered the equation.

I think it's more a testament that despite the base libraries being so freely accessible, only dynamic languages have actually built front-ends that people want to use. Even Julia is dynamic.

I don't know, I'm taking a Program Analysis graduate seminar this semester, and my take is that the techniques for dynamic analysis are getting halfway decent.

It's also interesting to compare Python and JavaScript. Holkner and Harland did a pair of papers about those two communities' usage of dynamic typing - JS people do type changes throughout the program execution, but after initialization the Python people follow the Aycock quote: "Giving people a dynamically-typed language does not mean that they write dynamically-typed programs." Languages have different characteristic programs, to some degree.

It might be an interesting contest to find the earliest reference to this debate. It isn't quite what I was looking for, but I found this short comparison of programming languages from 1972 amusing: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/1972002...

For example, this quote from the conclusion: "The possibility of standardization of computer languages is still remote, and in the author's opinion will remain so until standardization in hardware applied to standard problems is first achieved"

Are we there yet?

Static Languages won? That's not just a bit premature; it's bizarre. Several of the most popular and effective languages at the moment are dynamic: Python, Javascript, Ruby, PHP, all the LISP derivatives.

I don't doubt that lots of new static languages have popped up, but how many people actually use those? Plenty of people use static languages, true, but those are mostly the old ones: Java, C, C++, C#, and Haskell and Scala.

Any claim that this has been settled by some new languages nobody is using is bizarre.

Sweeping statements like "X programming language/paradigm has won" do an injustice to the wealth of uses of programming. You wouldn't use the same programming language to write code for an Arduino, a startup MVP web application, an enterprise desktop application etc. and there's no reason you should.

Personally I developed most of my web apps in C# but I find Python great for prototyping and data analysis tasks. Why is there a need to declare a winner?