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

Ruckus

10/04/2019, 8:28 PM
I'm not familiar with Flutter, so may I ask what that gives you over
Copy code
Padding(16.dp) { Text(text = "Hello, world!") }
a

alexsullivan114

10/04/2019, 8:29 PM
Having those modifiers as widgets makes for super deeply nested UI
If you look at a flutter build method they tend to go real deep real quick, at least partially because of all of these wrapping objects
a

Adam Powell

10/04/2019, 8:30 PM
yeah indentation level is one, ability to stick it in an object for reuse is another, UX research that the behavior of
Padding(16.dp) { Stuff(...) }
is confusing as well
r

romainguy

10/04/2019, 8:30 PM
I also like the ability to say
val border = lineBackground(black) wraps padding(16.dp)
(assuming modifiers can draw)
And then you could just
Text(modifier = myTheme.border)
for instance
a

alexsullivan114

10/04/2019, 8:31 PM
that is interesting.
wraps
and
+
have interesting different semantics. The word
wraps
is kind of intriguing though - especially in the context of padding, which is literally wrapping around things.
r

Ruckus

10/04/2019, 8:32 PM
@romainguy I don't see how that is an improvement over pulling it out to a composable function, so I'm probably still missing something.
👍 1
a

Adam Powell

10/04/2019, 8:32 PM
it also removed an ambiguity/very complex behavioral spec around this:
Copy code
Padding(16.dp) {
  Text(text = "Hello")
  Text(text = "World")
}
I'm not sure you can get any two people in a room who agree on what that snippet should do
a

alexsullivan114

10/04/2019, 8:34 PM
To be honest, I'm not sure I fully understand what two `Text`s aligned like that do without seeing the outer container. Which is a bit of a bummer
r

Ruckus

10/04/2019, 8:34 PM
Ah, I see. That's actually very similar to something we ran into with some #tornadofx builders a while ago.
a

Adam Powell

10/04/2019, 8:36 PM
@alexsullivan114 precisely. Flutter solves this by having single vs. multi-child widgets as something they express in the type system. Since Compose uses lambda function bodies it creates a challenge.
a

alexsullivan114

10/04/2019, 8:37 PM
Yeah, that's interesting. I wonder how big of an issue that will be moving forward - i.e. losing that type power about what kind of child widget a containing widget expects...
a

Adam Powell

10/04/2019, 8:38 PM
in nearly all cases so far we tend to consider it a feature; modifiers work to address one of the cases where it's not 🙂
a

alexsullivan114

10/04/2019, 8:38 PM
Interesting. Out of curiosity, where do you see it coming in handy in opposition to the way that Flutter does it?
a

Adam Powell

10/04/2019, 8:40 PM
it means that any parameter that accepts a composable function object by definition has to be ready to accept practically anything, and also leads to some DRY around default layout policies for that content
a

alexsullivan114

10/04/2019, 8:42 PM
Actually that
Padding
example feels like an easier one to grok (i.e. padding wrapping two text objects) than a specialized container widget that semantically should wrap one widget wrapping multiple ones. Like, something to this tune:
Copy code
BlackOutline {
    Text("Howdy")
    Text("Ho")
}
Now
BlackOutline
needs to know how to layout its children. Does
BlackOutline
have any way of stating that it does not know how to layout children and accepts only one child to outline?
a

Adam Powell

10/04/2019, 8:43 PM
yeah, that's the challenge. And then how do you make that part of the type system of functions in a way that doesn't lead to a lot of additional things you have to understand
and then how do you make it robust to refactor/extract method and still get the same consistent analysis
a

alexsullivan114

10/04/2019, 8:44 PM
I guess the problem I'm having trouble getting around is how do you state that you only accept n children to your widget? I'm down with always needing to accept any composable function object - that seems fine.
a

Adam Powell

10/04/2019, 8:44 PM
exactly the problem we had trouble getting around too 🙂
r

Ruckus

10/04/2019, 8:44 PM
any parameter that accepts a composable function object by definition has to be ready to accept practically anything
@Adam Powell Are there any plans/ideas on how to work around that, or is it now a defined limitation of Compose?
a

alexsullivan114

10/04/2019, 8:44 PM
But that problem still exists even with modifiers, right?
a

Adam Powell

10/04/2019, 8:46 PM
it does for slot-driven composable function APIs, yes. In some cases it's a strength in that you know you can put anything there and set expectations; in some cases it's a limitation. Depends on your perspective that day, really. 🙂
practically speaking it means that when you're writing a composable function API that accepts a composable function parameter as content, you have to define how it handles multiple layout children
a

alexsullivan114

10/04/2019, 8:47 PM
I wonder if there's any good way to enforce that you have to define how it handles multiple layout children.
I could see a world where people just assume that their widgets will only have one child. Which is maybe fine? Could be painful to debug some UI issue caused by passing multiple children into a composable function that only expects one
a

Adam Powell

10/04/2019, 8:49 PM
yeah, practically speaking that arises when you write a custom
Layout
that measures/positions the first measurable it receives and drops the rest on the floor. A humane implementation of such a thing might throw if
measurables.size > 1
but at this point we've already moved the checking to runtime and we're talking about debugger vs. static analysis
a

alexsullivan114

10/04/2019, 8:50 PM
Yeah - that throwing strategy is the best I can think of but it does move what is a type error in Flutter to a runtime error in Compose. Which is a bit of a bummer
Actually I bet some nice IDE warnings would alleviate that problem a lot.
a

Adam Powell

10/04/2019, 8:51 PM
yeah if you just want to catch the super straightforward cases you can do it with things like lint
@Ruckus to be explicit: for now it's a defined behavior unless something major changes
r

Ruckus

10/04/2019, 9:01 PM
Fair enough. Thanks
r

romainguy

10/04/2019, 9:03 PM
IDE warnings help and we've discussed them extensively but they don't help in code reviews or other editors
a

alexsullivan114

10/05/2019, 12:22 PM
Yeah. They're also kind of a poor mans types. I don't see how else you can enforce a number of siblings with the lambda approach that's in there now...
k

kioba

10/06/2019, 10:50 AM
with a return value these problems could be easily addressed. All of these problems are surfacing due to the side-effect based design of compose.
view hierarchies can be flattened and there are great examples of it. comprehension from functional programming is one of them and it plays nice with the function design of compose.
a

Adam Powell

10/09/2019, 12:50 PM
It'll probably be removed as this direction stabilizes
l

Luca Nicoletti

10/09/2019, 12:51 PM
So you’re going in that direction, and are keeping it only because you haven’t done with the migration in base components yet; correct? 🙂
a

Adam Powell

10/09/2019, 12:53 PM
So far, yes. 🙂 I'm hedging a bit here because it's still quite early in Compose's life, but these are things that have been deliberated quite a bit so far and we're fairly sure about at this point
l

Luca Nicoletti

10/09/2019, 1:01 PM
Thanks 🙂
a

Adam Powell

10/09/2019, 1:06 PM
As for this being a result of other decisions in the model, yes, we're aware. 🙂 @Leland Richardson [G]'s post from a while back goes into some of why we think this is still the right set of tradeoffs http://intelligiblebabble.com/compose-from-first-principles/
l

Leland Richardson [G]

10/09/2019, 6:48 PM
i haven’t read this entire thread but reading up a few lines, the move to modifiers in compose UI and the choice to not have tree structure defined as the return value of a composable feel like pretty separate decisions in my mind
this has been brought up quite a bit before but the quote above from my blog is maybe part of the logic but really only a small piece
this is a fairly large difference between models that we took and other libs took such as flutter and react etc. time will tell if it was the right decision but i’m pretty confident that we will look back on this choice fondly
using the return value (a la react/flutter/etc) means that there’s actually a thing that you are able to hold on to. which means that you (the user) have the capability to hold on to it, inspect it, save it, use it later, etc.
this means that you (1) have to allocate that thing and (2) have to deal with what you not returning it actually means
in practice in react/flutter/etc, people rarely take advantage of this capability (so i don’t think it’s an important ability), but it forces one’s hand in terms of how the architecture actually works
by using execution itself as the structure, we are able to be much more flexible in terms of what we allocate and more innovative in terms of how the runtime actually builds up your UI’s structure
the neat thing is that in addition to all of this, this also opens up the return value slot as a thing that people can use
this we later realized meant that we could take things like
memo
and
state
and turn them into composable functions themselves
this means that while react has two separate concepts for things like “hooks” and “jsx elements / components”, we can have just one
and it also means that our “composable functions” can really just be “functions PLUS capability” instead of “functions PLUS capability A MINUS capability B”
a

alexsullivan114

10/09/2019, 7:26 PM
Those were all interesting great points. You're correct though, this thread has passed its point of usefulness. In retrospect, my question should've gone to just the channel. I think we can call it on this thread!
l

Leland Richardson [G]

10/09/2019, 7:50 PM
it’s still useful to talk about it. some of these points haven’t really been pointed out outside of just internal conversations and lots of people will be curious. we might want to write some more about this in the future in a higher distribution channel
anyway, don’t feel bad for asking questions!