avatarGabriel Shanahan

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

3990

Abstract

l" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="9660">With <code>with</code>, we can do better:</p> <figure id="3eba"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2F_dcGMTbcN&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2F_dcGMTbcN&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="1962">You can see that bringing the <code>ContractUtils</code> object into scope allowed us to make the code much cleaner and more readable, but by using <code>with</code>, we're also communicating that the operation isn't actually applied to the receiver as it is when we use <code>run</code>. Indeed, you would probably feel weird defining this code as an extension method on <code>ContractUtils</code>, right?</p><p id="db1c">It is often, although not necessarily, the case that <code>with</code> is used with classes that do not carry any state and are simply a kind of "container" that groups together related functions. <b>This concept is actually much deeper than it seems, because it forms the basis of DSL writing in Kotlin, which we'll get to in <a href="https://readmedium.com/domain-specific-languages-867f2790a700">a future article</a></b>.</p><p id="0300">From a purely practical standpoint, the benefits of <code>with</code> are again very similar to those of <code>run</code>, with the exception of nullable receivers.<code>with</code> is not an extension function, so it cannot use <code>?.</code>. That fits nicely with how we just said <code>with</code> should be used — it’s purpose is to bring functionality into scope, so we can use it. That makes no sense if whatever we send into <code>with</code> is not guaranteed to be non-null, does it?</p><p id="3151">However, as is the case with <code>run</code>, we can use it to access extension functions defined within a different class. Let’s use that to our advantage.</p><p id="b7d7">Take another look at <code>ContractUtils</code>. All those functions are screaming to be converted to extensions (and frankly, we would probably move them to the top-level and get rid of the <code>ContractUtils</code> object all together, but let’s ignore that for now):</p> <figure id="fb77"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2Fd8wkpGBgB&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2Fd8wkpGBgB&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="9bd5">We could even go a step further and take advantage of <code>run</code>, if we felt like it:</p> <figure id="2d3e"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FSNO7C0Q8n&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FSNO7C0Q8n&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> <

Options

/div> </figure></iframe></div></div></figure><p id="5b46">Go ahead and compare this final version with what we originally started with — the difference in readability is incredible.</p><h2 id="67a1">run() vs. with()</h2><p id="1f7d">I think that the final version of the previous example best demonstrates what I feel is the difference between the two. While <code>run</code> lends itself well to situations where we want to say "<code>run</code> this calculation <b>on</b> this object", I would use <code>with</code> when I want to say "run this calculation <code>with</code> this object in scope".</p><p id="cb5b">The documentation lists “object configuration and computing the result” as an example of when you should use <code>run</code>, and "grouping function calls on an object" for <code>with</code>. These definitions <i>kinda-sorta-maybe?</i> correspond to what we talked about above, but the wording leaves much to be desired. Indeed, when browsing the internet, it would seem that many struggle with the distinction. Often, the ability of <code>run</code> to deal with nullable receivers using <code>?.</code> is presented as a key deciding factor, but I feel that is purely a practical issue and the difference between the two is more profound than that.</p><p id="9ee0">Another possible interpretation for <code>with</code> is "run this calculation <b>in the context</b> of this object", and we will revisit this interpretation extensively when we <a href="https://readmedium.com/domain-specific-languages-867f2790a700">talk about DSLs</a>. When viewed from this perspective, <code>with</code> is kind of like an <a href="https://en.wikipedia.org/wiki/Include_directive">include directive</a>, sort of similar to a <code>use</code> statement - it brings certain functions/variables implicitly into scope and allows us to use them to construct calculations, without having to reference their whole path.</p><p id="bec4">For instance, we could need more than one such object in scope:</p> <figure id="cb42"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2F14qtkxlv0&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2F14qtkxlv0&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="6846">The code makes perfect sense, and we understand exactly what’s intended.</p><p id="5920">Contrast this with the same code, but with <code>run</code>:</p> <figure id="a35e"> <div> <div> <img class="ratio" src="http://placehold.it/16x9"> <iframe class="" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fpl.kotl.in%2FVf-C7vaWU&amp;display_name=Kotlin+Playground&amp;url=https%3A%2F%2Fpl.kotl.in%2FVf-C7vaWU&amp;image=https%3A%2F%2Fplay.kotlinlang.org%2Fassets%2Fog-image.png&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;type=text%2Fhtml&amp;schema=kotl" allowfullscreen="" frameborder="0" height="300" width="800"> </div> </div> </figure></iframe></div></div></figure><p id="269a">Go back to <a href="https://readmedium.com/scope-functions-run-with-2af8fbe157cf">Scope Functions:<code>ru</code>n()</a>, jump to the <a href="https://readmedium.com/table-of-contents-c52573cfa291">Table of Contents</a>, or continue to <a href="https://readmedium.com/scope-functions-closing-remarks-exercises-6e21a6299311">Scope Functions: Closing Remarks & Exercises</a>.</p><figure id="8ecd"><img src="https://cdn-images-1.readmedium.com/v2/resize:fit:800/1*biBSB579iezsNvEQ_NMLBg.png"><figcaption></figcaption></figure></article></body>

