<@U5UU34LPK> the challenge is the following. The `...
# announcements
g
@karelpeeters the challenge is the following. The
foo
field is injected via DI, so it has to be lateinit. The thing is, this field is used to build another one —
bar
. That's why the
bar
is lazy.
Copy code
@Inject
    lateinit var foo

    val bar by lazy {  foo.foo()   }
Now, I'm wondering if I can hide all this trickery behind some delegate or something, so I'll end up with a clean
bar
initialization. Ideal:
Copy code
val bar by initBar() // somehow foo is injected inside?
Or at least:
Copy code
@Inject
    lateinit var foo

    val bar by initBar(foo)
p
May be just
Copy code
class Class1 {
    lateinit var foo: String
    
    val bar by initBar()

	fun initBar() = lazy { foo.toLowerCase() }
}
Or this?
Copy code
class Class1 {
    lateinit var foo: String
    
    val bar by initBar(this)
}

fun initBar(c: Class1) = lazy { c.foo.toLowerCase() }
or this
Copy code
class Class1 {
    lateinit var foo: String
    
    val bar by lazyByFoo()
}

fun Class1.lazyByFoo() = lazy { foo.toLowerCase() }
Why do you want to hide this initialization?
g
because for the sake of the example I simplified it. The actual initialization is longer. Sure, this is an option as well:
lazy { longInitMethod(foo) }
, but I was wondering if I can have a delegate that will wrap the whole block, including
lazy
a
Copy code
val bar by initBar()

fun initBar() = lazy { foo.foo() }
works for me You can also do:
Copy code
lateinit var bar: String

@Inject
fun initBar() {
    bar = foo.foo()
}
g
the first one doesn't scale, it works as a local function, because it has access to
foo
. I want it to be an utility function, so it could be reused in many places. But then, access to
foo
is lost.
a
would you still inject
foo
if you could just inject
bar
?
g
can't inject
bar
directly, because it's being managed by android framework.. it's bit complicated, but not relevant.
wait, it actually works
p
Copy code
fun main(args: Array<String>) {
    val c = Class1()
    
    c.foo = "A"
    println(c.bar)
}

class Class1 {
    lateinit var foo: String

	val bar by initBar { foo }

	fun initBar(fooSelector: () -> String) = lazy { fooSelector().toLowerCase() }
}
k
I think you can't really "intercept" the injrction "event", so you'll be stuck with some kind of lazy variant. You could make a function that initializes everything, but you're still going to have to deletate every oroprrty to it.
p
Yea, just tested, works 🙂
g
the one before, that you deleted. It works with crossinline modifier for me
fun bind(crossinline foo: () -> Foo) = lazy { foo.invoke().foo() }
k
Doesn't a full inline work?
g
yeah, the function is inlined, omitted for example
k
But why the
crossinline
then? Is that necessary?
g
the error says that the foo may contain non-local returns and crossinline is required
but I think it's awesome that it's possible, really happy about that. Thanks @Pavlo Liapota !
now, I'm still trying to get what you've posted above:
Copy code
@Inject
fun initBar() {
    bar = foo.foo()
}
didn't know you can do that. Where the foo is declared? How the DI knows what type to inject?
a
I was working under the assumption you have some
@Inject lateinit var foo: Foo
there in the same class
the only thing Dagger does here is to call the
initBar
method right after injecting members
you could add parameters to that method, then Dagger would use the dependency graph to pass them when calling it
here's the code generated by dagger:
Copy code
@Override
  public void injectMembers(SimpleActivity instance) {
    SimpleActivity_MembersInjector.injectFoo(instance, fooProvider.get());
    injectSetBaz(instance);
  }

  public static void injectSetBaz(SimpleActivity instance) {
    instance.setBaz();
  }
p
Wow, this is nice feature! So basically this is possible?
Copy code
lateinit var bar: Bar

@Inject
fun initBar(foo: Foo) {
    bar = foo.foo()
}
so foo property is not even need to be declared?
a
Well, yes and yes 🙂
👍 2
g
r/blackmagicfuckery/) I'll take it, neat stuff. Thx @arekolek
🖖 1