tag:www.holychao.com,2005:/2014/06?format=atomHoly Chao : Archives for Holy Chao Archives for Holy Chao June 2014 Being a collection of deranged ramblings regarding Discordian tainted independence, and other such rubbish2014-06-20T20:13:55ZTypourn:uuid:2f04bd06-9dd4-456d-8c3b-d499eb1a13352014-06-20T17:36:08Z2014-06-20T20:13:55ZVenerable High Pope Swanage I, Cogent Animal of Our Lady of DiscordNaming considered MOSTLY harmless<p>
This is a continuance of a thought that I'd <a href="https://twitter.com/holy_chao/status/478921214933495809">briefly mulled over</a> on twitter to some reaction. No point in summarizing as it's only a few characters: "In <a class="twitter-hashtag pretty-link js-nav" dir="ltr" href="https://twitter.com/hashtag/Clojure?src=hash" source="hashtag_click"><s>#</s><b>Clojure</b></a> I find it best to try and avoid naming anything except for the tools (fns and constants) used to construct a running system."</p>
<p>
The reactions were great, as I would more or less expect, namely trying to drive at the thrust of why I would say such a thing. "What are examples of things I would avoid naming?" "By naming do I mean assigning to a Var, or something else?" and "My examples are primarily stateful things, is this to cure live programming woes?"</p>
<p>
I'll do my best to expound on my reasoning in more detail, become more crisp in defining what I mean, and perhaps persuade you to strive in the vicinity of this same goal.</p>
<p>Let's start off with applying a more rigorous definition of this guideline to start with: "In Clojure, I find it best to minimize the number of things resolvable in a global namespace to a single unique value. I think that the minimal set of such things probably includes functions, protocols, types, records, compile time constant values. What all of the things I am comfortable naming share in common is that they are definitions abstract of any individual concrete application of some Clojure program."</p>
<p>So, from that, it means that a named thing assigned to a Var qualifies, as that occupies some point in the Clojure namespace resolver. Something bound to a JNDI name is resolvable in a global namespace, and so it also qualifies. Binding a value to a symbol, as with let, does not operate under this rule, as the scope of that name binding is the lexical scope of the let form. Associating a value into a map would not qualify, nor would it count if you're updating an atom holding a map with a new value. However, this principle does encourage you to avoid putting that atom in Var that is globally adressable. There are definite gray areas and times to bend this guideline as well. A dynamic Var is a globally resolvable thing, but the binding of that Var to any value is local to a thread. There's a safe and sane way to override this with the bindings macro. So I think it's safe too, but my tendency is to avoid using it except when there are concrete reasons to do so.</p>
<p>Some of the things I avoid naming are any non-Var Clojure identities like Agents, Atoms and Refs. I tend to try and avoid naming core.async Channels, though I sometimes do find not doing so sufficiently inconvenient that I name them. I'd rather work with a database connection in a dynamic Var or as a parameter than as a value in a Var that gets established via e.g. alter-var-root!</p>
<p>I'm going to tackle last the question of "Why?", because it is long to describe. Thanks for bearing with me. My motivations for why is that the things I have described as avoiding naming are the kinds of things which are resources that your program will be making use of. Some specific atom that's holding the current state of the game world is a resource you're making use of as the game engine runs forward in time to provide continuity between discrete game states. The things you name with (def) and (defn) special forms often include defining the behavior of your Clojure program. If you can structure your program such that the resources it uses are not bound to names as part of loading a file, you have now decoupled the process of altering your program's behavior from the process of initiating its dynamic state.</p>
<p>So one thing you may get out of this is easier live programming, certainly!</p>
<p>Another value this guideline will enable, though, is a <strong>conscious</strong> process of coupling process to resources. When you make this act conscious, it makes parallelizing your program eas<strong>ier</strong>, and weakens the coupling between any particular process and a particular resource. As a terrible non-compiling example for contemplation, consider:
<div class="CodeRay"><pre><notextile><span class="CodeRay">(ns foo)
(def conn (delay (initialize-db-connection)))
(def get-foos
[]
(execute @conn "select * from foo"))
(-main
[& args]
(println (get-foos))
</span></notextile></pre></div>
compared with
<div class="CodeRay"><pre><notextile><span class="CodeRay">(ns foo)
(def get-foos
[conn]
(execute conn "select * from foo"))
(-main
[& args]
(println (get-foos (initialize-db-connection)))
</span></notextile></pre></div>
In the former, get-foos only operates on the locally defined conn, and its correct functioning is predicated on that conn being successfully initialized prior to the query executing. As an aside, how often have you seen conn defined without being wrapped in a delay and dereferenced? Have you done it yourself?</p>
<p>The latter is functionally equivalent to the former for the use case of main, but get-foos now can accept an arbitrary initialized connection. If you wanted to get the foos out of 5 different databases, you could do so pretty easily mapping over those databases. get-foos behavior is less coupled to its compilation environment and more coupled to its runtime environment.</p>
<p>This has broad, subtle consequences when the systems you build are more complex than the simple example cases I've described above.</p>
<p>This is a principle I've found valuable from personal experience and most often reinforced by deviating away from it painfully. It is not an easy thing to do, but after you spend some time thinking about how to achieve it, it starts to get easier. Maybe you'll find it useful too if you give it a try.</p>
<p>I'd like to thank <a href="https://twitter.com/baranosky">@Baranosky</a>, <a href="https://twitter.com/ambrosebs">@ambrosebs</a>, <a href="https://twitter.com/alandipert">@alandipert</a>, and <a href="https://twitter.com/BrandonBloom">@BrandonBloom</a> for getting me wound up on this subject.</p>urn:uuid:ba6640ac-761a-4399-93b3-5c8d924689202014-06-10T20:13:42Z2014-06-10T20:25:10ZVenerable High Pope Swanage I, Cogent Animal of Our Lady of DiscordFun With Maths<p>I have lived in Baltimore County, Maryland exclusively since November of 2004.<p>
<p>In that time I have only received one Jury summons, it was for tomorrow, and my call in number was 365. I ducked getting called, as they only wanted 1 through 225.</p>
<p>Looking at the call in messages for today and for tomorrow, it appears that ~400 individuals are chosen each day. If one presumes the courts are only operating on standard business days, that yields about 248 days of 400 individuals. Each year, then, 99,200 individuals are randomly summoned to appear as jurors.</p>
<p>Presently the population of Baltimore County is approximately 817,455. If the proportion of summoned jurors to population held constant over the past ten years (a groundless assumption), then each year an individual has a ~12.13% chance of being summoned. Consequently your odds are ~87.87% of not being selected in any given year.</p>
<p>The odds of successfully avoiding summonses for 9 years in a row are ~31.22%. By purely random chance, one could expect to get a Jury Summons once every 5 years (.8787^5 = .5238). The odds of getting summoned two years in a row are ~1.5%.</p>
urn:uuid:f333e292-3b83-4538-b3df-26fd05c074f62014-06-03T19:57:43Z2014-06-04T01:37:05ZVenerable High Pope Swanage I, Cogent Animal of Our Lady of Discordnil, null, let's call the whole thing off.<p>Apple has recently announced the Swift programming language, along with language specifications and documents to support it. I'm not particularly interested in learning much about this language, in no small part because it seems like it's tightly coupled to Apple's walled garden. However, I am interested in discussing nil and/or null, which I will call nil from now on, because Swift calls it that, Clojure calls it that, and Ruby calls it that.</p>
<p>Swift promises to disallow the use of nil in a variable except in those cases which someone has specifically allowed for nil; be it a parameter, a variable declaration or what have you.<p>
<p>Having written 0 Swift programs, my opinion on this is tangentially valuable at best, but I have written many programs in many other languages, and each of those languages has always had some concept of nil, and many of them were entirely birthed after nil was well explored and people understood the costs of nil, and chose to include it anyway. I'd like to discuss some arguments about why I don't find Swift's approach valuable. Additionally I'd like to discuss some other ways languages have approached the problems nil introduces.<p>
<ul>
<li><strong>PRIMO:</strong> Nil is an elemental idea that exists when discussing logical action sequences and a valuable inclusion in your programming language. Contemplating map retrieval, if one attempts to retrieve a key from a map which does not contain that key, one has essentially three potential outcomes:
<ol><li>Return nil, or its moral equivalent.</li>
<li>Return some sentinel value replacing nil (e.g. 0)</li>
<li>Treat the retrieval of an absent key as an exceptional case and provoke an error condition in the language's error facility.</li>
</ol> While maps are convenient illustration of the value of nil, they are not an exhaustive example. I chose them merely to show that of obviously available approaches, I feel that nil incurs the least cost.</li>
<li><strong>SECUNDO:</strong> I view prohibiting nil as a form of static typing. The supremacy of static vs. dynamic is a can of worms that I am not particularly interested in opening; people have built many useful things using both static and dynamically typed programming languages. My personal preference tends toward dynamic programming languages, as I feel there is more implicit openness in the interfaces of systems built in dynamically typed languages. Taking any class of values and ruling them out of participation a priori, such as the class of values that are nil, is a static typing move that I feel incurs costs out of proportion to its benefits. I am particularly skeptical, as my understanding is that Swift defaults one's program into this particular form of typing, and as a programmer one is forced into opting out of this typing if one finds it undesirable.</li>
<li><strong>TERTIO:</strong> There are very good language constructs for dealing with nil in a way that causes nil values to not ruin everything. For example, Ruby treats nil as a singleton instance which can have methods extended to it. This is used to great effect in e.g. Rails to help catch nil errors for that specialized domain. Clojure treats nil as a distinct and viable dispatch candidate for protocols; so when one attempts to use a protocol fn against nil, the nil typed version is invoked.</li>
</ul>
<p>I'd like to spend a little more time on that third point because it is the most important. Nil is not a problem in programs; the way programmers are afforded tools to interact with nil is the real problem. What Ruby and Clojure offer is a way to specify to the computer a categorical definition of the behavior of nil for the lifetime of that program, and the absence of that language feature, such as in classical Java, is where the real pain point arises. There is certainly a domain of functionality for which nil inputs are going to be problematic, and having a facility to avoid receiving nil inputs seems like it could provide some amount of value. But heralding this as saving us from the problems of nil feels a bit too much like throwing the baby out with the bathwater.