Scope Functions: with(), run() vs. with()

Introducing with(), and how to use it to clean up code. Explaining once and for all what the difference between with() & run() is, when each should be used, and how the explanation in the official documentation leaves much to be desired.

— — — — — — — — — — — — — — —

THE CURRENT VERSION OF THIS ARTICLE IS PUBLISHED HERE.

— — — — — — — — — — — — — — —

Tags: #FUNDAMENTAL CONCEPT

This article is part of the Kotlin Primer, an opinionated guide to the Kotlin language, which is indented to help facilitate Kotlin adoption inside Java-centric organizations. It was originally written as an organizational learning resource for Etnetera a.s. and I would like to express my sincere gratitude for their support.

It is recommended to read the Introduction before moving on. Check out the Table of Contents for all articles.

With

The definition of with is essentially:

At first sight, we can see that it is almost completely the same as run with receiver. In fact, whenever you can write someObj.run { ... } you can always write with(someObj) { ... } and get exactly the same result. So why have two different functions that do the same thing?

The answer, as you have probably come to expect, is that the difference is in the intent they communicate. While run is used when the calculation directly pertains to a given object (i.e. in situations where we are tempted to define an extension function), with is used when we want to define a calculation with a class instance in scope, but the calculation doesn't necessarily pertain to the instance in question.

Why would we want to do that? Often, it is when the class in question groups together functionality that is relevant for our use-case, and we want to access it in a “first class manner”.

Here is an example:

With with, we can do better:

You can see that bringing the ContractUtils object into scope allowed us to make the code much cleaner and more readable, but by using with, we're also communicating that the operation isn't actually applied to the receiver as it is when we use run. Indeed, you would probably feel weird defining this code as an extension method on ContractUtils, right?

It is often, although not necessarily, the case that with is used with classes that do not carry any state and are simply a kind of "container" that groups together related functions. This concept is actually much deeper than it seems, because it forms the basis of DSL writing in Kotlin, which we'll get to in a future article.

From a purely practical standpoint, the benefits of with are again very similar to those of run, with the exception of nullable receivers.with is not an extension function, so it cannot use ?.. That fits nicely with how we just said with should be used — it’s purpose is to bring functionality into scope, so we can use it. That makes no sense if whatever we send into with is not guaranteed to be non-null, does it?

However, as is the case with run, we can use it to access extension functions defined within a different class. Let’s use that to our advantage.

Take another look at ContractUtils. All those functions are screaming to be converted to extensions (and frankly, we would probably move them to the top-level and get rid of the ContractUtils object all together, but let’s ignore that for now):

We could even go a step further and take advantage of run, if we felt like it:

Go ahead and compare this final version with what we originally started with — the difference in readability is incredible.

run() vs. with()

I think that the final version of the previous example best demonstrates what I feel is the difference between the two. While run lends itself well to situations where we want to say "run this calculation on this object", I would use with when I want to say "run this calculation with this object in scope".

The documentation lists “object configuration and computing the result” as an example of when you should use run, and "grouping function calls on an object" for with. These definitions kinda-sorta-maybe? correspond to what we talked about above, but the wording leaves much to be desired. Indeed, when browsing the internet, it would seem that many struggle with the distinction. Often, the ability of run to deal with nullable receivers using ?. is presented as a key deciding factor, but I feel that is purely a practical issue and the difference between the two is more profound than that.

Another possible interpretation for with is "run this calculation in the context of this object", and we will revisit this interpretation extensively when we talk about DSLs. When viewed from this perspective, with is kind of like an include directive, sort of similar to a use statement - it brings certain functions/variables implicitly into scope and allows us to use them to construct calculations, without having to reference their whole path.

For instance, we could need more than one such object in scope:

The code makes perfect sense, and we understand exactly what’s intended.

Contrast this with the same code, but with run:

Go back to Scope Functions:run(), jump to the Table of Contents, or continue to Scope Functions: Closing Remarks & Exercises.

Kotlin
Programming
Java
Functional Programming
Kotlin Scope Functions
Recommended from ReadMedium