anlex 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
}
Derek Peirce
04/28/2024, 12:49 AM+
operator, should there be a way to implement a more efficient multi-plus method? Such as operator fun <E> Set<E>.plusAll(vararg others: Iterable<E>): Set<E>
? Currently, setA + setB + setC
will first create an intermediate setAB
set, so one must use something like:
buildSet {
addAll(setA)
addAll(setB)
addAll(setC)
}
to avoid the inefficiency, which is a fair bit more code to achieve the same result.jNayden
05/13/2024, 4:42 PMjoseph_ivie
06/11/2024, 4:33 PMObservable.map {}
and Observable.combine()
, and I don't blame them. It's not particularly easy to read. Similar APIs and problems exist with Android's LiveData
, Kotlin's own Flow
, and several other similar libraries. I wonder if we can make operating on these types read similarly or identical to simpler code, much like suspension makes writing async code look like sync code.
So here's the proposal, roughly:
@MonadFlattening
interface Observable<T> {
fun <OUT> map(transformer: (T)->OUT): Observable<OUT>
fun <OUT> flatMap(transformer: (T)->Observable<OUT>): Observable<OUT>
// For optimization purposes, not strictly speaking necessary
fun <B, OUT> combine(other: Observable<B>, transformer: (T, B)->OUT): Observable<OUT>
}
fun sample(x: Observable<Int>, y: Observable<Int>) {
// using & as a postfix operator to indicate the start of flattening. Don't think that's the right symbol, but we'll work with it for now
val onePlusX: Observable<Int> = 1 + x&
// reduces to
val onePlusX: Observable<Int> = x.map { 1 + it }
val xPlusY: Observable<Int> = x& + y&
// reduces to
val xPlusY: Observable<Int> = x.combine(y) { x1, y1 -> x1 + y1 }
val xAsString: Observable<String> = x&.toString()
// reduces to
val xAsString: Observable<String> = x.map { it.toString() }
val xSlashY: Observable<String> = "${x&} / ${y&}"
// reduces to
val xSlashY: Observable<String> = x.combine(y) { x1, y1 -> "$x1 / $y1" }
data class Point(val x: Int, val y: Int)
val point: Observable<Point> = Point(x&, y&)
val angle: Observable<Double> = atan2(y&.toDouble(), x&.toDouble())
}
This enables a better potential syntax for UI and data:
val counter = Observable.interval(1, TimeUnit.seconds)
val view: TextView = TODO()
view::setText bind "${counter&} seconds elapsed"
Problem is that I think this is an incredibly large overhaul. It affects just about every expression in the language.
I can see this enabling a lot of interesting ideas further down the line.
I feel like there are some issues with the idea I'm not seeing yet, but this could be really useful.Alejandro Serrano.Mena
06/17/2024, 3:52 PMlouiscad
06/25/2024, 10:58 PMDaniel Pitts
07/06/2024, 6:19 PMclass A
class B
fun make():A = A()
fun make():B = B()
fun main() {
val a:A = make()
val b:B = make()
}
Daniel Pitts
07/10/2024, 6:39 PMContext Parameters
available for use yet? I'm currently using Context Receivers
for some things, and found a show-stopping compiler bug with them.dave08
07/17/2024, 3:51 PMval baz = "foo.bar"
var foo: String
var bar: String
// for assigning the vars, not new vals...
(foo, bar) = baz.split('.')
Hayden Jones
08/07/2024, 11:39 AMOleg Yukhnevich
08/12/2024, 4:05 PMAlejandro Serrano.Mena
09/12/2024, 10:00 AMutenma
09/20/2024, 1:03 AMdmcg
09/26/2024, 8:06 AMCies
10/07/2024, 3:25 PMMaria Sokolova
11/07/2024, 11:46 AMAlejandro Serrano.Mena
12/20/2024, 5:31 PMAugusto Megener
12/28/2024, 1:13 PMimplement
statements,
they would serve as an alternative way to create extension members
kt
class Foo {
val bar = "hi"
}
implement Foo {
val baz get() = "$bar, kotlin!" // would work like val Foo .baz get() = "$bar, kotlin!"
}
syntax sugar for interface implementation wrappers for existing classes, when used in classes from other libraries
kt
class ExternalClass {
val foo= "hi"
}
interface MyInterface {
fun getText(): String
}
implement ExternalClass : MyInterface {
override fun getText() = foo
}
// internally creates a wrapper
@JvmInline
value class MyInterfaceExternalClass(val value: ExternalClass) : MyInterface {
override fun getText() = value.foo
}
// when ExternalClass is used in contexts that require MyInterface, internally the wrapper will be used, but in practice, you can use it as if it were actually ExternalClass
fun myFun(arg: MyInterface) {
println(arg.getText())
}
val obj = ExternalClass()
myFun(obj) // prints "hi"
and for separating classes in multiple files, but uniting everything in a single class, when used in project classes
// a.kt
class Class {
[...]
}
// b.kt
implement Class {
[...]
}
// c.kt
implement Class : MyInterface {
override fun getText() =randomValue
[...]
}
in my opinion this would be viable and useful, what do you think?Daniel Pitts
01/11/2025, 9:26 PMRoman Venediktov
02/04/2025, 10:16 AMJesse Gottlieb
02/04/2025, 8:12 PMapplyIf
, applyUnless
, alsoIf
, and alsoUnless
to the standard lib. I chose apply
and also
among the various scope functions because these functions simply return the receiver object, so the return type can still be known regardless of the predicate. As a server developer, I use applyIf
on builder objects quite frequently and my company has added it to an internal shared kotlin library. I suspect many kotlin devs use some version of this already.
An example would be:
inline fun <T> T.applyIf(predicate: Boolean, f: T.() -> Unit) = apply {
if (predicate) f()
}
val myPlanBuilder = MyPlan.newBuilder()
myObjectBuilder.applyIf(isSunnyOutside) {
addPlanLineItem(goGetIceCream)
}
Laxystem
02/18/2025, 10:41 AMsandwwraith
03/05/2025, 3:34 PMbobko
03/21/2025, 3:24 PMJaebaek Seo
04/16/2025, 8:56 PMDerek Peirce
04/27/2025, 6:02 AMCompletable.doOnEvent
, which takes a lambda `(Throwable?) -> Unit`:
myCompletable.doOnEvent { doSomething() }
However, this started throwing exceptions. As it is a Java method, Kotlin automatically regarded it
as Throwable!
and therefore Throwable
, and as soon as the lambda was called with a null value, it did a null check and threw a NPE, even though it was verifying a value that went completely unused.
As the only reason Kotlin automatically treats Throwable!
as Throwable
here is for convenience, could it recognize in this case that the parameter is entirely unused, and therefore not overeagerly perform a null check? The solution to avoid the exception is to specify { _: Throwable? -> doSomething() }
, which I'd rather not need to specify, and I'd especially have preferred not to have to deal with the exception in the first place at all.