<div dir="ltr"><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Mar 17, 2015 at 2:55 PM, Joe Armstrong <span dir="ltr"><<a href="mailto:erlang@gmail.com" target="_blank">erlang@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div id=":1ml" class="a3s" style="overflow:hidden">The more I think about it the more I come to the conclusion that we<br>
should not be writing polymorphic interfaces to libraries and making<br>
them easy to use. Instead we should be writing minimal libraries<br>
containing only essential features.</div></blockquote></div><br>This has always been my point of view. Several remarks:</div><div class="gmail_extra"><br></div><div class="gmail_extra">* It is by far the solution with the best type-system overlay. Suppose Erlang had a static type system. Then this is essentially the first and simplest solution that comes up if you have static types. The key is how your library composes with other code. And compositionally with "everything" has considerably less structural rigor than "only composable with this or that".</div><div class="gmail_extra"><br></div><div class="gmail_extra">* The library becomes much simpler. If you really want, then having a compatibility layer module is probably better in the long run. Convert in the layer and then pass on the data to the real system. Programmers who know the API can call it directly, avoiding the conversion layer.</div><div class="gmail_extra"><br></div><div class="gmail_extra">* It is transparent. Code calling binary_to_list/1 internally increases the memory resource pressure by a factor of 20. Hiding this in the library gives you less information. You thought it operated on binary data, but it really operates on strings, internally. This tells you a lot about its resource consumption. For instance that it isn't made to be used with binary data several megabytes in size.</div><div class="gmail_extra"><br></div><div class="gmail_extra">* Breaking the assumption crashes the process. This is a good thing! Implicit polymorphic conversion *decides for you*. Sometimes the code makes the right call, and the conversion is exactly like you want. Sometimes, it accepts the wrong data, converts it to something completely random and processes that. It can lead to misery. Library code shouldn't decide for the caller what to do. The caller knows.</div><div class="gmail_extra"><br></div><div class="gmail_extra">* A major problem in all software is the question "does my data have the right structure here?" We do lots of conversions all the time. We read a binary() value. We convert it into structural JSON. We grab fields in the JSON structure and interpret them into other internal data values. The purpose of conversion code is to handle this, and it is hard to see how you can get around having to describe the conversion at least somewhere in the program.</div><div class="gmail_extra"><br></div><div class="gmail_extra">* Hidden conversions between data and polymorphic acceptance is costly. If your internals are converting back and forth between representations of the same data, you want to know this is the case. Once you compose several polymorphic accepting functions, you pay in execution speed, memory usage through extra GC pressure and lack of precise understanding of data mangling (which misconverts your data). It is evil!</div><div class="gmail_extra"><br></div><div class="gmail_extra">* The more generic an API, the less it tends to say. As one who enjoys programming OCaml, the power stemming from a type-level restriction is the precision in the surrounding code context. You know exactly what data you have and thus also exactly what functions can manipulate it. This restriction is a spotlight on API-usage because I can ask "what API calls can satisfy my need?" and not get back "EVERYTHING! BLOODY EVERYTHING!"</div><div class="gmail_extra"><br clear="all"><div><br></div>-- <br><div class="gmail_signature">J.</div>
</div></div>