Jeff Gulbronson
02/18/2019, 1:38 PMExtension functions should not use variables from a scope other than the scope available to them from the class they’re extending. Instead, variables should be passed in as parameters. Put another way, extension functions should be “stateless”, and not rely on where they’re defined to function. Extension functions should be able to be moved to a new file and continue to work.
Czar
02/18/2019, 1:42 PMMyEntity: Entity
and repository: MyRepository
I don't want to add an explicit dependency on the repository so I define a "autowired" extension function Entity.save()
, which uses repository from its defintion scope, then I'm able to write:
MyEntity(...).save()
Jeff Gulbronson
02/18/2019, 1:45 PMCzar
02/18/2019, 1:46 PMJeff Gulbronson
02/18/2019, 1:47 PMMyRepository
wherever you need to call Entity.save()
Czar
02/18/2019, 1:48 PMmyRepository.save(MyEntity(...))
streetsofboston
02/18/2019, 1:49 PMCzar
02/18/2019, 1:49 PMJeff Gulbronson
02/18/2019, 1:52 PMThis means that the logic inside context is completely separated from the context implementation and could be written in different part of the program or even different module.
Jeff Gulbronson
02/18/2019, 1:53 PMCzar
02/18/2019, 1:55 PMEntity.save()
function is that wrapper 🙂dmcg
02/18/2019, 1:57 PMJeff Gulbronson
02/18/2019, 1:57 PMJeff Gulbronson
02/18/2019, 2:00 PMclass Bar @Inject constructor(
private val a: A,
private val b: B,
private val c: C
) {
fun handle(foo: Foo) {
return foo.handle()
}
fun Foo.handle() {
return this.sumWithA(a) + this.sumWithB(b) + this.sumWithC(c)
}
}
That seems like it should just be a private function on class Bar, instead of an extension function on class FooJeff Gulbronson
02/18/2019, 2:00 PMdmcg
02/18/2019, 2:04 PMJeff Gulbronson
02/18/2019, 2:07 PMdmcg
02/18/2019, 2:10 PMthis.a, this.b
params that you get the combination. In these cases I make them private and suck it up.Jeff Gulbronson
02/18/2019, 2:12 PMa
and b
are defined?dmcg
02/18/2019, 2:15 PMfun handle(foo: Foo) = op2(op1(foo, a, b), a, b)
dmcg
02/18/2019, 2:23 PMfun Foo.op1() = doAThingWith(foo, a, b)
fun Foo.op2() = anotherThingWith(foo, a, b)
so that I could write
fun handle(foo: Foo) = foo.op1().op2()
Jeff Gulbronson
02/18/2019, 2:25 PMfun handle(foo: Foo) = foo.op1(a, b).op2(a, b)
Jeff Gulbronson
02/18/2019, 2:27 PMop1()
, so no chaining, then an extension function would make less sense under your guidelines yeah?dmcg
02/18/2019, 2:28 PMdmcg
02/18/2019, 2:28 PM.toSomethingElse()
dmcg
02/18/2019, 2:29 PMconvertToBar(foo)
- foo.toBar()
Jeff Gulbronson
02/18/2019, 2:29 PMJeff Gulbronson
02/18/2019, 2:30 PMdmcg
02/18/2019, 2:31 PMJeff Gulbronson
02/18/2019, 2:33 PMdmcg
02/18/2019, 2:33 PMdmcg
02/18/2019, 2:35 PMJeff Gulbronson
02/18/2019, 2:36 PMfoo.op1().op2()
Is easier to grok the basic understanding of versus
foo.op1(a, b).op2(a, b)
Except now I have to figure out what op1 and op2 are depending on implicitly, versus being able to see at the call site.dmcg
02/18/2019, 2:38 PMJeff Gulbronson
02/18/2019, 2:38 PMdmcg
02/18/2019, 2:39 PMJeff Gulbronson
02/18/2019, 2:40 PMdmcg
02/18/2019, 2:43 PMJeff Gulbronson
02/18/2019, 2:46 PMJeff Gulbronson
02/18/2019, 2:46 PMapply
, run
, let
, etc.dmcg
02/18/2019, 2:47 PMshould
with must
Jeff Gulbronson
02/18/2019, 2:48 PMJeff Gulbronson
02/18/2019, 2:48 PMdmcg
02/18/2019, 2:49 PMJeff Gulbronson
02/18/2019, 2:51 PMif
instead of apply
or run
. Those can be a bit overwhelming for newer developers as well.