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

napperley

05/21/2019, 11:11 PM
Sounds like Compose is strongly moving in the Functional direction (aka Functional DSLs). Would there be any plans in the compose language proposal on how state is managed? Do think that the compose language proposal should include the ability to initialise the context in a code block without having to pass through function parameters, so a user can use a composable API like this eg:
Copy code
// ...
StoryWidget {
    story = StoryData
    Clickable {
        onClick = onClick
        Padding {
            amount = 8.dp
            Column {
                Title { txtContent = story.title }
                Image { src = story.image }
                Text { txtContent = story.content }
            }
        }
    }
}
👎 4
c

Chuck Jazdzewski [G]

05/21/2019, 11:22 PM
We considered this syntax and there are issues with it. First it introduces into the scope symbols which are ambiguous which you see in your example
onClick = onClick
It might be clear you that the
onClick
you are setting is the
Clickable::onClick
but does right-hand
onClick
refer to the readable value of the
Clickable::onClick
or some outer scope
onClick
. Does it require
onClick@MyWidget
to disambiguate? Also, we want to be able to skip the call to
Clickable
if all the values passed to it are the same. If you can mix in statements it becomes unclear what can be skipped and what cannot be. The function call syntax already resolves these issues by having a parameters.
n

napperley

05/21/2019, 11:27 PM
Biggest issue with the function call syntax is that it cannot be made free form. For instance one cannot define a variable for use in simple calculations, and function calls can't be made which limits functional composition potential.
In the example above there is a typo. The
onClick = onClick
should be
onClick = onClick@MyWidget
which isn't ambiguous.
c

Chuck Jazdzewski [G]

05/21/2019, 11:31 PM
Even if you can disambiguate the expression, the fact you need to remember to do it is a problem as unedited version is legal and wrong.
Can you give an example "free form" use that the current syntax is preventing?
n

napperley

05/21/2019, 11:32 PM
Function call syntax is highly inflexible and makes the APIs too rigid. Always desirable to provide APIs that can provide some flexibility.
c

Chuck Jazdzewski [G]

05/21/2019, 11:32 PM
Can you give me an example?
The example above is can be transformed into
Copy code
StoryWidget(story = story) {
  Clickable(onClick = onClick) {
    Padding(amount = 8.dp) {
      Column {
        Title(text = story.title)
        Image(src = story.image)
        Text(text = story.content)
      }
    }
  }
}
One large problem with the proposed syntax is that is becomes unclear what to do with:
Copy code
Padding {
  if (indented) amount = 8.dp
}
What is unclear is what happens when
indented
turns from
true
to
false
? It is unclear what to do with this as it needs to "unset" the value
amount
. The current syntax never gets into this situation.
n

napperley

05/21/2019, 11:41 PM
Here is the free form example:
Copy code
// ...
StoryWidget {
    val newAuthor = "$firstName $lastName"
    validateAuthor(newAuthor)

    author = newAuthor
    story = StoryData
    onClick = onClick@MyWidget
    Padding {
        amount = 8.dp
        Column {
            Title { txtContent = story.title }
            Image { src = story.image }
            Text { txtContent = story.content }
        }
    }
}
c

Chuck Jazdzewski [G]

05/21/2019, 11:44 PM
First, validation of author should be done in the model not here as composition is the wrong place for validation. That aside, it largely a matter of style as the
val newAuthor
can be lifted one level and you get:
Copy code
val newAuthor = "$firstName $lastName"
StoryWidget(author = newAuthor, story = story) {
   ...
}
8
Or simply,
Copy code
StoryWidget(author = "$firstName $lastName", ...) {
   ...
}
g

gildor

05/22/2019, 12:30 AM
Isn't this synax requires receiver (aka own class for each component and instance of this class for scope) for each widget type and this receiver should be mutable?
b

bdawg.io

05/22/2019, 1:08 AM
I find the function call syntax way more idiomatic. Is a specific nested component just a function? Is it an object constructor? The beauty of the Kotlin function/constructor syntax is why should we care which one it is if that's the interface of the component regardless? Existing XML layouts are declarative and the most awkward part of them IMO are the object references, which you would need to have if you want compose to provide builder patterns
n

napperley

05/22/2019, 2:07 AM
A constructor doesn't use curly braces (not normally and if so it wouldn't be Kotlinic - making the constructor behave like a function even though it isn't). Don't agree that the function call syntax is Kotlinic (idiomatic Kotlin) since Kotlin is a hybrid programming language (can easily mix both OOP and Functional concepts seamlessly), and not a pure Functional language, which is to be taken into account with the Compose library design. Compose is using both Functional and OOP concepts even though it is mainly heading down the Functional path.
🤔 1
c

cedric

05/22/2019, 2:49 AM
At the risk of being pedantic, the fact that
Text()
and others return
Unit
is not exactly functional.
I don't really care personally, the rationale for this given earlier by (Leland or Adam, forgot) is convincing enough.
4
s

streetsofboston

05/22/2019, 2:58 AM
@cedric Writing to a screen, rendering, is a side-effect and it could return Unit much like a bunch of `println`s. The way I see it is that the Compose annotation could be seen as something like the functional type
IO<Unit>
of the function it annotates.
I wonder what @raulraja would have to say about this being functional or not :-)
👍 1
c

cedric

05/22/2019, 3:03 AM
Pretty sure he'd say it's barely composable, let alone functional :)
😀 4
t

themishkun

05/22/2019, 5:04 AM
The syntax you proposed mixes things up. Add a receiver up and you'll find yourself in the awkward position where you can't distinguish between tree modifications and logic. Also how would you actually *de*compose your "freeform" into separate functions?
1
And also, regarding variables and statements - you always can use
run
block when passing parameter, or make all of the calculations beforehand
r

raulraja

05/22/2019, 7:28 AM
Compose is not functional, as @cedric mentioned it returns Unit. The only useful thing you can do with a Unit return is perform effects. Also personally I dislike builders that use mutability like this. The same can be achieved with immutable data classes and a few extra comas. Also I agree that for this to be interesting it needs to bake in state management otherwise is nothing but another view building DSL with less power than most other UI frameworks like React etc.
t

themishkun

05/22/2019, 8:32 AM
@raulraja It actually performs state management behind the scenes.
@Compose
annotation adds implicit argument that handles all of the memoization and computations
r

raulraja

05/22/2019, 9:01 AM
@themishkun thanks!, any useful links or docs where I can read about it?
All I found about it does not mention state or how this is done
g

gildor

05/22/2019, 9:02 AM
If you check this channel and threads you can get many parts about implementation details, Compose team promise to publish some blogposts about it
t

themishkun

05/22/2019, 9:10 AM
@raulraja it is a pre-alpha release, the docs are pretty laconic about implementation, but you can check https://github.com/aosp-mirror/platform_frameworks_support/blob/androidx-master-dev/compose/runtime/src/main/java/androidx/compose/Composer.kt for the most interesting parts)
r

raulraja

05/22/2019, 9:13 AM
thanks!
c

cedric

05/22/2019, 5:38 PM
What I find interesting is that the Compose code that you see on the screen is only the very, very tiny tip of a giant iceberg, since so much is happening behind the scenes. Trying to assess whether that code is functional (which I don’t find a very useful exercise to be honest, so this is just for the sake of argument) is actually not that trivial.
👍 1
n

napperley

05/22/2019, 10:58 PM
Indeed, the Compose library is doing too much magical stuff.
f

Fudge

05/23/2019, 8:50 AM
The
@Composable
is just a few syntactic sugar improvements
n

napperley

05/23/2019, 9:11 PM
Annotations are still magical even though some good explanations have been provided in the article on how Compose works under the hood, which clears up some issues. It is important to realise that annotations are not like programming language keywords. One of the Compose team members is planning to put forth a Compose proposal to the Kotlin team, which if accepted would significantly reduce the in the Compose library by minimising the need to use annotations, and removes the need to use compiler plugins.
b

bdawg.io

05/23/2019, 9:37 PM
It's because it becomes part of the compiler itself haha
2
g

gildor

05/24/2019, 12:46 AM
I'm against including such domain specific syntax to the language, because you need not only modifier, but also runtime library for this, at least basic one, and this goes completely against current ideology of compose as unbundled library. One more problem is that @Compose is not the only annotation I don't see significant difference between @Compose and compose modifier, it a bit better synthactically and originally Kotlin had modifier-like syntax for annotations, but it was dropped because cause significant problems with tooling I'm also not sure that I would like to allow compiler plugins introduce new keywords, especially, if in case if compose, it very easy to solve using annotations and possible to do using compiler plugin, not everything should be a part of the language, I think every attempt modify language, just because of some minor style changes, just because somehow annotations are and a new language modifier is not are not just counterproductive as for composer and for Kotlin but imo just harmful, because do not allow to focus on library development, instead just cause more bikeshedding
t

themishkun

05/24/2019, 6:49 AM
@napperley how removing of the
@
suppose to reduce "magic"?
4
b

bdawg.io

05/24/2019, 7:04 AM
We already have annotations. And if compiler plugins make them a much better experience to use than kapt, then all the better without a need for a new source code paradigm
g

gildor

05/24/2019, 7:05 AM
How annotation vs modifier is related to kapt?
b

bdawg.io

05/24/2019, 7:05 AM
I'm talking about not needing modifiers because we already have annotations. It's more of compiler plugins vs kapt
g

gildor

05/24/2019, 7:06 AM
but nobody talks about kapt
and it’s impossible to modify code with kapt/apt, only generate new
this is the main point of compiler plugins
1
b

bdawg.io

05/24/2019, 7:07 AM
Exactly what I'm saying haha
compiler plugins make them a much better experience to use than kapt....without a need for a new source code paradigm
g

gildor

05/24/2019, 7:07 AM
But I’m completely agree, that why introduce modifiers if annotation is just fine
4 Views