Skip to content

Instantly share code, notes, and snippets.

@gustavofranke
Last active May 26, 2024 06:11
Show Gist options
  • Save gustavofranke/948f63aa896a174dd4315bddf1f7dfd8 to your computer and use it in GitHub Desktop.
Save gustavofranke/948f63aa896a174dd4315bddf1f7dfd8 to your computer and use it in GitHub Desktop.
context receivers
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