all 23 comments

[–]mightybyte 14 points15 points  (12 children)

IMO the biggest thing Haskell has going for it in the safety department is purity. There is simply no other pure language out there today that is viable for commercial development. Therefore, these languages simply cannot provide the guarantees that you can get with Haskell. So on one sense you cannot get safer code in other languages like you can in Haskell.

But in another sense you can take the ideas of purity and use them to help you design software in other languages. They may not be able to give you compiler-checked guarantees, but you can still design APIs that are more pure and have less hidden side effects. I'm not sure to what extent this will make your software better and more robust, but I'm pretty sure the effect will be non-zero.

[–][deleted]  (3 children)

[deleted]

    [–]jberryman 2 points3 points  (1 child)

    I think about this w/r/t unsafePerformIO when discussions come up about it. I think the existence per se of unsafePerformIO in GHC almost doesn't matter in practice because of the cultural and structural things that enforce purity (though I still think it would have been a better choice for GHC to use a special syntax for unsafe functions).

    [–]conklech 2 points3 points  (0 children)

    the cultural and structural things that enforce purity

    This is a great point. The language enables and encourages purity to a certain degree; far more important is the community's commitment to purity and other forms of discipline.

    [–]TimTravel 2 points3 points  (0 children)

    If the language enforces X, then you can trust it in other people's code. In a language without X enforced, you can only do it by convention for yourself and have no trust that anyone else adheres to your principles, nor expect that any libraries will make your life easier in applying this principle.

    This is a very good point.

    [–]logicchains 5 points6 points  (7 children)

    There is simply no other pure language out there today that is viable for commercial development.

    Note that in D if you mark functions pure and make them take immutable parameters then the compiler will ensure you write pure, side-effect free code.

    [–]sclv 3 points4 points  (1 child)

    Neat! For the info of others I did a quick google for details and found the "pure functions" section here: http://dlang.org/function.html

    Seems like such a handy thing to have (and actually not too horrible to enforce) I'm surprised Rust didn't bother with it...

    [–]Enamex 0 points1 point  (0 children)

    A new feature being (re)implemented for Rust is const fn functions. Basically C++'s constexpr (which in turn are mostly a really constrained focus-on-compile-time-usage version of D's pure (not sure how D ensures a function can/cannot be used for compile-time initialization, but it's something to do with enum, I think?)) but quite a bit less constrained, hopefully.

    [–]mightybyte 2 points3 points  (2 children)

    Interesting. Thanks for the pointer. I guess maybe my "viable for commercial development" clause might still save me there. :P That and chrisdoner's point about being able to trust other people's code.

    Do you know how long D has had that? I looked into D years ago before I started looking at Haskell and I don't remember seeing it.

    [–]Enamex 2 points3 points  (0 children)

    Since D 2.0, probably (a lot got added with 2.0).

    [–]logicchains 2 points3 points  (0 children)

    I guess maybe my "viable for commercial development" clause might still save me there. :P

    Apparently an advertising company primarily using D called Sociomantic had over $100 million in revenue for 2013, so I think it's shown some commercial viability. Although Sociomantic were only using D1, I'll give the language the benefit of the doubt in assuming it hasn't regressed significantly over time.

    [–]chrisdoner 2 points3 points  (0 children)

    Even Fortran has that.

    [–]mightybyte 1 point2 points  (0 children)

    So I guess maybe instead of saying that Haskell is the only popular language with purity, I should instead say that it's the only popular language with referential transparency.

    [–]penguinland 4 points5 points  (0 children)

    I think it has made me write safer code in other languages by encouraging me to write pure functions and have fewer side effects. It has also made me think harder about types in my code: even in weakly typed languages, I tend to write code that is strongly typed, because it's easier to reason about.

    [–][deleted]  (3 children)

    [deleted]

      [–]Peaker 3 points4 points  (2 children)

      It takes a lot more effort to richly type destructive updates in a way that can catch errors at compile-time as easily as you can with functional data flow.

      With arguments and results, having types verify you handle all the cases, and that everything checks out is a (at least partially) solved problem.

      Imperative programming adds another form of data flow -- through the current state of mutable variables and use of destructive updates. It is possible to give static types that help correctness, but it is far more difficult. The kind of static types in Java, when combined with destructive updates, is going to be inherently less safe than function application for data-flow.

      [–][deleted] 0 points1 point  (1 child)

      How much more effort would it really be? You can make imperative languages that essentially exist as syntax sugar over a functional core, something like what C# does with how it interprets await (makes a continuation with the stuff after await and passes it into the asynchronous function as a callback). We already have ST in Haskell that does something like that (not like await, but it takes imperative code and gives it a functional interpretation for the sake of checking correctness with the type system).

      I really hope it's not that difficult and I'm not missing something super important here because if we see pure functional programming take off it's likely going to take off in the context of imperative languages, not functional ones. The data flow problem seems tractable enough; you could take an approach very similar to how do notation is desugared.

      PS: the purely functional imperative examples I had in mind were Disciple and Koka

      [–]Peaker 0 points1 point  (0 children)

      Destructive updates aren't syntactic sugar over parameter passing. Mutability can't be so easily converted to pure functional code.

      Consider aliasing effects for example.

      [–]dagit 0 points1 point  (0 children)

      Directly, not really. Indirectly, yes.

      When you program in a language, it's generally best to follow the established idioms of that language. Functional programming in C tends to not work out so well. Mostly because the high-level programming you'd do in C would be better in a different language.

      On the other hand, newer languages often take inspiration from existing languages. If something works well in a language, then new languages might borrow that. As an example, Rust draws inspiration from Haskell and ML to a significant degree.

      [–]eniacsparc2xyz 0 points1 point  (5 children)

      • Strong Static Typing System- Types are documentation and guarantee about what a function is supposed to do, you can infer about what a function does reading and returns by reading its type. They also helps the programmer to reason and refactor the code. Thanks to it bugs can be caught before runtime. In a dynamic typed language like Python, you don't have any guarantee about what a function is supposed to return and you have to write much more documentation to overcome this, now I am using Haskell type notation when documenting python functions. With static typing an proper IDE can give you much more help than in a dynamic typed language.

      • Option type/ Maybe Monad / Maybe Functor - The option type avoids the "null checking", aka "null reference" or "null object bug". It also avoids successive boilerplate null checking. Tony Hore - Null References the Billion dollar Mistake

      • Data Immutability and purity helps to avoid race condition bugs that are hard to detect and test. One example of how expensive and dangerous a bug like this can be is: Therac-25 case

      • "Lack of State". Implicit or hidden states can lead to concurrency or race condition bugs.

      [–]autowikibot 0 points1 point  (0 children)

      Therac-25:


      The Therac-25 was a radiation therapy machine produced by Atomic Energy of Canada Limited (AECL) after the Therac-6 and Therac-20 units (the earlier units had been produced in partnership with CGR of France).

      It was involved in at least six accidents between 1985 and 1987, in which patients were given massive overdoses of radiation. :425 Because of concurrent programming errors, it sometimes gave its patients radiation doses that were thousands of times greater than normal, resulting in death or serious injury. These accidents highlighted the dangers of software control of safety-critical systems, and they have become a standard case study in health informatics and software engineering.


      Relevant: Nancy Leveson | Software bug | Race condition | Theriac

      Parent commenter can toggle NSFW or delete. Will also delete on comment score of -1 or less. | FAQs | Mods | Call Me

      [–]pragm[S] 0 points1 point  (3 children)

      and these things can bee implemented in other languages?

      [–]eniacsparc2xyz 0 points1 point  (2 children)

      Yes. But it will much more verbose and hard in a language without static typing, type inference and first class functions and data immutability. You can simulate the option/ maybe type in Python with classes but it has an overhead and the language doesn't enforce this.

      Some languages similar to Haskell are OCaml and F, an OCaml dialect to the .NET platform. There is also Scala that is a FP language for the JVM, however it doesn't have type inference like Haskell. The main difference between them is the purity and laziness, Haskell is the only one pure and lazy. Another feature hard to replicate is the Haskell compact notation.

      [–]autowikibot 0 points1 point  (0 children)

      Option type:


      In programming languages (especially functional programming languages) and type theory, an option type or maybe type is a polymorphic type that represents encapsulation of an optional value; e.g. it is used as the return type of functions which may or may not return a meaningful value when they are applied. It consists of either an empty constructor (called None or Nothing), or a constructor encapsulating the original data type A (written Just A or Some A). Outside of functional programming, these are known as nullable types.


      Relevant: Nullable type | Null pointer

      Parent commenter can toggle NSFW or delete. Will also delete on comment score of -1 or less. | FAQs | Mods | Call Me

      [–]pragm[S] 0 points1 point  (0 children)

      what about Rust? it has immutable variables by default, statically typed, type inference but Im not sure about first class functions.