What about using Pkl instead of Yaml for Amper? <h...
# amper
s
What about using Pkl instead of Yaml for Amper?

https://youtu.be/lAxXWYAIt4k?si=5LqopkiisdjuLU8G

https://github.com/apple/pkl
j
👍 3
It must be noted that there are a bunch of things in pkl that might get in the way of 2-way tooling, though. For example: methods, conditions, and other imperative-looking things. So even if we chose pkl we would probably have to limit it in some way, but with that in mind it's definitely an option worth considering.
❤️ 1
j
I don’t get the point about blocking methods, conditions and so on. If you need to block the user, then the problem is the exposed DSL that is not enough and the user needs to do workaround. Fix the exposed DSL so even the users could use any complex config, they will not. If not, the breach between “build engineers” and “no build engineers” will increase. Blocking pkl power to get the same a Yaml provides with a different syntax is wasting money in my opinion, you can just use Yaml.
s
I will have a deeper look to Amper + Pkl and share my feedback, especially on this « blocking methods and other features » point.
thank you color 1
j
> If you need to block the user, then the problem is the exposed DSL that is not enough and the user needs to do workaround. Fix the exposed DSL so even the users could use any complex config, they will not. That might seem fair, but it's not the point. Even in the best of worlds where users don't need to use imperative features, having the features in the language means that the tooling might be hindered in some way or another. When using Gradle properly you shouldn't need imperative logic in build scripts, yet the tooling cannot rely on this assumption, it's definitely not an invariant that can be used when writing tools that modify the build scripts, because by essence they are still scripts. > Fix the exposed DSL so even the users could use any complex config, they will not. Assuming we do this, why do you need such pkl power then?
j
Assuming we do this, why do you need such pkl power then?
Because it is impossible to fix all complex use cases, they will exist, that is the real reason behind:
If not, the breach between “build engineers” and “no build engineers” will increase.
No build devs will be far away from Gradle. Before or after, they will get blocked by a constrained solution like what a Yaml or a subset of Kotlin/PKL could provide. So they will have even more problems than today to fix those scenarios because they will have zero knowledge about the build tool they are indeed using behind the scenes. You need to reduce them to the minimum, but splitting the tools into multiple ones will lead to more problems outside basic projects. Personally, I prefer PKL, without blocking it, over Yaml (I even prefer a stone over a blocking config language). But for me, you already have the perfect language for this purpose, Kotlin. It will be possible to create really good DSLs with Kotlin + context parameters/receivers to reduce the imperative logic. But you cannot wrap the world (each Gradle plugin in the market) in Amper. Fix Gradle to allow creating plugins easily with good practices (tons of APIs should have been fired years ago and they are still there), and fix the DSLs. Create tutorials about how create good DSLs.
j
I think we're not talking about the same things here. I am not talking about extensibility/plugins, but only about the configuration language for the developer-facing part of the tool. The thing that IDEs and other tools will need to read and edit as much as devs. The complex needs / custom tasks / plugins etc. are another story, less related to the config language of the declarative configuration.
j
My point is, just to have an if-else for a simple use case that Amper is not wrapping, you are going to force creating an included build, do something with Gradle, and bind that somehow in Amper?
How is that more simple than just having the same DSL and allowing the if-else?
j
We'll definitely think of a better way to do this for users. The acceptable solution for this kind of problems will have to be simpler, I definitely agree with you. The point I'm trying to make is that allowing the `if`s/methods/etc. in the declarative language will make it impossible for the tooling to just "parse" the configuration, and it will need to "execute" it instead. This means having to run some sort of process (maybe a daemon), having a proper environment to run it, etc. This also means the IDE no longer knows where to insert new bits of configuration because there are now infinite ways to do the same thing, and it's not possible to know where the user expects this bit of config to be placed. About 10min ago, I auto-completed some Ktor engine name in my
HttpClient
config, and the IDE tried to insert the dependency on this engine in my multiplatform build script in Gradle, and miserably failed at it (it inserted a
dependencies { .. }
top-level block completely outside of my
kotlin.sourceSets.commonMain.dependencies { .. }
block). But I can't really blame it. How would it know in which source set to add the dependency? I haven't even extracted anything related to dependencies in a convention plugin, nor extracted any variable or functions in this build script, but the fact that I have this possibility makes the task of improving this IDE feature next to impossible.
👍 3
👍🏽 1
By the way, all the above is only my personal opinion on the matter, not the Amper team's opinion. We'll definitely consider all of this as a team 😉
j
Yeah, I think those are a lot of things that JetBrains and Gradle could improve a lot. A lot of things in Gradle are totally oriented to be consumed on Java, so third party plugins can have a lot of problems integrating with them. Fixtures, test suites, source sets APIs, and so on. They should be moved to a more abstract approach. The dependencies block shouldn’t exist if it is not created by a plugin, as it has limitations about getting accessors generated on time so it will not be a friendly way to add dependencies from KMP there as you need to use the string extension method.
s
I was a bit nervous about JetBrains having to create a custom subset of Pkl for Amper use case, but reading the documentation I see here: « Pcf (a static subset of Pkl) ». @Joffrey Is it something that would be more suitable for Amper use case from your POV?
thank you color 1
j
That sounds quite interesting (cc @dsavvinov). I coudn't find anything about Pcf with a quick search on the pkl website, is there any more comprehensive info about this subset apart from a couple mentions?
s
Not found yet but worth to dig deeper IMO
j
Yep, thanks for pointing that out in any case!
👍 1
s
One option could be to ask more details about Pcf on https://github.com/apple/pkl/discussions
j
For sure everyone looks at amper from different perspectives and as a potential tool to serve their individual needs. For me it is a chance to have a consistent and deterministic configuration, finally. Gradle’s a powerful and mighty programming language tailored for builds, but that’s it: it’s programming language, not just configuration language. And as such, it’s much harder to build a tool that will, idk… download all dependencies for offline use. Or check if all versions are up-to-date. Just look how long it took the DependaBot team to be finally able to analyze gradle builds. What I’m looking for is not yet another “convention over configuration but if you want it another way here’s how” tooling, but rather “convention. period.” You want dependencies declared? Here’s the only way to do it. You want build artifacts versioning? Here’s the only way to do it. etc, etc. I understand very much that the world is more complicated and often there are valid cases when rich customization is required, but for that we can still have gradle. YMMV, as always. That being said, I’m still excited with Pkl. I hope that there’s a way to drop the “imperative functionalities” to keep it all simple and parseable and easy for tooling.
a
Could you share several use-cases, where you think YAML (or other declarative language) sets unacceptable limitation so that imperative logic the configuration is required?
c
To the point about build engineers versus not: In my experience Gradle forces me to be a build engineer. Every project I work on requires some convention plugins. Most of the time I feel it should be doable declaratively instead of writing a custom plugin. Amper's templates seem to be a step in this direction. If it reduces the need for build engineering I'm all for it
s
To me one of the main questions is what is the main extensibility model for Amper when I reaches the limit of the imperative format. • Pkl "imperative features"? • Gradle Kotlin DSL? • Gradle plugins? • Gradle "buildSrc"?
I would be interested to know the latest status of JetBrains related thoughts (in order to avoid doing all the thought process from scratch).
a
We don’t consider adding imperative features in the configuration. As @joffrey mentioned, our approach to the design is that the configuration part is declarative data, while the actual build logic part is the regular imperative code. Here are some ideas on the extensibility. This doesn’t mean that we are not going to support the workflows that currently require imperative code in Gradle. Such as different configuration for CI and local development. Such workflows could be supported on the different abstraction level, though. E.g. by introducing Maven-like profiles, as one of the option. That’s why I’m asking about the use-cases. Understanding the use-cases will help us decide whether and how we want to support them