9 ms·
The inductive claim "more likely to be correct" is strongly supported by the evidence gained from enumerating the number of ways the functions could go wrong.
by mightybyte 12y ago
The inductive claim "more likely to be correct" is strongly supported by the evidence gained from enumerating the number of ways the functions could go wrong. Now if we want to expand our domain out from just that function to programs in general, we need an idea of how applicable those ideas are to larger programs. The biggest source of reducing error cases in my example was purity.
Some parts of programs (namely the side effecting parts) can't be expressed as pure functions. So the next piece of evidence we need is an estimate of the percentage of large programs that can be expressed as pure functions. From my experience writing Haskell full-time for the last five years I can tell you that it is very substantial. Even in very impure code you can often factor out lots of small pure operations. I feel very safe in claiming that at least a third of Haskell code can be written with pure functions, and I think it's likely greater than half. (It could be a lot higher, but I'm trying to keep the confidence level fairly high.) You don't have to take my word for this. You can go off and browse through millions of lines of Haskell on [Hackage](http://hackage.haskell.org/packages/ http://hackage.haskell.org/packages/) and see for yourself. It probably wouldn't be too difficult to write an automated script to do this.
Now we've seen that pure functions have a small fraction of the error conditions that impure functions have. And we've seen that maybe half of all the code we write can be expressed that way. That's a pretty dramatic reduction in the number of potential error conditions we might encounter for even complex programs. That is why I think the claim "more likely to be correct" is strongly supported by evidence.
- infraruby 12y ago> It could be a lot higher I'd believe 95% LOC don't perform IO, just like any codebase in any language, though it may be easier in Haskell to identify which LOC those are. But it doesn't matter! The problem could be in the non-IO functions. Take this "scary!" line of code: rm -rf "$STEAMROOT/"* That's a correct IO function (rm -rf) using the result of an incorrect non-IO function ("$STEAMROOT/"*).
- codygman 12y agoI see that as a null error. Using maybe or optional would have solved that problem.
- infraruby 12y ago> Using maybe or optional would have solved that problem. If the code were written correctly then it would be correct!
- the_af 12y agoIt's more like "if the code were written like Haskell programmers write programs, taking full advantage of static types to encode information about function return values, then it would be correct. Forgetting to handle the 'null' option would be detected at compile time."
- infraruby 12y ago> if the code were written like Haskell programmers write programs [...] then it would be correct and if the code were written like (true) bash programmers write programs, taking full advantage of "set -u" and "test", then it would be correct.
- the_af 12y agoThere is a big difference: "set -u" won't reject incorrect bash programs, it will merely stop some kinds of incorrect behaviors by stopping the program and preventing it from causing greater harm. However, the program won't have completed its intended task, therefore remaining incorrect. In contrast, using Maybe to indicate "possibly no value" in Haskell (as it is standard practice; in fact there are no nulls in the language) prevents you from even writing some kinds of incorrect programs in the first place. In this sense, a program written in Haskell is a lot more likely to be correct than one written in bash, because the compiler will force you to consider cases you may have missed in a less safe language (like bash). Of course, neither language guarantees correctness. It's just that one is safer than the other by design.
- mightybyte 12y agoOk, so 50%, 95%--whatever your number is--of the code in Haskell we have established is susceptible to dramatically fewer bugs than any other language out there. How can you possibly claim it doesn't matter? Just because you can construct a situation where it seems to not matter doesn't mean that situation is representative. And oh by the way, we can easily prevent your situation in Haskell as well. safeRm :: SafeFilePath -> IO () Then we create the SafeFilePath data type (it can even be a newtype, which means it will have zero performance overhead) and we can write a smart constructor that makes it impossible to ever have dollar signs, stars, or anything else that might cause this kind of bug. mkSafeRm :: String -> Maybe SafeFilePath Then you hide that stuff away in a module and only expose a safe interface. Now, BOOM, safeRm cannot possibly ever have the bug you described. This is made possible by purity, strong static types, and the module system. Some mainstream languages allow you to partly achieve this, but it usually incurs lots of boilerplate and the lack of immutability means that there will be more holes in whatever solution you can come up with.
- infraruby 12y ago> 95% [...] of the code in Haskell we have established is susceptible to dramatically fewer bugs than any other language out there. No! Haskell has about the same proportion of LOC performing IO as any language. In Haskell, it may be easier to find where the IO code is, using the type system, but that doesn't make any of the code correct. > Then you hide that stuff away in a module and only expose a safe interface. You could do that in any language.
- tome 12y agoI think you are talking past each other. Indeed Haskell does not automatically make code higher quality than any other language. On the other hand, Haskell provides more infrastructure for making code reliable than most (or maybe all) mainstream languages.
- infraruby 12y agoDid you read the thread? :-p > Haskell provides more infrastructure for making code reliable than most (or maybe all) mainstream languages. Is there any empirical evidence that Haskell programs really are more reliable (all else being equal)? Is all that infrastructure actually useful?
- im3w1l 12y agoYou are piecing a bunch of empirical facts together using reasoning, but there are lots of implicit assumptions in your reasoning. One assumption is that reducing error cases, reduces errors. Maybe the other errors increase in prevalence when you reduce error cases? You say that even in impure code you can factor out pure parts. You assume this refactoring doesn't introduce bugs. You talk about the fraction of code that is pure in haskell repos. But we don't know how the amount of impure code compares to amount of impure code in other languages. Maybe it is the same? Just haskellers have some pure code in addition? Finally, we are talking about the bug proneness of haskell, not just an idealized fp-language. Maybe something with haskell causes bugs. There are many candidates. Poor support for debugging has mentioned in another comment. Maybe the libraries are less mature. Maybe less IDE support. Maybe something about the syntax causes bugs. Etc etc. For this reason I think it would be easier to just experimentally verify the hypothesis directly: Does Haskell cause less bugs?
- mightybyte 12y ago> but there are lots of implicit assumptions in your reasoning. Yes, there are assumptions, but now we're getting somewhere. > One assumption is that reducing error cases, reduces errors. Maybe the other errors increase in prevalence when you reduce error cases? I think this is pretty unlikely. If we switch from C to a programming language that makes buffer overflows impossible, we don't expect to see a corresponding increase in, for example, off-by-one errors. After working with a language like Haskell for awhile you start to see that when the compiler tells you about missing a case for Nothing, you don't just sweep it under the rug. You stop and think about that case. I think it's reasonable to assume that when a programmer stops and thinks about a case, he's more likely to get it right. Errors often happen because the programmer neglected to think about a case entirely. > You say that even in impure code you can factor out pure parts. You assume this refactoring doesn't introduce bugs. I'm not talking about refactoring here. I'm talking about writing your code that way from the start, so regressions aren't an issue. As for the question of how many bugs you might write to begin with, see the previous point. > You talk about the fraction of code that is pure in haskell repos. But we don't know how the amount of impure code compares to amount of impure code in other languages. Maybe it is the same? Just haskellers have some pure code in addition? In other languages ALL code is impure. There are no other pure languages in mainstream use today. So then the question becomes whether the pure code written in Haskell performs any useful function as opposed to being just meaningless fluff. It's obvious that this code performs tons of useful operations and every time it is used, we are avoiding the need to have to solve the same problem again. It's very clear what problems are solved by that code, and it's very clear that people are able to reuse it to avoid the work. Therefore, it's absolutely not simply additional cruft. > Finally, we are talking about the bug proneness of haskell, not just an idealized fp-language. Maybe something with haskell causes bugs. None of the points you mention cause bugs. Lack of debugging has nothing to do with causing a bug. It just means that you'll have to go about fixing your bug differently. You can look for counter-arguments all day long, but at some point you're just grasping at straws. > For this reason I think it would be easier to just experimentally verify the hypothesis directly: Does Haskell cause less bugs? It's not easier. Building software is hard and takes a long time. Furthermore, constructing a scientifically valid experiment is even more costly. Most people want to be productive, so they're not going to go to that effort. There is huge variation between people, so these kinds of experiments have to be undertaken like medical studies...i.e. with large n. If you're interested in building complex, real-world systems, you're simply not going to get a large n. Also, Haskell has only become commercially viable in the last 5 or so years, so there hasn't yet been enough time/effort spent to perform these experiments. But even with all these caveats, we do have some experimental evidence. There was a CUFP report from a company that rewrote a substantial groovy app in Haskell [1]. And the result is that yes, Haskell did indeed result in fewer bugs. [1] https://www.youtube.com/watch?v=BveDrw9CwEg#t=1207 https://www.youtube.com/watch?v=BveDrw9CwEg#t=1207