https://kotlinlang.org logo
#compose
Title
# compose
t

Tristan Caron

10/11/2019, 3:01 PM
I think this question has been already answered, but I am gonna ask it again 😄 Why
Copy code
val (text, setText) = +state { "Hello, World!" }
And not
Copy code
var text by State("Hello, World!")
Same questions for
@Composable
actually
Copy code
@Composable
fun MyComponent() {}
Instead of
Copy code
fun MyComponent = composable { }
Maybe I should wait for an article about this?
f

Fudge

10/11/2019, 3:12 PM
The answer to the first question is ‘why not both? ‘
They both work
Regarding the second question, that adds another layer of indentation (
Copy code
@Composable fun x() = Text(“hello”)
becomes
Copy code
fun x() = composable {
   Text(“hello”)
}
)
t

Tristan Caron

10/11/2019, 3:20 PM
I did not know for the first one : O And regarding the second one, I am sure that the layer of indentation was the concern here. It seems to be a lot of work (to write the plugin for gradle, for intellij, etc), for such little benefit.
f

Fudge

10/11/2019, 3:30 PM
I don’t know if they would not need to make a compiler plugin
Also remember it would need to be an extension function
Composer.x() = composable{}
People are saying there is no need for a gradle plugin though?
l

Luca Nicoletti

10/11/2019, 4:02 PM
You can get
fun MyComponent() = composable { }
to work 😧
@Fudge it’s either shipped with the version I posted on the other thread (silently, without anyone noticing) or not required
l

Leland Richardson [G]

10/11/2019, 4:13 PM
note that
var text by state { "Hello, World!" }
will be the way it will work. right now the
+
is needed. but property delegates are indeed something i’m looking forward to being used here. they didn’t work with the new kotlin compiler backend that we rely on until recently though
however,
val text by State("Hello World")
compiles, but is subtly wrong, so don’t do that
we should probably fix by making the State constructor internal
👍 1
f

Fudge

10/11/2019, 4:14 PM
If you don’t have it as extension method you won’t have ‘can only be called in other composables’
l

Leland Richardson [G]

10/11/2019, 4:14 PM
regarding the 2nd question
we thought a lot about using the receiver as our method for passing around the composer
it has a lot of similarities but is also different from what we are doing in a few ways
i believe i went into detail about our decision making process here a while ago if you want to try and dig that up
(it was a multi-month decision for us, so trust me, we thought long and hard about it)
also there is some complexity here that isn’t quite “done” in terms of how @Composable works in the current compiler version
i

Icaro Temponi

10/11/2019, 4:17 PM
What about the hook syntax? will it still be supported or the preferred way will be the
var text by state { "Hello, World!" }
?
l

Leland Richardson [G]

10/11/2019, 4:21 PM
both will work. your choice
(at least that is the current plan)
i

Icaro Temponi

10/11/2019, 4:21 PM
awesome, thx 🙂
l

Leland Richardson [G]

10/11/2019, 4:22 PM
all of this works because the return type of
state
which is
State
implements the componentN operators and the property delegate operators
t

Tristan Caron

10/11/2019, 4:23 PM
@Leland Richardson [G] Thanks for your lights! Also, I read somewhere that BLOC (mostly known in Flutter) is something that we will be able to to. Do you think that something like this would be possible? (Quick concept)
Copy code
class CounterService {
    private val counter = ConflatedBroadcastChannel(0)
    
    fun openSubscription() = counter.openSubscription()

    suspend fun increment() {
        counter.send(counter.value + 1)
    }
}

//

@Composable
fun MyComponent(counterService: CounterService) {
    Button(onclick = { counterService.increment() })
    Text(counterService.openSubscription())
}
The view would be automatically updated on new values.
l

Leland Richardson [G]

10/11/2019, 4:24 PM
yeah, definitely.
i have a lot of ideas around this but suspend functions don’t yet work with the kotlin IR backend so some stuff isn’t merged yet and is yet to be explored fully
but the broad strokes are: a composable context could be thought of as a superset to a coroutine context, so you should be able to launch coroutines from inside of composable functions without any concern over what context it is launched in
and you could use channels like your example does to invalidate recompose scopes very seamlessly
t

Tristan Caron

10/11/2019, 4:28 PM
I am in love... Finally found the framework that do everything I want! Can’t wait to see in action, and port it to multiplatform 😛 You’re amazing guys!
❤️ 3
👍 1
a

Adam Powell

10/11/2019, 9:34 PM
You'll probably want flows rather than channels, there are some interesting things that happen in terms of compositions that may or may not be committed, recompositions, etc. and you'll want some automatic cleanup to be at work that would be a lot easier with flows 🙂
t

Tristan Caron

10/11/2019, 11:17 PM
But I thought flows were for “flux” that have an end, like reading a file. For me it’s similar to
Sequence
but async, so
AsyncSequence
. And channel, for something that doesn’t, like a event. I thinking like having an UserService, and if an user change some settings, like color, it is broadcast across the app. When a component is removed from the tree, of course, we have to think of unsubscribing. But the service will be always running.
g

gildor

10/15/2019, 12:38 AM
Flows are not only for the things that have "an end" (actually it's also true for sequences). Essentially you probably shouldn't expose any channel API, channel may be used as implementation detail, but Flow API is more safe and powerful for consumer
broadcast across the app
Right, and to subscribe on this broadcast you consume it using Flow. Under the hood it will be a channel for now, or upcoming DataFlow or Flow.share()
t

Tristan Caron

10/15/2019, 3:30 PM
So we will be able to use flows for events?
How will it look like using flows?
Copy code
class CounterService {
    private val counter = ConflatedBroadcastChannel(0)
    
    fun openSubscription() = counter.openSubscription()

    suspend fun increment() {
        counter.send(counter.value + 1)
    }
}
g

gildor

10/15/2019, 11:26 PM
With DataFlow it would look like in this doc on your link, but even now, without DataFlow, you can use Flow API, just replace counter.openSubscription() with counter.asFlow()