loading...

with(ConfigObject) { "Language $KOTLIN".isSparkingJoy() }

jmfayard profile image Jean-Michel Fayard πŸ‡«πŸ‡·πŸ‡©πŸ‡ͺπŸ‡¬πŸ‡§πŸ‡ͺπŸ‡ΈπŸ‡¨πŸ‡΄ ・Updated on ・3 min read

I am using Kotlin since traits were a thing. Yet it continue to surprise me for the better, usually when I discover how two familiar language constructs combine nicely for the better.

Today I will share with you such a recent discovery. I am not aware that this pattern has already a name, so I will cal it the with(ConfigObject) Pattern.

with(ConfigObject) { 
     "Language $KOTLIN".isSparkingJoy() 
}

But first I will start with a confession:

That shitty first draft

When I'm starting to work on a project or a feature, my initial code is messy.

It has thing that are hard-coded but shouldn't. It has top-level properties and functions all over the place. Sometimes implemented twice. Things that should be extracted but are not. Things that are extracted in a way that doesn't really make sense. Usually with a bad name.

That initial messy code serves important purposes. Playing with and learning a new API. Validating that it makes sense to invest time into an idea. More importantly, it's a remedy against perfectionism. On this, I am with writer Anne Lamott

Perfectionism is the voice of the oppressor, the enemy of the people. It will keep you cramped and insane your whole life, and it is the main obstacle between you and a shitty first draft.
Perfectionism is a mean, frozen form of idealism, while messes are the artist’s true friend. What people somehow (inadvertently, I’m sure) forgot to mention when we were children was that we need to make messes in order to find out who we are and why we are here β€” and, by extension, what we’re supposed to be writing.

Refactoring time

Yet, when the time has come, it's time to clean things up.

It's time for refactoring.

Imagine we have this initial messy code:

fun doStuff() {
    val feeling = "is sparking joy"
    println("Language $language " + feeling + "!")
}

val language = "Kotlin"

The pattern here is to

  • Create a Config singleton that contains all the extracted constants so that there are not all over the place in the package
  • Use the scope-function with that imports all the properties and extension function of Config

It works. Trust me!

No, actually, trust me but do verify by clicking on the Run ▢️ button of this embedded snippet:

You will probably have to scroll down the Kotlin snippet because of thepracticaldev/dev.to#4011 Iframe resizing. But it does work:

image

Conclusion

I am not sure if this pattern has already a name. It use familiar building blocks. You do similar, more complex things when you use Kotlin to build a Domain Specific Language - DSL, see Kotlin in Action, chapter 11.

But DSL are a rather advanced topics, while this is an easy solution to a simple problem and merits to be highlighted.

Obviously, this example was contrived to fit on the title of my Post.

For a real-world example, have a look in my open-source project at PluginConfig and its usage with(PluginConfig) { ... }

One thing worth pointing out is that it works really well not only for constants, but also for functions and more importantly extension functions! I am not a fan of having extensions function for String. That would pollute all the Strings out there. But the ConfigObject provides a scope for it.

Try it out to discover the life-changing magic of tidying up!

Hello, Kotlin Weekly

Lots of visitors. What happened? Oh, I was featured in Kotlin Weekly?

Welcome to dev.to!

I shall invite you to create an account here.
It's a friendly dev community of readers and writers.
Here is a good summary of what you may want to publish here instead - or in parallel with publishing on Medium.com

You can follow Kotlin content:

and if you wish, you can also follow me

jmfayard image

Discussion

pic
Editor guide
Collapse
kip13 profile image
kip

In JS you have the with statement too:

const myObj = {test: 123}
const test = "is a test !"

with (myObj) { console.log(test) }
console.log(test)

Collapse
jmfayard profile image
Jean-Michel Fayard πŸ‡«πŸ‡·πŸ‡©πŸ‡ͺπŸ‡¬πŸ‡§πŸ‡ͺπŸ‡ΈπŸ‡¨πŸ‡΄ Author

I had forgotten, thank you! Not doing so much JavaScript those days.
A difference with Kotlin is that we have strong static typing - with type inference.
So much of the stated problems for the with statement do not apply.