16 ms·
Rich comes down hard here on statically typed languages, but before the static typers get too offended, his main attack is on the overuse of ADTs/classes to bui
by wellpast 9y ago
Rich comes down hard here on statically typed languages, but before the static typers get too offended, his main attack is on the overuse of ADTs/classes to build information processing systems (i.e., what a majority of us industry programmers are doing; he takes pains to define this arena...see the slides/discussion on what Rich calls "Situated Programs").
So before the static vs dynamic typing debate gets too heated up here, I think we should focus on this point first[1].
For those of you wary of his point here, I think it's worthwhile to go through an exercise, if you have the time to explore this. Write a simple information processing app using two different paradigms:
- Write it using a statically typed language and a relational database.
- Then write the same app using some NoSQL store and avoid using ADTs (prefer using just maps of facts). Ideally do this in a dynamic language so the ergonomics are better for you.
And then ask yourself: Which one of these felt safer? More familiar? Which one of these offered more freedom, choice, and speed?
1. I do think that once you come to terms with the problems of ADTs, you are on your way to not needing all the static type verification, but leave that to later.
- flavio81 9y ago>I do think that once you come to terms with the problems of ADTs, you are on your way to not needing all the static type verification, but leave that to later. Excellent thought. Also, as a side note, people that criticize Clojure for its lack of static type enforcement, forget the fact that Rich Hickey had good previous experience in C++, so it's not as if he hadn't tried a statically-typed language before.
- throwaway7645 9y agoC++, Java, and C# if I recall correctly
- pkd 9y agoWhile that is true, it's not like C++ and Java are the torchbearers of static typing. Much better type systems exist than those of C++ and Java and basing your worldview of static typing just on the experience with these two is shortsighted.
- james-mcelwain 9y agoRight, but most of the statically typed code in the world is written in C++, Java, etc. If you're presenting Clojure to your organization, the choice isn't going to be Clojure vs Haskell/Idris, it's going to be Clojure vs Java. The sort of boosters for static typing in this domain are the AbstractSingletonProxyFactoryBean people. I think defenders of static typing have at least some burden to defend "actual existing type systems" rather than immediately falling back to "well, in Haskell..."
- deleted 9y ago[deleted]
- willtim 9y agoWhat makes you assume Haskell is somehow more niche than Clojure? I would say it depends on the domain. Haskell is certainly more mature (~30 years) and has a lot more tutorials and literature.
- hnbroseph 9y ago> Haskell is certainly more mature (~30 years) and has a lot more tutorials and literature. and yet, still, nobody outside the gated community has any idea wtf a monad is. :(
- hepta 9y agoI do agree that there are problems where the "maps of facts" approach is better suited than ADTs. I'm not sure if those are the majority of problems we're solving. You can still do all that in a typed language, using dictionaries. You can be as precise as you want. In some sense you lose that without a type-checker. I only have my experience (which is about 1/4 of his) to lean on. And I've only had problems when protocols are not well understood by all parties, never the opposite. Talking in the level of ADTs (or some representation that is equally precise) tends to either clear things up, or uncover problems that were not obvious in informal discussion.
- wellpast 9y ago> Talking in the level of ADTs (or some representation that is equally precise) I will argue that ADTs offer no more precision than first-class properties and first-class properties are much more aligned with human beings natural way of thinking. I.e., "name" is semantically strong/precise, I don't need to enslave it to a Person class. I can give a Cat a name, a building a name, etc. ADTs are trying to bundle properties together when those properties should/could have strong enough semantics on their own and be much more "composable" (RH's term) and freer to use.
- hepta 9y agoMaybe we have to dig into the specifics: there's a lot of things that can be done with Name, regardless of where the name belongs, is that what you mean? If so, most typed languages let you say that Person can be a thing with a Name. I don't have Clojure experience so we might be talking past each other here.
- wellpast 9y agoWhat resonates most with me is that traditionally ADTs make the properties second-class citizen to the ADT/class. First-class properties are strong enough semantics and bundling them together in an ADT is almost always introducing coupling and rigidity with no real benefit. Why do we need the Person class? Why do we need to taxonomize like that? The answer is we don't. All the Person class brings to the table is straight-jacketing and a false sense of order and security.
- mikebenfield 9y agoActually, this talk mostly convinced me that dynamic typing is not just an anachronism and really is the right choice for some domains. Then again, now I wonder if statically typed languages could get the benefits Hickey talks about just by having convenient Map and Keyword types like in Clojure and using them where appropriate.
- wellpast 9y agoAn interesting thought I got out of this talk is the reminder that most (nearly all?) statically typed languages are really just "mandated type verification" (not RH's terminology, btw). But, in the talk, Rich isn't anti- type verification. He says, like any tool, type verification should be used consciously, it should be a la carte (his term); that is what clojure.spec is all about, as I understand it.
- benfle 9y agoI think Rich is talking more about data structures than data abstractions here. In particular, he's saying that he favors sound data models (RDF, datalog, relational) to manipulate information in our programs over specific data structures. To me it is related to Alan Perlis's saying on the power you get from uniformity: "It is better to have 100 functions operate on one data structure than 10 functions on 10 data structures." I totally agree with him on this point and I also agree that for some of us a lot of our programs are about manipulating static information structures. But let's not reduce programming to that.
- wellpast 9y agoAren't statically typed languages "sound models"? Aren't ADTs a form of data structure? I think his point is much more in the realm of abstraction. RH always seems to be trying to minimize the delta between thinking and coding/problem-solving. ADTs are in most cases cumbersome. Static languages introduce more impedance and coupling than benefit to the industry business problems we're solving via code. These are arguments against certain attempts at abstraction, it seems to me. But I may be missing what you're saying.
- pklausler 9y agoBut at its best (as in Haskell), static typing just means that the compiler is enforcing the requirements of your interfaces. Why would you not want to know about these bugs immediately and fix them early in the development process when it's cheap to do? Why wouldn't you want the compiler recheck everything automatically every time you change your interfaces? Everybody's always fixing bugs. Static typing makes it more likely that the bugs you're working on are closer to the problem domain, instead of being crap work that should have been caught at compilation time with better languages and compilers.
- wellpast 9y ago> Why would you not want to know about these bugs immediately and fix them early in the development process? That's a good question. But enforcing your codebase to be a Rubix cube you have to twist and turn until the static type checker says Yes is not trivial. Its a tax. The real question is whether that tax is worth it when your goal is purely business delivery and not something else (eg, intellectual stimulation). Is it? Writing unit tests and code review are other means to root out bugs. But they also come with a tax. When are they worth the tax and when are they not worth the tax? In some cases we judge they are. In other cases not. A statically typed language typically asks us to turn off our brain and apply type verification everywhere. In this way, statically typed languages wield type verification more like a religion than a tool.
- pklausler 9y agoYou can fix your interface bugs early in the development process with the aid of a compiler, or you can fix them later manually at much greater expense. When the "tax" is so much cheaper than the consequences, not paying the tax is crazy.
- wellpast 9y agoBut "interface bugs" are the least of our problems. As evidenced by most bug queues that I've peeked at.
- tensor 9y agoCan I just touch on the relational vs nosql comment? I'd like to point out that data almost always has a schema, and it's almost always relational. Most of the time when people use nosql with map of maps, they are simply refusing to recognize and formalize the structure of the data that is already there. This absolutely leads to errors and performance problems. There is a small class of problems where specialized databases do excel, but it's definitely not the common case.
- systems 9y ago"and it's almost always relational" this is a bit backward, and not very accurate there is no such thing as relational data and non relational data, its the other way around, there is a relational model, which promises to model any set of related data so you can fit, any set of related data into a relational model, and this is a feature of the model, not the data the key value, of relational models, is the promise of integrity, once you model your data into a relational model, and then only access your data through it, you are guaranteed integrity the key issue with relational models is that they are static, so if your data change, your model need to change, and once your model changed, now you have to deal with two models .. and this is where things start to get hard .. and this is when people start to use other models .. it is not because they cannot fit their data into a relational model anymore, its because they dont want or dont know how to deal with two relational models
- tensor 9y agoYou are conflating two separate things. First, your comment on changing data relates to schema, not the relational model. Using a nosql database where you don't bother writing the schema down certainly means that you don't have to worry about updating your schema as the data changes. But you still need to worry about updating your code, and since you have no schema written down you run the risk of data inconsistency as you write updated code. As for the relational model, you are correct in that it's a model for storing data. However, I will go further and also argue that it can be a property of the data itself. Consider a simple case of users and posts. This data is fundamentally 'relational' in the sense that there are two related items. No matter how you try to store this data, the relationship between users and posts will _always_ be there. You can either recognize it explicitly via the relational model or otherwise, or you can pretend it's not there which is what many people using nosql do. Say you stored users and posts each as maps in a key value store or document store. One key per user and one key per post. Now, imagine getting all the users and their posts. In a relational database you'd do a join. In the nosql scenario you need to do multiple queries. The latter is essentially doing what the relational database is doing, but you are doing it manually via a for loop. In short, what I'm arguing is that relationships in data are a property of the data.
- willtim 9y agoClasses and ADTs are both examples of Nominal typing, but Structural typing would offer a better fit for your example. Structural types can give types to queries without requiring any declaration or naming of the result type. Correctness in terms of the assumed fields can still be verified. Most of the anti-modular and boilerplate criticisms of static types do not consider structural typing, perhaps because industry has yet to discover them.
- christophilus 9y agoTypeScript is structurally typed and is pretty popular. The industry has discovered this. It's still more painful than ClojureScript in many ways (and less painful in other ways). To me, having written a fair bit of both, it's not clear which is best. Both are good. ClojureScript is far more elegant. PureScript is probably the most interesting statically-typed language I've seen in a long time. But for some reason, powerful static typing never seems to gain much traction. So, if I had to choose between the most popular statically typed languages or Clojure, Clojure wins hands down.
- jernfrost 9y agoI am a dynamic language fan but I would actually disagree. I prefer the Julia programming language and there I see a lot of benefits from working with types. I've always had a fascination for LISP, but every time I've tried using it after learning Julia, I've found the lack of type focus limiting and in the way. Types makes it easier to build abstractions. I can write several functions which look the same but act different depending on the type of the arguments. The way in which types get in your way in statically typed languages is pretty much gone in Julia as you can so easily and fluidly deal with types as they are just objects at runtime which you can pass around freely. Julia already has most of the things I like about LISP: everything is an expression, and it is really easy to write macros.
- kbp 9y ago> I've always had a fascination for LISP, but every time I've tried using it after learning Julia, I've found the lack of type focus limiting and in the way. > Types makes it easier to build abstractions. I can write several functions which look the same but act different depending on the type of the arguments. You can do this in Lisp: CL-USER> (defclass my-class () ()) #<STANDARD-CLASS COMMON-LISP-USER::MY-CLASS> CL-USER> (defmethod identify ((mc my-class)) "This is my class") #<STANDARD-METHOD COMMON-LISP-USER::IDENTIFY (MY-CLASS) {1005BDFFB3}> CL-USER> (defmethod identify ((n fixnum)) "This is a fixnum") #<STANDARD-METHOD COMMON-LISP-USER::IDENTIFY (FIXNUM) {1005C984F3}> CL-USER> (identify (make-instance 'my-class)) "This is my class" CL-USER> (identify 3) "This is a fixnum" > The way in which types get in your way in statically typed languages is pretty much gone in Julia as you can so easily and fluidly deal with types as they are just objects at runtime which you can pass around freely. Did you notice how DEFCLASS returned a class object earlier? It's a first class value in Lisp: CL-USER> (defvar *c* (find-class 'my-class)) *C* CL-USER> (type-of *c*) STANDARD-CLASS CL-USER> (make-instance *c*) #<MY-CLASS {1005E38AA3}> CL-USER> (typep (make-instance 'my-class) *c*) T CL-USER> (subtypep (defclass derived-class (my-class) ()) *c*) T