www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Safety strategies

reply bearophile <bearophileHUGS lycos.com> writes:
This is one of the most interesting CS ideas I've found in the past month, here
I have started to understand rationally why dynamic languages like Python may
generally be not significantly more bug prone than tightly statically typed
languages like ML or D:
http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=126394

Recently in this Reddit thread I have found a third interesting safety strategy:
http://www.reddit.com/r/programming/comments/fdrtz/lisp_atoms_ruby_symbols_erlang_atoms_how_useful/

It's explained more in focus here:
http://stackoverflow.com/questions/3399956/pattern-matching-f-vs-erlang

Erlang software systems are among the most reliable ones, yet it refuses the

many more). It's really a different strategy to create reliable systems. 

--------------

Some mixed quotations from that stackoverflow and reddit discussions:

When you run into a constraint that needs to change you change the types. If
there is a case I didn't consider I add a new value to a sum type or enum or
class or whatever. In a pattern matching language this will break things but
the compiler will handily point out exactly which patterns no longer make any
sense or which ones are now non-exhaustive. Fixing it straight forward.


You mention the value of the compiler pointing out non-exhaustive pattern
matching. It might interest you to know that in Erlang that is a no-no. Your
pattern matching should not handle cases you do not know how to deal with in a
"let it crash" manner. Actually Joe Armstrong (Erlang's creator) puts it as let
some other process fix the error. The idea is not unlike the idea common in
exception handling that you shouldn't catch all exceptions but rather those
that you can handle.


Crash here doesn't mean bring down the program. In Erlang, a program typically
consists of a number of processes, interacting via message passing. If a
process crashes then another process handles that event (oversimplified). It
may elect to respawn the process crashed and/or deal with the error in whatever
way it sees fit. It may also simply die as well, and then its supervisor
handles the result. As I said, the nearest thing to this is other languages is
exception handling.

The whole point, as it is the point in exception handling, is that the process
or function should not be programmed that defensively. Let's have an example.


let testColor c =
    match c with
    | Black -> 1
    | White -> 0
    | Other -> failwith "unexpected color"

an almost equivalent Erlang code is

case c of
    black -> 1;
    white -> 0
end;


me to have exhaustive pattern matching. In Erlang it doesn't. In fact, Erlang
encourages me not to fill in a handler for all other cases where the color is
not black or white.

Now the results:

On the other hand, because I was forced to do what is essentially error
handling as early as possible I might get it wrong. In the example, I returned
a generic error "unexpected color" which may or may not be true (in this case
copied from here I am using an active pattern and the error might be anything
else in the pattern function). In short, I am losing information because I had
to handle the potential error early. This is the same argument in exception
handling. You don't catch an exception which you do not know how to handle; you
let it go up the stack.
- In Erlang, if a colour is not matched then the pattern matching raises a
badmatch error. This can be handled at the appropriate level in the function
stack or the process hierarchy.

correctness. Depending on whether you think this is an important enough issue,
you might prefer that.

I have worked with both. It really depends on the whole approach you are using.
Erlang has a very impressive pattern matching and it is non-exhaustive, because
the whole model of fault handling is different from the ML approach where a
fault is a "world collapses" type of event. Armstrong's PhD thesis was "Making
reliable distributed systems in the presence of software errors". The ML
approach is to not have software errors.

The point of the Erlang philosophy is not to produce bad code that always
crashes. Let it crash means let some other process fix the error. Instead of
writing the function so that it can handle all possible cases, let the caller
(for example) handle the bad cases which are thrown automatically. For those
with Java background, it is like the difference between having a language with
checked exceptions which must declare everything it will possibly return with
every possible exception, and having a language in which functions may raise
exceptions that are not explicitly declared.



attention to the warning, is that it makes it easy to refactor by extending
your datatype, because the compiler will then warn you about code you haven't
yet updated with the new case.

-------------------

Compared to ML languages D is less safe, because it's closer to C and its
unsafe nature. Yet D looks designed more toward the kind of safety used by ML
languages instead of Erlang or Python kinds of safety (D1 was a bit closer to
Python-style safety). Is it possible to add more Erlang-style safety to D2?

Bye,
bearophile
Feb 06 2011
parent Ulrik Mikaelsson <ulrik.mikaelsson gmail.com> writes:
Interesting idea, especially when you start considering how software
might survive errors in dependent systems, I.E. hardware, networking,
or software components outside the control of the compiler.

It sounds like the Erlang approach is far more likely to survive
spurious bitflips, power-fluctuations and others things we all prefer
to pretend don't exist.

2011/2/6 bearophile <bearophileHUGS lycos.com>:
 This is one of the most interesting CS ideas I've found in the past month=
, here I have started to understand rationally why dynamic languages like P= ython may generally be not significantly more bug prone than tightly static= ally typed languages like ML or D:
 http://www.digitalmars.com/webnews/newsgroups.php?art_group=3Ddigitalmars=
.D&article_id=3D126394
 Recently in this Reddit thread I have found a third interesting safety st=
rategy:
 http://www.reddit.com/r/programming/comments/fdrtz/lisp_atoms_ruby_symbol=
s_erlang_atoms_how_useful/
 It's explained more in focus here:
 http://stackoverflow.com/questions/3399956/pattern-matching-f-vs-erlang

 Erlang software systems are among the most reliable ones, yet it refuses =
the static safety used by ML-class languages (like SML, Haskell, ATS, OCaML= stems.
 --------------

 Some mixed quotations from that stackoverflow and reddit discussions:

 When you run into a constraint that needs to change you change the types.=
If there is a case I didn't consider I add a new value to a sum type or en= um or class or whatever. In a pattern matching language this will break thi= ngs but the compiler will handily point out exactly which patterns no longe= r make any sense or which ones are now non-exhaustive. Fixing it straight f= orward.
 You mention the value of the compiler pointing out non-exhaustive pattern=
matching. It might interest you to know that in Erlang that is a no-no. Yo= ur pattern matching should not handle cases you do not know how to deal wit= h in a "let it crash" manner. Actually Joe Armstrong (Erlang's creator) put= s it as let some other process fix the error. The idea is not unlike the id= ea common in exception handling that you shouldn't catch all exceptions but= rather those that you can handle.
 Crash here doesn't mean bring down the program. In Erlang, a program typi=
cally consists of a number of processes, interacting via message passing. I= f a process crashes then another process handles that event (oversimplified= ). It may elect to respawn the process crashed and/or deal with the error i= n whatever way it sees fit. It may also simply die as well, and then its su= pervisor handles the result. As I said, the nearest thing to this is other = languages is exception handling.
 The whole point, as it is the point in exception handling, is that the pr=
ocess or function should not be programmed that defensively. Let's have an =
 let testColor c =3D
 =C2=A0 =C2=A0match c with
 =C2=A0 =C2=A0| Black -> 1
 =C2=A0 =C2=A0| White -> 0
 =C2=A0 =C2=A0| Other -> failwith "unexpected color"

 an almost equivalent Erlang code is

 case c of
 =C2=A0 =C2=A0black -> 1;
 =C2=A0 =C2=A0white -> 0
 end;


forces me to have exhaustive pattern matching. In Erlang it doesn't. In fac= t, Erlang encourages me not to fill in a handler for all other cases where = the color is not black or white.
 Now the results:

hat. On the other hand, because I was forced to do what is essentially erro= r handling as early as possible I might get it wrong. In the example, I ret= urned a generic error "unexpected color" which may or may not be true (in t= his case copied from here I am using an active pattern and the error might = be anything else in the pattern function). In short, I am losing informatio= n because I had to handle the potential error early. This is the same argum= ent in exception handling. You don't catch an exception which you do not kn= ow how to handle; you let it go up the stack.
 - In Erlang, if a colour is not matched then the pattern matching raises =
a badmatch error. This can be handled at the appropriate level in the funct= ion stack or the process hierarchy.

f correctness. Depending on whether you think this is an important enough i= ssue, you might prefer that.
 I have worked with both. It really depends on the whole approach you are =
using. Erlang has a very impressive pattern matching and it is non-exhausti= ve, because the whole model of fault handling is different from the ML appr= oach where a fault is a "world collapses" type of event. Armstrong's PhD th= esis was "Making reliable distributed systems in the presence of software e= rrors". The ML approach is to not have software errors.
 The point of the Erlang philosophy is not to produce bad code that always=
crashes. Let it crash means let some other process fix the error. Instead = of writing the function so that it can handle all possible cases, let the c= aller (for example) handle the bad cases which are thrown automatically. Fo= r those with Java background, it is like the difference between having a la= nguage with checked exceptions which must declare everything it will possib= ly return with every possible exception, and having a language in which fun= ctions may raise exceptions that are not explicitly declared.

paying attention to the warning, is that it makes it easy to refactor by ex= tending your datatype, because the compiler will then warn you about code y= ou haven't yet updated with the new case.
 -------------------

 Compared to ML languages D is less safe, because it's closer to C and its=
unsafe nature. Yet D looks designed more toward the kind of safety used by= ML languages instead of Erlang or Python kinds of safety (D1 was a bit clo= ser to Python-style safety). Is it possible to add more Erlang-style safety= to D2?
 Bye,
 bearophile
Feb 06 2011