1. 33
  1.  

  2. 9

    I don’t think most people refer to languages like Lisp, Clojure, or Erlang as “scripting” languages. They’re pretty well known for building large scale systems.

    It’s also worth noting type hints when comparing performance. For example, Clojure provides type hints for getting predictable performance. I’d argue that types in C are basically type hints as well, since the compiler does very little to enforce them. The reality is that majority of the code in any given application doesn’t run all that often. In most domains you can profile the app and add type hints in sections that need to be more performant If and when you hit performance issues. My experience is that this only becomes an issue in specific domains like graphics or system level code like drivers.

    When it comes to providing documentation I personally find runtime contracts such as Racket Contracts or Clojure Spec provide much more meaningful documentation than types. Types tend to focus on on demonstrating that code is self-consistent. Meanwhile, a contract is a specification for what the code is meant to be doing.

    As the speaker notes, we don’t really have any hard data on whether one approach is objectively better than the other. Outside that we’re left with anecdotal evidence that we collect and personal preference. It’s also entirely possible that the language doesn’t actually play a major role in software quality. Perhaps, process, developer skill, testing practices, and so on are the dominant factors. So, the right language inevitably becomes the one that the team enjoys working with.

    1. 5

      Interesting example given in haskell about type system complexity:

      length (1, 2)  --> 1    wut?
      length (1, 2, 3)  --> *incomprehensible error* 
      
      1. 4

        FWIW, this is all caused by a Foldable ((,) a) instance that is already quite controversial in the Haskell community1. It isn’t the only controversial Foldable instance either - did you know there is a Foldable (Either a)2?

        The main friction is that removing instances that were previously there may cause code that currently compiles to stop compiling. One suggestion I personally like is to have a compiler warning for the pathological cases3.

        1. 3
          <interactive>:6:1: error:
              • No instance for (Foldable ((,,) t0 t1))
                  arising from a use of ‘length’
          

          — what’s incomprehensible about this?

          1. 4

            Hmm well this is what I got, which is pretty incomprehensible to someone starting out with haskell I think.

            <interactive>:4:1: error:
                • No instance for (Foldable ((,,) t0 t1))
                    arising from a use of ‘length’
                • In the expression: length (1, 2, 3)
                  In an equation for ‘it’: it = length (1, 2, 3)
            <interactive>:4:9: error:
                • Ambiguous type variable ‘t0’ arising from the literal ‘1’
                  prevents the constraint ‘(Num t0)’ from being solved.
                  Probable fix: use a type annotation to specify what ‘t0’ should be.
                  These potential instances exist:
                    instance Num Integer -- Defined in ‘GHC.Num’
                    instance Num Double -- Defined in ‘GHC.Float’
                    instance Num Float -- Defined in ‘GHC.Float’
                    ...plus two others
                    ...plus three instances involving out-of-scope types
                    (use -fprint-potential-instances to see them all)
                • In the expression: 1
                  In the first argument of ‘length’, namely ‘(1, 2, 3)’
                  In the expression: length (1, 2, 3)
            <interactive>:4:11: error:
                • Ambiguous type variable ‘t1’ arising from the literal ‘2’
                  prevents the constraint ‘(Num t1)’ from being solved.
                  Probable fix: use a type annotation to specify what ‘t1’ should be.
                  These potential instances exist:
                    instance Num Integer -- Defined in ‘GHC.Num’
                    instance Num Double -- Defined in ‘GHC.Float’
                    instance Num Float -- Defined in ‘GHC.Float’
                    ...plus two others
                    ...plus three instances involving out-of-scope types
                    (use -fprint-potential-instances to see them all)
                • In the expression: 2
                  In the first argument of ‘length’, namely ‘(1, 2, 3)’
                  In the expression: length (1, 2, 3)
            
            1. 5

              Yeah, sadly GHC error messages are pointlessly hard to read.

              The first should just say “There is no instance of Foldable for (a,b,c)”.

              The other two are very standard messages you’ll see all the time. You don’t even need to read them. Actually, GHC should be taught to simply not produce them in cases like this. They’re a consequence of the previous error. GHC should be printing something like “I don’t know what type to assign to literal ‘1’ because there are no constraints on it. If there are other type errors fixing them may add additional constraints. If not, annotate the literal with a type like (1::Int)”.

              Basically, 1, doesn’t mean much. It could be an integer, a double, a km/s, a price, the unit vector, etc. As long as the type has a Num instance available 1 can be converted to it. Since the type controls the behavior of that object you need to know what it is before you can run the code.

              1. 3

                I agree that the amount of information that GHC outputs is overwhelming (the GHC typechecker looks to me like a complicated solver environment that might be better served by its own interactive mode and type-level debugger, Coq-style). On the other hand, the source of the error is clearly written in two lines at the start of the message, that’s why it’s hardly “incomprehensible”.

                1. 2

                  To me this looks like the unreadable messages from g++. You just have to learn to read through it!

                2. 3

                  For someone new to Haskell, the notion that – were you to invest the time to learn, this would be a readable message – is hard to fathom. I think that sort of imagination barrier is why generally things with steep learning curves are less popular.

                  1. 9

                    There’s nothing Haskell-specific about bad error messages. And it’s nothing to do with imagination or the learning curve of Haskell. It’s just the obtuse way that GHC error messages are written and the lack of interest to make them better.

                    If this message said “(,,) is not an instance of Foldable” no one would find it difficult to comprehend.

                    That being said. The tuple instance of Foldable is really horrible and confusing. Either length shouldn’t be in foldable and we should use some other concept (slotness or something) or that instance shouldn’t be there by default. But this has nothing to do with Haskell or type systems. It’s just as if Java had created a terrible misnamed class that gave you the wrong answer to an obvious query.