Last active
May 26, 2024 06:11
-
-
Save gustavofranke/948f63aa896a174dd4315bddf1f7dfd8 to your computer and use it in GitHub Desktop.
context receivers
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.contextReceivers | |
import kotlin.random.Random | |
fun String.sarcastic(): String = | |
asIterable().joinToString("") { | |
if (Random.nextBoolean()) it.uppercase() else it.lowercase() | |
} | |
fun printTransformedGreeting(transform: String.() -> Unit) { | |
val greeting = "Hello, world!" | |
val transformed = greeting.transform() | |
println("transformed $transformed") | |
} | |
private fun example1() { | |
println("foobar".sarcastic()) | |
} | |
private fun example2() { | |
printTransformedGreeting { sarcastic() } | |
} | |
/////////////////////////////////////////////////////// | |
class Loggger(val name: String) { | |
fun log(s: String) = println("$name: $s") | |
} | |
class NotificationSender { | |
fun send(s: String) = println("NOTIFY: $s") | |
} | |
class NotificationSender2(val name: String) { | |
fun log(s: String) = println("NOTIFY: $s") | |
} | |
interface LoggerContext { | |
val logger: Loggger | |
} | |
interface NotificationContext { | |
val notificationSender: NotificationSender2 | |
} | |
class Api { | |
fun get(): String = "Hello, World" | |
} | |
fun store(s: String, logger: Loggger) { | |
logger.log("Stored $s on disk.") | |
} | |
fun Loggger.store1(s: String) { | |
log("Stored $s on disk.") | |
} | |
context(Loggger) | |
fun store2(s: String) { | |
log("Stored $s on disk.") | |
} | |
context(Loggger, NotificationSender) | |
fun store3(s: String) { | |
log("Stored $s on disk.") | |
send("Successful storage event") | |
} | |
// resolving ambiguities: val name and fun log are in both contexts - this doesn't look so practical anymore | |
context(Loggger, NotificationSender2) | |
fun store4(s: String) { | |
this@Loggger.log("Stored $s on disk (via ${this@Loggger.name}).") | |
this@NotificationSender2.log("Successful storage event") | |
} | |
context(LoggerContext, NotificationContext) | |
fun store5(s: String) { | |
logStorageEvent(s) | |
notificationSender.log("Successful storage event") | |
} | |
context(LoggerContext) | |
private fun logStorageEvent(s: String) { | |
logger.log("Stored $s on disk via ${logger.name}.") | |
} | |
context(LoggerContext, NotificationContext) | |
class Repository { | |
fun store6(s: String) { | |
logStorageEvent(s) | |
notificationSender.log("Successful storage event") | |
} | |
} | |
private fun example3() { | |
val logger = Loggger("Main") | |
logger.log("Test 1") | |
} | |
private fun example4() { | |
val logger = Loggger("Main") | |
logger.log("Test 1") | |
logger.log("Test 2") | |
logger.log("Test 3") | |
} | |
private fun example5() { | |
val logger = Loggger("Main") | |
with(logger) { | |
with(Api()) { | |
log(get()) | |
} | |
} | |
} | |
private fun example6() { | |
val logger = Loggger("Main") | |
store("An image", logger) | |
store("A text file", logger) | |
store("A cheese burger", logger) | |
} | |
private fun example7() { | |
val logger = Loggger("Main") | |
// logger.store1("An image") | |
// logger.store1("A text file") | |
// logger.store1("A cheese burger") | |
with(logger) { | |
store1("An image") | |
store1("A text file") | |
store1("A cheese burger") | |
} | |
} | |
private fun example8() { | |
val logger = Loggger("Main") | |
with(logger) { | |
store2("An image") | |
store2("A text file") | |
store2("A cheese burger") | |
} | |
} | |
private fun example9() { | |
val logger = Loggger("Main") | |
val notificationSender = NotificationSender() | |
with(logger) { | |
with(notificationSender) | |
{ | |
store3("An image") | |
store3("A text file") | |
store3("A cheese burger") | |
} | |
} | |
} | |
private fun example10() { | |
val logger = Loggger("Main") | |
val notificationSender = NotificationSender2("Main") | |
val loggerContext = object : LoggerContext { | |
override val logger: Loggger = logger | |
} | |
val notificationContext = object : NotificationContext { | |
override val notificationSender: NotificationSender2 = notificationSender | |
} | |
with(loggerContext) { | |
with(notificationContext) | |
{ | |
store5("An image") | |
store5("A text file") | |
store5("A cheese burger") | |
} | |
} | |
} | |
private fun example11() { | |
val logger = Loggger("Main") | |
val notificationSender = NotificationSender2("Main") | |
val loggerContext = object : LoggerContext { | |
override val logger: Loggger = logger | |
} | |
val notificationContext = object : NotificationContext { | |
override val notificationSender: NotificationSender2 = notificationSender | |
} | |
val repo = with(loggerContext) { | |
with(notificationContext) { | |
Repository() | |
} | |
} | |
repo.store6("An Idea") | |
} | |
/////////////////////////////////////////////////////// | |
data class Euro(val cents: Int) | |
data class Dollar(val cents: Int) | |
class ExchangeRateProvider() { | |
val euroToDollar = 1.09 | |
val dollarToEuro = 1 / euroToDollar | |
} | |
interface ExchangeRateContext { | |
val exchangeRateProvider: ExchangeRateProvider | |
} | |
context(ExchangeRateContext) | |
fun monthlyRevenue(): Euro { | |
val usRevenue = Dollar(3_99) | |
val euRevenue = Euro(5_00) | |
// val exchangeRateContext = object : ExchangeRateContext { | |
// override val exchangeRateProvider: ExchangeRateProvider = ExchangeRateProvider() | |
// } | |
// return with(exchangeRateContext) { euRevenue + usRevenue } | |
return euRevenue + usRevenue | |
} | |
context(ExchangeRateContext) | |
operator fun Euro.plus(other: Dollar): Euro { | |
return Euro((this.cents + other.cents * exchangeRateProvider.dollarToEuro).toInt()) | |
} | |
/////////////////////////////////////////////////////// | |
class TransactionScope {} | |
fun tx(scope: context(TransactionScope) () -> Unit) {} | |
context(TransactionScope) fun connect() {} | |
fun example12() { | |
tx { | |
connect() | |
} | |
} | |
fun main() { | |
// example1() // foOBaR | |
// example2() | |
// example3() | |
// example4() | |
// example5() | |
// example6() | |
// example7() | |
// example8() | |
// example9() | |
// example10() | |
example11() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment