Derek 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") )
...
}
Ayla
03/24/2024, 7:10 AMconst
class and const
collection
const
class restricts all field types to be immutable (non-read-only), which can bring more optimization possibilities for hashcode (caching, just like string) and copy (reusing immutable fields instead of full copy), and this helps ensure multi-thread safety.
const data class A(
val int:Int,
var mutableField:String,//error: fields of a const class should be immutable
val list:List<String>
)
const val instance= A(1,"",const ["1","2","3"])
const
collection can ensure that the collection is immutable, which can be combined with collection literals to eliminate the copy overhead of varargs
fun simpleFunction(const list:List<String>){}
fun varargsFunction(vararg item:String){}
var str=""
const val c1=const ["",str]//error:The elements of a const collection should be immutable
const val c2=const [""]
simpleFunction(list2)
varargsFunction(c2)
katz
03/25/2024, 1:47 PMfoo?: return
== if(foo == null) return
• How about add inverse operator
foo !: return
foo !: return foo
foo !: return it
[it==foo captured value]
all above equals to if(foo!=null) return *
Case:
bafore
val errors = getErrors()
if(errors != null) return errors
we had to create val to hold result and then type if
after:
getErrors() !: return it
way simplieranlex N
03/26/2024, 5:53 AManlex N
03/26/2024, 6:05 AMemptyList<String>()
have compared to listOf<String>()
?vach
04/14/2024, 1:34 PMGat Tag
04/19/2024, 1:24 PMinterface MyThing<A: Any, B: MyRoot?> { }
extension <A: Any, B: MyRoot?> (MyThing<A, B>){
val thingA: A get() = TODO()
val thingB: Optional<B & Any> get() = TODO()
val otherThing: (A) -> String by TODO()
fun <C: SomeType> doThing(): Pair<A, C> {
return TODO()
}
}
A reduction step would emit:
interface MyThing<A: Any, B: MyRoot?> { }
val <A: Any, B: MyRoot?> MyThing<A, B>.thingA: A get() = TODO()
val <A: Any, B: MyRoot?> MyThing<A, B>.thingB: Optional<B & Any> get() = TODO()
val <A: Any, B: MyRoot?> MyThing<A, B>.otherThing: (A) -> String by TODO()
fun <A: Any, B: MyRoot?, C: SomeType> MyThing<A, B>.doThing(): Pair<A, C> {
return TODO()
}
This syntax could also be used inside a class like declaration for member extension functions as well.
I could also see more widely applicable usage when allowing something similar for the upcoming context receivers allowing a block for which all declarations require the specified contexts.groostav
04/25/2024, 12:36 AMDontInferAny
so that I can avoid a call to Collection.minus<T>(it: T)
inferring T
is Any
?
I used to have this code
data class SimpleDomainValueType(name: String);
data class Customer(simples: List<SimpleDomainValueType>);
fun businessLogic(cust: Customer){
val specialSimples: List<SimpleDomainValueType> = doBusinessLogic()
val result = specialSimples- cust.simples
}
Then I did a refactor
data class SimpleDomainValueType(name: String);
class SimpleDomainValueCollection {
operator fun get(index: Int): SimpleDomainValueType = ...
val size: Int get() = ...
}
data class Customer(simples: SimpleDomainValueCollection);
And I spent 30 minutes tracking down that the line val result = specialSauceItems - cust.simples
still compiles, because minus
is effectively becoming
val result = specialSimples.minusElement<Any>(cust.simples)
which is definitely not what I want.
I suspect its not what the overwhelming majority of people want.
I would think we could tell kotlin something like:
public operator fun <@DontInferAny T> Iterable<T>.minus(elements: Iterable<T>): List<T>
to tell kotlin that Any
is not an acceptable resolution for T
here.
---
this would blow up a lot of existing code, especially people using raw-typed lists or similar 🙃 but it makes my life easier and thats all that matters so i want it.PHondogo
04/25/2024, 1:48 PM// interfaces declaration
@NotReferencable
interface SomeBuilder {
@AtLeastOnce
fun author(name: String)
fun comment(text: String)
@ExactlyOnce
fun body(lambda: SomeScope.()->Unit)
}
fun build(lambda: SomeBuilder.()->Unit)
// usage
var builder: SomeBuilder? = null
build {
builder = this // ERROR cause SomeBuilder is constrained with @NotReferencable
author(name = "Test name 1") // OK (if comment this line and line after than it is error at compile time, cause fun author must be called at least once)
author(name = "Test name 2") // OK
comment(text = "Comment 1") // OK (if comment this line and line after it still will be OK, cause there are no constraints for this function)
comment(text = "Comment 2") // OK
body {} // OK
body {} // ERROR cause exactly once constraint specified, if comment both lines that it will be an error cause of the same reason
}