Marcello Galhardo
06/14/2023, 10:09 AMRow
, Column
, and similar view groups but it is heavily customisable. Basically, you can do something like:
// Definition, kind of:
@resultBuilder
struct SettingsBuilder {
static func buildBlock() -> [Setting] { [] }
}
func makeSettings(@SettingsBuilder _ content: () -> [Setting]) -> [Setting] {
content()
}
// Usage, each line is an item in the array:
makeSettings {
Setting(name: "Offline mode", value: .bool(false))
Setting(name: "Search page size", value: .int(25))
}
That would be similar to what we have with Compose groups, I guess:
Row {
Text("Offline mode")
Second("Search page size")
}
The nice part is that you can create and customize your own “view group”-like DSL to build your APIs. Is there anything similar in the plans for Kotlin?Daniele Segato
06/19/2023, 4:50 PMdata interface GenericEntity(
val id: String,
val created: Instant,
)
data class Customer(
val name: String,
): GenericEntity
I suppose the syntax I propose here isn't the best...
Anyway, the idea would be to have the interface allow usage of copy methods as if it was a data class with just those values and ease up reuse of common data structures.
Currently there's no way to rely on the copy and other helpers methods of data classes unless you expose the implementation.mikehearn
06/21/2023, 10:36 AMif (val foobar != null) { ... }
where foobar
is earlier declared as a nullable var. Today you can do this by writing foobar?.let { foobar -> .... }
but I dislike this:
1. It is a conditional but looks nothing like one. The meaning isn't obvious to someone new to Kotlin even if it's logical.
2. The name of the variable is repeated twice.
3. It requires an even uglier form if you're doing a type based smart cast i.e. (foobar as? Thing)?.let { ... }
, compare to if (val foobar is Thing) { ... }
.
This new syntactic form would combine the check with capturing current value of the variable onto the stack and shadowing the name.Adam S
06/22/2023, 10:22 AMinternal external interface ValuesManager {
fun access(id: Int) : LibValue
}
/** Some value, might be X/Y/Z - use extension functions to convert (...) */
external interface LibValue
Perhaps code marked as ‘external’ could be assumed to be ‘internal’, and could be specifically overridden to be ‘public’ or ‘private’?
// internal is inferred, but can be manually specified if required
/*internal*/ external interface ValuesManager {
fun access(id: Int) : LibValue
}
// have to explicitly type 'public'
public external interface LibValue
Or will https://youtrack.jetbrains.com/issue/KT-29227 help?Peter
06/22/2023, 9:21 PMbuildList
if I modify a list but at the end of the method want to return a read-only version of that same list. However because buildList uses a mutable-list as its receiver, it often makes invoking other methods in the same object a bit clumsy. Suddenly my code is full of this@… syntax.
So what I do is define something like this and use that instead:
inline fun <E> createList(
capacity: Int = 10,
builderAction: (MutableList<E>) -> Unit
): List<E> = _buildList_(capacity) *{*
builderAction(this)
}
But of course that is not ideal. So I was wondering if there are proposals on the horizon to make buildList (or other similar scenarios) nicer to use (like would multiple-receivers also solve this use-case)?
Or perhaps people don’t mind the this@.. syntax that much?Derek Peirce
06/28/2023, 4:42 PMclass Foo: Bar by bar {
val bar: Bar = ...
}
This would get Unresolved reference: bar
. Is there any reasoning for this other than the order in which the compiler is evaluating symbols? Could the compiler be improved so that it understands that bar
exists, and generates the proper delegation code?
override fun doBar() = bar.doBar()
I'd also like to see the ability to delegate by method instead of by entire interface, something like:
override fun doBar() by bar
with specifying the arguments being optional, otherwise all possible overloads are delegated.Chris Fillmore
07/20/2023, 2:49 PMval (a, b) by myDelegate {
"a" to "b"
}
Currently this errors with Initializer required for destructuring declaration
.
Thanks!xxfast
07/28/2023, 2:46 AMDerek Peirce
07/30/2023, 1:44 AMoverride fun compareTo(other: Item): Int {
return compareValuesBy(this, other, { foo }, { bar })
}
The version that takes one argument is `inline`:
@kotlin.internal.InlineOnly
public inline fun <T> compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*>?): Int {
return compareValues(selector(a), selector(b))
}
but the one that takes a variable number is not:
public fun <T> compareValuesBy(a: T, b: T, vararg selectors: (T) -> Comparable<*>?): Int {
require(selectors.size > 0)
return compareValuesByImpl(a, b, selectors)
}
This makes it considerably less efficient. This could be solved by just adding different compareValuesBy
methods with different lambda counts to stdlib, but the more forward-thinking approach is to inline the lambdas and unroll the loop on the array.
I tried searching for the topic, and found only my own post from 2020, which included a performance test demonstrating that inlining is faster. I haven't found any other progress on it, is this something on the Kotlin roadmap?
https://discuss.kotlinlang.org/t/inlining-arrays-of-lambdas/18249Jordan Terrell
08/24/2023, 4:20 PMzsqw123
09/23/2023, 5:42 PMclass Foo {
api fun bar(): String
}
// write in another file
impl fun Foo.bar() = "bar"
The reason I want to implement this is that I want the actual implementation of the bar
function to be implemented by KSP generated code, and I want it to be a member function that does not require import and does not need to wait for KspDebug
to finish executing before calling toSeth Madison
10/10/2023, 3:55 AMJsExport
code this is becoming more important to us. It feels there should be a way to do this built into the language.mitch
10/12/2023, 12:29 AMT?
to adopt swift-style optionals that nests correctly e.g. T?
is optional and T??
means optional of optional. That perhaps can be enabled with a compiler option (because of the possibility for breaking interop with Java). I just realized how misleading nullables can be when paired with generic codes due to the null
auto-flattened... I believe this is known as the nested nullability problem in Kotlin (i.e. T?
and T???????
are the same thing: null
). I'm surprised not many online sources that talk about this problem...
Use-case:
to hopefully explain my pain.. a toy example with `List<T?>`:
val myList: List<T?> = ....
/**
* if the result is null, does it mean:
* - the first element is null, or
* - [myList] is empty?
*/
val first: T? = myList.firstOrNull()
println(first) // null :( but why???
what I really need (thinking of swift here)
val myList: List<T?> = ....
// notice ?? - I can then know
val first: T?? = myList.firstOrNull()
println(first) // some(nil) list isn't empty, first value is nil
uli
10/13/2023, 1:30 PM1: fun verificationText(verified: Boolean) : String {
2: return when {
3: verified -> "Verified"
4: verified.not() -> "Not verified"
5: }
6: }
1. Error: ‘when’ expression must be exhaustive, add necessary ‘else’ branch (Line 2)
2. Warning: Value of ‘verified’ is always false (Line 4)
I disagree with the compiler. For me (2) means “yes, we have a catch all case. No need for exhaustive error, no need for warning.
In my everyday work, I use when expressions to exhaustively map combinations of boolean flags and feel that adding an else branch to the when above, just to shut up the compiler is big pain.PHondogo
10/16/2023, 11:09 AMclass Context {
val v: Int = 1
}
class X {
val v: Int = 0
fun Context.test() {
println(v) // such cases are difficult for code readers. Suggest to issue warning if not explicitly specified this@... for them
}
}
Laxystem
10/24/2023, 12:53 PMclass Foo(bar: String)
// three mentions of Foo in explicit api! Java interop is horrible! The IDE doesn't know this is a constructor, complains about the naming, and stylizes incorrectly!
fun Foo(bar: Int?): Foo = Foo(bar.toString())
// An extension secondary constructor! Java thinks it's a static method named "fooOf".
Foo.constructor(bar: Int?) : this(bar.toString())
// Alternate syntax
constructor Foo(bar: Int?) : this(bar.toString())
// And extension "inner" classes, for free!
context(String)
Foo.constructor() : this(this@String)
Ben Woodworth
10/25/2023, 7:43 AMbreak
and continue
as operator functions, for use in loop-like functions? I'm imagining the compiler seeing that the operators present in scope, allowing break/continue, and compile down to a return to end the current block early, then call the operator functions to let the loop-like function know to handle it. It'd be useful in stdlib functions like forEach, and for me, a parameterized loop library I'm working on (here).
I'm picturing something like this:
class LoopScope {
internal var shouldBreak = false
operator fun onBreak() {
shouldBreak = true
}
operator fun onContinue() {
// no handling needed, the compiler just inserts a return in the current scope
}
}
fun loop(block: LoopScope.() -> Unit) {
val scope = LoopScope()
do {
scope.block()
} while (!scope.shouldBreak)
}
Matthew Pope
11/17/2023, 8:28 PM@RequiresOptIn annotation class Unsafe
to mark the unsafe functions, but I would like to have a custom annotation to opt in, such as annotation class SafeBecause(val reason: String)
so that (a) you can't opt in for a whole file or class, and (b) I can force someone to document how we know it is safe to use this function. I don't think there's any mechanism to do this right now.
I think there's a few approaches to this. All of them would require compiler support (I think).
1. Add a new field to RequiresOptIn
, so that we could define unsafe like this: @RequiresOptIn(optInWith = SafeBecause::class) annotation class Unsafe
. This actually fulfills the two requirements I had. Because you pick your own annotation to opt in, you can create one that only targets expressions, and you can have a mandatory "reason" field.
2. Introduce an OptsInto
annotation that is the complement of `RequiresOptIn`; that is to say, it annotates another annotation which can then be use instead of @OptIn
. For example @OptsInto(Unsafe::class) annotation class SafeBecause(val reason: String)
could be used instead of @OptIn(Unsafe::class)
. There is some nice symmetry to this, but it implies that it would be possible to create multiple annotations that would allow you to opt into a particular annotation. Would we have to add a rule that you can only create an OptsInto
for annotations that are defined in the same module?
3. Add a "reason" field to @OptIn
so that you can write @OptIn(Unsafe::class, "We already checked the precondition ...")
. This is probably the least invasive change, but it doesn't fulfill the goal of being able to limit the scope of opting in.
Thoughts?Slackbot
12/01/2023, 9:02 AMandylamax
12/01/2023, 9:30 AMtypealias LoggableDatabase = Loggable & Database
fun LoggableDatabase.listAll() : List<Thing> {
log("listing") // from (this as Loggable)
return query("select * from things") // from (this as Database)
}
Would endup being almost close to
context(Loggable,Database)
fun listAll() {
log("listing") // from (this as Loggable)
return query("select * from things") // from (this as Database)
}
This question can be phrased in another way.
e.g. Shouldn't the kotlin team work on intersection types and that will give us both, intersection types and context receivers functionality as well???? Thoughts????Daniel Pitts
12/09/2023, 1:04 AMfun <...Types> doThing(block: (Types...)->Unit, args: Types...){ block(*args) }
?anlex N
12/10/2023, 3:01 PMc++
// deriv_VirtualFunctions2.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;
class Base {
public:
virtual void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Base::NameOf() {
cout << "Base::NameOf\n";
}
void Base::InvokingClass() {
cout << "Invoked by Base\n";
}
class Derived : public Base {
public:
void NameOf(); // Virtual function.
void InvokingClass(); // Nonvirtual function.
};
// Implement the two functions.
void Derived::NameOf() {
cout << "Derived::NameOf\n";
}
void Derived::InvokingClass() {
cout << "Invoked by Derived\n";
}
int main() {
// Declare an object of type Derived.
Derived aDerived;
// Declare two pointers, one of type Derived * and the other
// of type Base *, and initialize them to point to aDerived.
Derived *pDerived = &aDerived;
Base *pBase = &aDerived;
// Call the functions.
pBase->NameOf(); // Call virtual function.
pBase->InvokingClass(); // Call nonvirtual function.
pDerived->NameOf(); // Call virtual function.
pDerived->InvokingClass(); // Call nonvirtual function.
}
how to convert this c++ to kotlin?Laxystem
12/13/2023, 11:32 AMAdam Chance
12/27/2023, 9:03 PMsuspend
functions for use outside of Kotlin code.
Example of creating a suspend
function and exposing it as a `CompletableFuture`:
suspend fun getMarketTaxRates(world: World): Map<City, Byte> {
doStuff()
}
@JvmName("getMarketTaxRates")
fun getMarketTaxRatesAsync(world: World) = GlobalScope.future {
getMarketTaxRates(world)
}
The function appended with Async
doesn't do anything beyond wrapping another suspend
function within a GlobalScope.Future
.
As an annotation this could look like:
@JvmFuture
suspend fun getMarketTaxRates(world: World): Map<City, Byte> {
doStuff()
}
which could automatically generate the wrapper function with @JvmName
set to the name of the original function.Ruckus
01/11/2024, 10:33 PMinterface Slot {
operator fun plus(count: Int): Slot
operator fun minus(count: Int): Slot
}
interface Shelf {
operator fun get(row: Int, col: Int): Slot
operator fun set(row: Int, col: Int, items: Slot)
}
We should be able to do this
shelf[3, 7] += 2
Felix Kranich
01/18/2024, 1:46 PMwhere
blocks to allow adding local bindings to single-expression functions without creating a block (similar to Haskell's where)
fun greet(hourOfDay: Int, name: String) = println(greeting + name)
where {
val greeting = when {
hourOfDay < 10 -> "Good morning, "
hourOfDay < 12 -> "Good day, "
hourOfDay < 17 -> "Good afternoon, "
else -> "Good evening, "
}
}
Laxystem
01/27/2024, 2:02 PMprivate fun firePositionChangeEvent() {
val x = x
val y = y
if (x != null && y != null) {
tile = onPositionChange(x, y)
}
}
// becomes
private fun firePositionChangeEvent() {
tile = if (catch val x != null && catch val y != null) onPositionChange(x, y) else null
}
Created KT-65359, proposing adding catch val
, a way to "catch" the current value of a mutable/delegated property for smartcasting purposes.Arkadii Ivanov
02/10/2024, 3:02 PMinterface Foo {
fun foo1()
fun foo2()
}
class FooImpl : Foo {
override fun foo1() { /*...*/ }
override fun foo2() { /*...*/ }
}
class Bar private constructor(
private val foo: Foo, // Private constructor as we don't want to expose the parameter
) : Foo by foo {
constructor() : this(foo = FooImpl())
override fun foo1() {
foo.foo1()
// Additional code here
}
}
It would be good to have something like this instead.
class Bar : Foo by foo@FooImpl() {
override fun foo1() {
foo.foo1()
// Additional code here
}
}
xxfast
02/14/2024, 4:07 AM+-
or .plusOrMinus
operator that does
val fruits = listOf("🍎", "🍊", "🍌")
print(fruits ± "🥝") // "🍎", "🍊", "🍌", "🥝"
print(fruits ± "🍊") // "🍎", "🍌"
which works like
operator fun <T> Collection<T>.plusOrMinus(item: T): Collection<T> =
if (item in this) this + item
else this - item
PHondogo
02/15/2024, 7:42 AMopen sealed class HistoryItem( // make it open to omit adding additional class. Something like: class StdHistoryItem(...) : HistoryItem(...)
val ts: Long,
val info: String
) {
open fun log() {
println("[$ts] $info")
}
}
class WithContextHistoryItem(
ts: Long,
info: String,
context: Any
) : HistoryItem(ts, info) {
override fun log() {
println("[$ts] $info ($context)")
}
}
fun main() {
val items = listOf( HistoryItem(1, "a"), WithContextHistoryItem(2, "b", "c") )
...
}