<html><body><div style="color:#000; background-color:#fff; font-family:HelveticaNeue, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif;font-size:10pt"><div class="" style=""><span class="" style="">"</span><span style="font-family: monospace; font-size: 10pt;" class="">This is a somewhat controversial view that will probably upset some</span></div><span style="font-family: monospace;" class="">people, but _statistically_ creating and enforcing axiomatic</span><br style="font-family: monospace;" class=""><span style="font-family: monospace;" class="">abstractions is the only thing that qualifies as a type system. Dynamic</span><br style="font-family: monospace;" class=""><span style="font-family: monospace;" class="">typing just isn't typing (going even further, which is even more</span><br style="font-family: monospace;" class=""><span style="font-family: monospace;" class="">controversial (but accurate IMO), it is
uni-typing)."</span><div><br></div><div><br style="font-family: monospace;" class=""><div class="" style=""><span class="" style="">Static typing people as a rule want to reject dynamic typing from consideration, usually reserving "typing" for their own work. (Do I detect a hint of Bob Harper in your text above?) But dynamic typing does however, for example, work well in Milner's sense of "does not go wrong", which is sufficient to many of us. There are other advantages too, like trivially handling incomplete or changing programs. Or for that matter allowing programs that are correct and do not go wrong, yet still are rejected by the type inference algorithm.</span></div><div class="" style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;"><span class="" style=""><br></span></div><div class="" style="color: rgb(0, 0, 0);
font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;"><span class="" style="">In the larger scheme of things, we also have to consider other issues than typing purity tests. While there are many aspects to this, two points have remained with me. First, it's a family of restrictive disciplines combined with various inference algorithms that buys you some assurances of correctness, but utterly ignores other potentially important issues, including partial correctness. Do the gains outweigh the costs? It's a trade off. Second, in some sense, the preference for static vs dynamic seems more than anything else to be an issue of personality (perhaps reinforced by upbringing). For example, some love it that the type checker finds their "tons of errors" (as they often put it), while others prefer the shortcuts available when there are less restrictions,
like having PIDs instead of typed channels.</span></div><div class="" style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;"><span class="" style=""><br></span></div><div class="" style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;"><span class="" style="">And since this same discussion has been recurring for me since the early 90s, with no apparent progress, and since this is not the mailing list to rehash these old issues, with that I'll try to leave the bait and unhook myself ;-)</span></div><div style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;"
class=""><span class="" style=""><br class="" style=""></span></div><div style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;" class=""><span class="" style="">Best,</span></div><div style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;" class=""><span class="" style="">Thomas</span></div><div style="color: rgb(0, 0, 0); font-size: 13px; font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans-serif; font-style: normal; background-color: transparent;" class=""><span class="" style=""><br class="" style=""></span></div> <div class="qtdSeparateBR"><br><br></div><div class="yahoo_quoted" style="display: block;"> <div style="font-family: HelveticaNeue, Helvetica
Neue, Helvetica, Arial, Lucida Grande, sans-serif; font-size: 10pt;" class=""> <div style="font-family: HelveticaNeue, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif; font-size: 12pt;" class=""> <div dir="ltr" class="" style=""> <font size="2" face="Arial" class="" style=""> On Saturday, July 19, 2014 8:16 PM, Siraaj Khandkar <siraaj@khandkar.net> wrote:<br class="" style=""> </font> </div> <blockquote style="border-left: 2px solid rgb(16, 16, 255); margin-left: 5px; margin-top: 5px; padding-left: 5px;" class=""> <br class="" style=""><br class="" style=""> <div class="" style="">On 07/17/2014 10:29 AM, Fred Hebert wrote:<br class="" style="">> On 07/17, Siraaj Khandkar wrote:<br class="" style="">>> In the face of such ambiguities, Dialyzer really has no choice but to<br class="" style="">>> assume innocence until guilt can be proven with certainty.<br class="" style="">>><br class="" style="">>> When you
say `baz = foo:bar()`, Dialyzer can _try_ to follow the path<br class="" style="">>> and match the expressions, but when you say `baz = Foo:bar()` - the rug<br class="" style="">>> is swept from underneath Dialyzer's feet and (at that call site) it can<br class="" style="">>> go no further than _try_ to find a case where Foo does not result in<br class="" style="">>> being an atom.<br class="" style="">>><br class="" style="">>> So in other words, Dialyzer is not a type checker - it only seeks<br class="" style="">>> _definite_ failure cases in the call graph and sometimes<br class="" style="">>> success-or-failure depends _only_ on runtime state (such as dynamic<br class="" style="">>> references).<br class="" style="">>><br class="" style="">> <br class="" style="">> Someone who knows better about types, type systems, and type checking<br class="" style="">> than me may correct me,
but I believe that Dialyzer still is a type<br class="" style="">> checker.<br class="" style="">> <br class="" style="">> The difference is that it checks a type system that isn't axiomatic<br class="" style="">> (such as Hindley-Milner) -- those that tend to *prove* that there is no<br class="" style="">> type errors in the program, sometimes at the cost of forbidding certain<br class="" style="">> otherwise valid programs.<br class="" style="">> <br class="" style="">> The canonical example for this is is:<br class="" style="">> <br class="" style="">> 'and'(true, true) -> true;<br class="" style="">> 'and'(_, _) -> false.<br class="" style="">> <br class="" style="">> being called as:<br class="" style="">> <br class="" style="">> 'and'(5,6)<br class="" style="">> <br class="" style="">> A type inference for an axiomatic type system might decide that
the<br class="" style="">> 'and'/2 function's signature is <br class="" style="">> <br class="" style="">> -spec 'and'(boolean(), boolean()) -> boolean()'<br class="" style=""><br class="" style=""><br class="" style="">Very interesting point! To explore it, the key question to answer is:<br class="" style="">"What is a type?"<br class="" style=""><br class="" style="">I struggled with that question for sometime, because I noticed that I<br class="" style="">use similar reasoning, of creating building blocks, in languages with<br class="" style="">_and_ without static type enforcement. So one way to think about "type"<br class="" style="">is as a synonym for "abstraction".<br class="" style=""><br class="" style="">Going further, I think the most enlightening definition of "type" was<br class="" style="">given by John Reynolds as: "a syntactic discipline for maintaining<br class="" style="">levels of abstraction." [1]<br
class="" style=""><br class="" style="">So, while related, a type is not the abstraction itself, but a tool for<br class="" style="">enforcing it. More specifically, a _syntactic_ tool, that is - static.<br class="" style=""><br class="" style="">The 'and' example, I think, perfectly demonstrates why the enforcement<br class="" style="">necessarily has to be static - the catch-all case breaks the abstraction<br class="" style="">and by the time it hits runtime - it is too late and there's no<br class="" style="">principled way to prevent it other than adding checks _syntactically_.<br class="" style=""><br class="" style="">This is a somewhat controversial view that will probably upset some<br class="" style="">people, but _statistically_ creating and enforcing axiomatic<br class="" style="">abstractions is the only thing that qualifies as a type system. Dynamic<br class="" style="">typing just isn't typing (going even further, which is even more<br
class="" style="">controversial (but accurate IMO), it is uni-typing).<br class="" style=""><br class="" style=""><br class="" style="">[1]:<br class="" style=""><a href="http://www.cse.chalmers.se/edu/year/2010/course/DAT140_Types/Reynolds_typesabpara.pdf" target="_blank" class="" style="">http://www.cse.chalmers.se/edu/year/2010/course/DAT140_Types/Reynolds_typesabpara.pdf</a><br class="" style=""><br class="" style="">> <br class="" style="">> and therefore ban the call. Dialyzer can in fact ban this one if you<br class="" style="">> explicitly write that signature down, but won't infer this. If you have<br class="" style="">> no signature and call `$ typer <mod>`, the output is:<br class="" style="">> <br class="" style="">> -spec 'and'(_,_) -> boolean().<br class="" style=""><br class="" style="">And this is the key point that makes me feel that Dialyzer is not quite<br class="" style="">a type checker.
Except... it DOES give you a way to syntactically define<br class="" style="">and enforce abstraction, so it DOES do type checking, but _optionally_<br class="" style="">and _incompletely_ (as in the case of dynamic references discussed<br class="" style="">earlier). So what to do? :)<br class="" style=""><br class="" style="">IMO it is an awesome static analysis tool that I cannot imagine using<br class="" style="">Erlang without, but because of the unavoidable typing holes - it cannot<br class="" style="">be thought of as a full-blown type checker in my mind.<br class="" style=""><br class="" style=""><br class="" style="">> Erlang's semantics allow that call, and that is the correct type<br class="" style="">> signature that will correspond to its behavior at runtime.<br class="" style=""><br class="" style="">Yes, Dialyzer is true to Erlang semantics, but Erlang semantics is<br class="" style="">exactly what creates the abstraction holes in
the first place.<br class="" style=""><br class="" style=""><br class="" style=""><br class="" style="">> So the reason for this is that Dialyzer type checks on a concept called<br class="" style="">> 'success typing'. To simplify a lot (maybe too much), an axiomatic type<br class="" style="">> checker will build its list of what is valid or not by starting with a<br class="" style="">> null set (nothing is valid), and expanding it as it finds more<br class="" style="">> information in your program. This leads to denying programs that are:<br class="" style="">> <br class="" style="">> 1. wrong all of the time for an execution path<br class="" style="">> 2. wrong some of the time for an execution path (and therefore right<br class="" style="">> some of the time)<br class="" style="">> 3. do not provide sufficient information to know something will always<br class="" style="">> be right (false
negative)<br class="" style="">> <br class="" style="">> Success typing basically works the other way around. It starts assuming<br class="" style="">> that everything is good, and then restricts what it thinks is valid as<br class="" style="">> it finds more information. This leads to denying programs that are:<br class="" style="">> <br class="" style="">> 1. wrong all the time for an execution path<br class="" style="">> <br class="" style="">> Programs that may or may not fail, either due to lack of information or<br class="" style="">> succeeding some of the time (or a combination of both) will be accepted<br class="" style="">> by Dialyzer.<br class="" style="">> <br class="" style="">> Dialyzer still definitely checks your types, does analysis, does<br class="" style="">> inference, etc. It just analyzes them differently to give you a<br class="" style="">> different diagnostic, but for all intents and
purposes, it is a type<br class="" style="">> checker (on top of being able to find other discrepancies in your<br class="" style="">> programs).<br class="" style="">_______________________________________________<br class="" style="">erlang-questions mailing list<br class="" style=""><a ymailto="mailto:erlang-questions@erlang.org" href="mailto:erlang-questions@erlang.org" class="" style="">erlang-questions@erlang.org</a><br class="" style=""><a href="http://erlang.org/mailman/listinfo/erlang-questions" target="_blank" class="" style="">http://erlang.org/mailman/listinfo/erlang-questions</a><br class="" style=""><br class="" style=""><br class="" style=""></div> </blockquote> </div> </div> </div> </div></div></body></html>