3 ms·
I'm really not a fan of implicit context being passed around like this. I hated Scala's implicit feature although I'm not familiar with the recent apparent imp
by derriz 4y ago
I'm really not a fan of implicit context being passed around like this. I hated Scala's implicit feature although I'm not familiar with the recent apparent improvements referenced in the article.
In a larger 'with' block, you cannot tell which invocations will interact with or change the state of a context object without looking at site of the definition of the function.
For me, when reading others' code, being able to construct a mental model of what the effects of a line of code in isolation is a vital property for code to be readable/comprehensible. Without implicits, you can mentally constrain what effects a line like "x.y(z)" will have on the state of the program.
One issue I had with the Scala feature was how it made refactoring is more fraught - as it's not clear which pieces of code in the 'with' block can be moved elsewhere from just reading the code.
Context objects behave like a form of global variable except their use can be even more confusing as Foo@this will refer to different things depending on the runtime call stack. And similarly, it bakes in a singleton aspect to the context objects. The example model from the article should allow functions to operate on multiple Transaction or AccountRepo instances, for example.
- rob74 4y agoYup, I'm skeptical too. I hope JetBrains support this feature really well in their IDE, that will hopefully make code using context receivers a bit easier to read. But of course Kotlin code should not only be readable in Android Studio...
- scns 4y ago> But of course Kotlin code should not only be readable in Android Studio... Intellij Idea Community Version reads it just fine ;)
- mjburgess 4y agoConsider, (in my own syntax), on(table) select(blah) where(blah) groupby(blah) this is basically just, table.select(blah).where(blah).groupby(blah) but this becomes inflexible when we want `table` to track more than just itself: table.connect().select(blah).where(blah).groupby(blah) suddenly, `table` holds fields which function like your "global variables". instead, on(table, connection) select() ... In otherwords OO already has this implicit mechanism at work in a highly action-at-a-distance manner, with unweildy objects functioning like a box-of-globals. By being explicit about which "nonlocal"s are required for an API, we can control this better. And also compose-in other APIs, etc., add toJson() at the end. (NB. nonlocal in the sense that they are common to most/all uses of an API) Python does this with decorators, but if it would add a little function chaining/compositon syntax, it would be more powerful.
- derriz 4y agoYes, you can achieve also reduce local readability by passing objects containing buckets of state around. But such classes always smell to me - particularly if component instances have other aliases. But I try to avoid it by designing distinct and hopefully coherent service or context classes. And this Kotlin feature effectively requires you structure your context/service/etc. classes in this way - the point is to allow multiple implicit contexts. When you say 'action-at-a-distance' - I would argue that the "distance" is not on the same scale. One crosses statements invisibly while your example, in all languages I've used, would still constitute a single statement. But fundamentally, this is an argument about style as it's not a pure binary distinction, so I don't think there's a definitive right or wrong here. Subjectively - in my experience, codebases (remembering one in Scala in particular) which rely heavily on implicit context objects are more difficult to understand. For me, when trying to get my head around an unfamiliar codebase, explicit is better than implicit unless it introduces so much verbiage that the intent is hidden.
- mjburgess 4y agoI read this as a means of making the implictness of OO, explicit. Ie., it is syntax for specifying what `this` is Inheritance, fluid changing + properties, etc. are all implicit in exactly the same way. OO programmers have just got used to them