Hmm, I’ll try it again, but I remember issues with the function call syntax too. Iirc, it had to do with the fact that redefinitions don’t count if the use site is running in another thread. But I’ll double-check this when I get a chance.
One example I can think of is how Ring middleware works. The request map is passed through a series of functions, and each one can modify it in its own way. For example, you could have an authentication library that adds an :identity key, and another that adds a :session key. These libraries can work together without having to know anything about each other.
I'm not sure about the history. It looks like UHC supported existential types at some point, but I'm not sure how that would interact with what I am presuming is a more sophisticated system in GHC Haskell.
I really like tome's observation in the other comment: universally-quantified types have a direct encoding in System F as type abstractions, but there is no such direct encoding for existentially-quantified types.
No, it's not. Try `(+ 1 "1")` in clojure and clojurescript. In clojure, it produces a runtime exception. In clojurescript it silently errs, resulting in a "11".
The compiler correctly infers and warns of the problem, but that is of no use if your inputs change types on you. In the case of the service I'm referring to, an external service started serving up json strings for large numbers, whereas it had previously been json numbers. Since there was no exception produced, it silently corrupted data for a couple weeks before it was caught.
The problem comes from the fact that clojure and clojurescript are two different type disciplines, but people approach them with the same expectations. That exact problem would have errored out if they were running clojure, and a thrown exception is good enough validation for many developers. But because they were duped into a false safety net by thinking clojure == clojurescript, it slipped right underneath their radar.
And documented to what extent types are automatically coerced.
Also got the rational behind this: performance.
And that every new release of the compiler performs smarter and smarter type inference and can warn about more of these cases. Though it still misses some as of now.
Just like your response, my evidence is the anecdata of my own experience. I’ve built a large system that 9 engineers use, all of different experience levels. Functional programming gives more understandability not less, you can always understand the input and our output of a function from the types. I really can’t see how anyone can argue about types and refactoring ... even without any tools you can just change the function signature and get everything compiling again. You know you didn’t miss any callers. Even better one knows when you can change a data structure or effect type from one to another because the compiler will tell you. If you use scala correctly you can eliminate whole classes of runtime errors and i’ve experienced that too both in a good way and a bad way when we let nulls creep in.
Whats even better is higher kinded types let you assert semantics to engineers that are hard to do in Clojure.. this type must be appendable or foldable, this type must handle async, this type maybe missing and this list cannot be empty.
All these things are a joy not a burden once they start working for you
15 comments
[ 3.4 ms ] story [ 39.9 ms ] threadStatic typing requires all types to make sense together no matter how small the addition is.
In dynamic typing, we can just add a class/object/field here and there because it'll only be used narrowly anyway. So, it's often fine.
This would be great if we can think of a small example to illustrate this trade off.
This post had some interesting tidbits about technical challenges, but I didn't fully grasp everything on first read: http://blog.ezyang.com/2016/04/hindley-milner-with-top-level...
I really like tome's observation in the other comment: universally-quantified types have a direct encoding in System F as type abstractions, but there is no such direct encoding for existentially-quantified types.
The compiler correctly infers and warns of the problem, but that is of no use if your inputs change types on you. In the case of the service I'm referring to, an external service started serving up json strings for large numbers, whereas it had previously been json numbers. Since there was no exception produced, it silently corrupted data for a couple weeks before it was caught.
And documented to what extent types are automatically coerced.
Also got the rational behind this: performance.
And that every new release of the compiler performs smarter and smarter type inference and can warn about more of these cases. Though it still misses some as of now.
Whats even better is higher kinded types let you assert semantics to engineers that are hard to do in Clojure.. this type must be appendable or foldable, this type must handle async, this type maybe missing and this list cannot be empty.
All these things are a joy not a burden once they start working for you