https://kotlinlang.org logo
Docs
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
language-evolution
  • h

    Hullaballoonatic

    09/05/2020, 7:20 PM
    Why don't property setters use lambda syntax? I imagine it was considered and decided against:
    var foo = 6
        set {
            println("setting foo to $it")
            field = it
        }
    var foo = 6
        set { num ->
            println("this is maybe more tedious")
            field = num
        }
    👀 1
    🤔 3
    r
    e
    • 3
    • 2
  • r

    raulraja

    09/13/2020, 1:10 PM
    Working with the new features in 1.4 and finding some limitations such as the ability to declare abstract suspend members in
    fun interface
    . Is this just a current limitation or something that would not be supported because of the way SAM interop works in the compiler?
    fun interface DelimitedContinuation<A, B> {
      suspend operator fun invoke(a: A): B //fails to compile
    }
    g
    d
    e
    • 4
    • 7
  • a

    Animesh Sahu

    11/01/2020, 10:43 AM
    Why the new property delegation syntax was introduced in Kotlin 1.4:
    val delegatedProperty: Int by anotherObj::intProperty
    using reflection? When
    val delegatedProperty: Int get() = anotherObj.intProperty
    works out of the box (getter property without field). Doesn't the former will have performance penalty due to reflections are involved (
    KProperty0
    as seen by decompiler).
    g
    d
    • 3
    • 8
  • a

    Animesh Sahu

    11/09/2020, 5:52 PM
    Are object declarations (singletons) initialized statically or at the first access? The docs says:
    Object declaration's initialization is thread-safe and done at first access.
    But the following code
    object TestObject {
        val a = "hello"
        fun b(): Nothing = TODO()
    }
    decompiles as follows:
    public final class TestObject {
       @NotNull
       private static final String a;
       public static final TestObject INSTANCE;
    
       @NotNull
       public final String getA() {
          return a;
       }
    
       @NotNull
       public final Void b() {
          boolean var1 = false;
          throw (Throwable)(new NotImplementedError((String)null, 1, (DefaultConstructorMarker)null));
       }
    
       private TestObject() {
       }
    
       static {
          TestObject var0 = new TestObject();
          INSTANCE = var0;
          a = "hello";
       }
    }
    Tested with/without property and with/without function declaration. Same behavior static initialization, is the docs outdated?
    z
    n
    • 3
    • 7
  • a

    Animesh Sahu

    01/15/2021, 4:10 AM
    What's the recommended way to handle async object initialization? Since there are no suspend constructor, maybe a fake constructor (
    suspend operator fun invoke
    in the companion), or probably just wrap the result into a
    Deferred<>
    and call await() every time when needed?
    r
    b
    g
    • 4
    • 5
  • n

    natario1

    02/12/2021, 11:23 AM
    Curious as to why
    Number
    is a class as opposed to an interface, any hints?
    ➕ 1
    i
    k
    +3
    • 6
    • 6
  • q

    Quy D X Nguyen

    02/19/2021, 8:40 AM
    Is there a reason that nested destructuring isn't allowed? I'd suggest making it for easier refactoring/dealing with nested POD classes.
    ➕ 1
    w
    • 2
    • 1
  • a

    Alex Vanyo

    03/10/2021, 4:00 AM
    While experimenting with sealed interfaces and imagining how they might provide ways to model different hierarchies, I'm wondering if there's an opportunity to do some sort of smart casting or some sort of additional type resolution.
    sealed interface Alpha {
        interface A : Alpha
        interface B : Alpha
    }
    
    sealed class Beta /* : Alpha */ {
        object Y : Beta(), Alpha.A
        object Z : Beta(), Alpha.B
    }
    
    fun Beta.fix(): Alpha = when (this) {
        is Beta.Y -> this
        is Beta.Z -> this
    }
    
    fun first(beta: Beta) = second(beta.fix()) // Could fix() be implicit?
    
    fun second(alpha: Alpha) = when (alpha) {
        is Alpha.A -> "A"
        is Alpha.B -> "B"
    }
    All subclasses of
    Beta
    implement one of the subinterfaces of
    Alpha
    , so
    Beta is Alpha
    is always true. However,
    Beta
    can't directly implement
    Alpha
    without adding more subclasses to
    Alpha
    . It's possible to make this explicit with something like the
    Beta.fix()
    above, which shows that
    Beta is Alpha
    is always true, but it'd be really cool if that could be done automatically in some way.
    e
    • 2
    • 3
  • c

    christophsturm

    03/11/2021, 11:18 AM
    this seems to be better suited for here.
    u
    e
    • 3
    • 6
  • y

    Youssef Shoaib [MOD]

    03/18/2021, 7:52 PM
    Is there any publicly-available information about
    coeffects
    ? Because I heard that there's some internal discussions about it and the name itself sounds intriguing especially because it'll allegedly solve DI. Obviously it's in a very very very early stage, but if there's a keep or something for it so that the community can discuss it then that'd be quite hlepful
    e
    • 2
    • 5
  • c

    christophsturm

    03/19/2021, 10:20 AM
    the syntax for function references currently does not allow to distinguish between two versions of an overloaded method
    import kotlin.reflect.KCallable
    
    interface IImpl {
        fun method()
        fun method(number: Int, name: String)
        fun nonOverloadedMethod()
    }
    
    fun function(callref: KCallable<*>) {println(callref)}
    
    function(IImpl::nonOverloadedMethod)
    function(IImpl::method) // resolution ambiguity
    I wonder how a syntax that makes that work could look like
    🤔 1
    e
    y
    • 3
    • 15
  • m

    melatonina

    03/24/2021, 2:38 PM
    I would like to propose a new syntax to simplify expressions involving nullable types and avoid awkward nested
    ?.let { }
    expressions, in case it has not been discussed before. Whenever, inside of an expression, a
    ?
    (question mark) is appended to the name of a variable (mutable
    var
    or non mutable
    val
    ) of nullable type, the whole expression containing it would evaluate to
    null
    if that variable is
    null
    , otherwise the variable is cast to the respective non-nullable type.
    fun f(a: A): B = TODO()
    fun g(a: A?): B? = f(a?)
    fun h(a: Int?, b: Int): Int? = (a? + b)*2
    fun i(a: Int?, b: Int?, c: Int?): Int? = (a? + b?)*c?
    I don't know how to call this feature. Maybe "short-circuiting null operator"? As suggested by @uli, this feature is symmetric to the
    ?.
    operator, and would work on all arguments of a function like
    ?.
    does on the
    this
    argument. Would this syntax cause conflict with other language features? Would you consider its implementations?
    u
    i
    • 3
    • 13
  • d

    Derek Peirce

    03/27/2021, 6:04 AM
    Suppose that you wanted to combine two generated lists:
    val listA = listOf("foo", "bar")
        val listB = listOf("alpha", "beta", "gamma")
    
        val firstLetters = listA.map { it.first() } + listB.map { it.first() }
    +
    works, and it's as concise as can be, so everything is fine, right? Well, it works, but not very efficiently. If we inline the methods, we see that each
    map
    creates its own
    ArrayList
    , and then a third
    ArrayList
    is created with
    +
    to store all of them, which is two more list objects than we actually needed, because
    +
    respected that the individual lists shouldn't be mutated, even though they're never used again beyond this block of code. Consider a rewritten, more efficient form:
    val firstLetters = ArrayList<Char>(listA.size + listB.size).apply {
            listA.mapTo(this) { it.first() }
            listB.mapTo(this) { it.first() }
        }
    This creates exactly the single list that we need, no wasted objects. It's also terribly ugly. But what if Kotlin allowed us to use the concise expressiveness of the first functional line with the efficiency of the four lines above? It would have to recognize that
    map
    has a corresponding
    mapTo
    , and then that the results of
    map
    are used only by
    +
    . The second requirement is easy, but the first requires a bit more. What if
    mapTo
    didn't exist as a separate method from
    map
    ? Suppose
    map
    were written as:
    public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
        @CollectionBuilder val destination = ArrayList<R>(collectionSizeOrDefault(10))
        for (item in this)
            destination.add(transform(item))
        return destination
    }
    @CollectionBuilder
    would indicate to the compiler that it should build two versions of
    map
    , the one above and a transformed one, `map_collectionBuilder`:
    public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.map_collectionBuilder(destination: C, transform: (T) -> R): C {
        for (item in this)
            destination.add(transform(item))
        return destination
    }
    This is, of course, the original
    mapTo
    . As long as the result of
    add
    is never checked, it should be possible for any method that builds its own collection to instead append to an existing one, with the type
    List
    being effectively the default output. The compiler can then create its own empty list and fill it with each
    map_collectionBuilder
    call automatically. The only remaining problem is how to right-size that list. Maybe it would add the two existing
    collectionSizeOrDefault
    calls together, but that could get tricky to find. Or maybe the
    map
    method would need an annotation to give a hint to this collection-optimization step that this method creates a collection that is exactly as large as the input,
    @SameSizeOutput
    , while others like
    filter
    may indicate that as a ceiling,
    @SameSizeOrSmallerOutput
    . In such a case, perhaps the methods would be inverted, and we write this one method instead:
    public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.mapTo(@CollectionBuilder(directName = "map", size = SAME_SIZE) destination: C, transform: (T) -> R): C {
        for (item in this)
            destination.add(transform(item))
        return destination
    }
    and the corresponding
    map
    would be generated from there. If it seems strange for the language to specifically optimize
    +
    on collections like this, we've already done it for
    String
    , converting repeated `+`s into `StringBuilder`s, we may as well offer something similar to collections.
    y
    • 2
    • 14
  • r

    Rob Elliot

    03/30/2021, 3:42 PM
    How bad would it be for kotlin to coarce Int and Long literals to BigInteger or BigDecimal without having to add a method call, if that’s the required type? Am I profoundly misguided for even suggesting it?
    y
    • 2
    • 4
  • z

    zokipirlo

    04/08/2021, 1:32 PM
    Hi! I shot myself again with elvis operator. Had similar bug months ago, but of course forgot it and was debugging it today again 🙃
    private fun isGroupChatInfoExpired(groupChatInfo: GroupChatInfo): Boolean {
        return Epoch.currentEpoch > (groupChatInfo.epoch ?: 0 + GROUP_CHAT_INFO_VALID_TIME) //epoch is nullable
    }
    This is always
    true
    . To fix the problem`groupChatInfo.epoch ?: 0` must be in parenthesis like:
    private fun isGroupChatInfoExpired(groupChatInfo: GroupChatInfo): Boolean {
        return Epoch.currentEpoch > ((groupChatInfo.epoch ?: 0) + GROUP_CHAT_INFO_VALID_TIME) //epoch is nullable
    }
    Is it possible to show some warning in IntelliJ (Android Studio) that this will possibly have a wrong evaluation?
    e
    d
    e
    • 4
    • 4
  • e

    edrd

    04/12/2021, 4:15 PM
    Can someone point me to links with sample use cases (i.e. real code) the Kotlin team is considering for the immutability features being discussed in the Value Classes KEEP?
    d
    e
    • 3
    • 2
  • t

    Tomasz Krakowiak

    04/22/2021, 9:03 AM
    message has been deleted
    r
    r
    • 3
    • 6
  • t

    Tomasz Krakowiak

    04/22/2021, 9:51 AM
    Anyone has idea if Kotlin crew already considered implementation of type functions?
    e
    • 2
    • 4
  • p

    Peter

    05/12/2021, 8:01 PM
    I noticed that generics types cannot have default values. Is this something that can be added in the future? Since now it seems I have to result into using the Java pattern that Kotlin was suppose to fix. Perhaps there are there some corner cases that prevent this from being supported? Just a very simple example to highlight my question (and yes, as a code snippet it doesn't make much sense ;)
    // Java approach works of course
    fun <T> test1(a: T) = a
    
    fun test1() = test1("World")
    
    
    // Not allowed, gives an error
    fun <T> test2(a: T = "World") = a
    e
    r
    • 3
    • 13
  • n

    nisrulz

    05/26/2021, 12:31 PM
    Hi 👋 I would like to suggest an enhancement to the
    @OptIn
    annotation. My usecase is that when we start using non-propagating opt-in, lets say internal to library in a multi-module library project, then there is no ability to provide reasoning for why we are
    @OptIn
    . In this particular case the reasoning would be “Internal to main library” for example. The reason can vary though. The actual annotation of say
    ShinyNewAPI
    does have the message via the
    @RequireOptIn
    annotation, like so
    @RequiresOptIn(message = "This API is experimental. It may be changed in the future without notice.")
    However this message is for clients who try to use the class marked with the annotation. When writing code for internal modules, the reason to opt in could vary. Maybe it could be like “Donot want to propagate to client code, but want to use code from another sub module”. This can be fixed by adding a code comment, but I was thinking if it could be part of the Annotation somehow, so one can wrap a new annotation with it and then use that, thus not requiring to add the message everytime.
    // Function doSomething uses API marked with ShinyNewAPI and is also
    // required to opt in. Here, we choose a non-propagating opt-in, because the
    // API is used in the function body and it should not concern our clients
    @OptIn(ShinyNewAPI::class)
    fun doSomething() {
        val foo = Foo()
        foo.bar()
    }
    Please follow more in thread.
    e
    g
    • 3
    • 12
  • y

    Youssef Shoaib [MOD]

    06/08/2021, 3:06 PM
    I'd love to get some clarification or thoughts from someone in the Kotlin team who worked on Coroutines' design about this: https://discuss.kotlinlang.org/t/coroutine-vs-job/22049/13 since tbh I'm starting to doubt everything I know about Coroutines now lol!
    g
    e
    • 3
    • 13
  • t

    Tomasz Krakowiak

    06/15/2021, 8:09 PM
    I was analysing Kotlin antlr grammar and I noticed few strange things. I wonder if anyone could explain why were they implemented this way: 1. WS is "-> channel(HIDDEN)", but NL is not. 2. Why fragment Hidden is needed? 3. Why fragment Hidden does not include NL? I found that, how "?:" and "!!" depend on this weird definition, but wouldn't it be cleaner to define them as separate tokens? (lexer grammar - https://github.com/Kotlin/kotlin-spec/blob/release/grammar/src/main/antlr/KotlinLexer.g4)
    e
    r
    • 3
    • 2
  • e

    edrd

    06/17/2021, 3:46 PM
    Published earlier today: https://github.com/Kotlin/KEEP/issues/259
    👏 3
    👏🏼 1
    🎉 6
    :kotlin-intensifies: 8
    e
    r
    +3
    • 6
    • 17
  • g

    giso

    07/01/2021, 10:10 AM
    Hi there, We have several classes in multiple Gradle modules, where we would like to make the constructor only `internal`ly visible to protect against accidental couplings. However most of our DI-wiring happens inside the main application module and therefore, so we are forced to make the visibility
    public
    . I was wondering how this use case can be fulfilled with Kotlin. Maybe with a compiler plugin, which is only applied to the main module, granting higher visibility? Or more tightly scoped with a method annotation granting only this method a higher visibility? What are you thoughts, or have I overlooked an already present solution?
    t
    w
    r
    • 4
    • 13
  • t

    Tomasz Krakowiak

    07/14/2021, 6:59 AM
    Shouldn't this be legal?
    interface A1
    interface A2 : A1
    interface B<out T>
    interface C1 : B<A1>
    interface C2 : C1, B<A2> // Type parameter T of 'B' has inconsistent values: A1, A2
    https://pl.kotl.in/xgbmimjy6
    e
    • 2
    • 1
  • n

    nwh

    07/28/2021, 12:17 AM
    What exactly is the purpose of functions like
    firstNotNullOfOrNull
    ? I have seen an increasing number of these functions appearing and they always strike me as excessive and obtuse - this one in particular still does not make sense to me, even after some soul seeking. It's a combination of
    firstOrNull
    and
    mapNotNull
    , the latter of which is itself a "convenience" for
    filterNotNull().map { ... }
    . Where does it end? Should we have
    firstNotNullOfOrNullIsInstanceOf
    ? I feel like I'm missing something here. To me, seeing this in code explains a lot more conceptually, and I don't see what's "wrong" with it:
    data.map { String.toDoubleOrNull(it) }.filterNotNull().firstOrNull()
    e
    r
    • 3
    • 9
  • o

    Oliver.O

    08/18/2021, 9:07 PM
    I have a use-case where I'd like to invoke a generic method from a generic class with and without a type like this: •
    get()
    •
    get<DateModel>()
    Currently, it requires two function definitions to achieve the goal, which might be resolved by introducing a default type for a type parameter as shown in the following example:
    package genericMethodDefaultType
    
    open class Model
    
    open class AttributeModel : Model()
    
    data class DateModel(var value: String) : AttributeModel()
    
    val modelCache = mutableMapOf<Int, Model>()
    
    @Suppress("UNCHECKED_CAST")
    class ModelReference<SpecificModel : Model>(private val modelId: Int) {
        // Variant (1) returning the default type.
        fun get() = modelCache[modelId]!! as SpecificModel
    
        // Variant (2) returning a derivative.
        @JvmName("getSpecific")  // required to disambiguate JVM signatures
        fun <MoreSpecificModel : SpecificModel> get() = modelCache[modelId]!! as MoreSpecificModel
    
        // Variant (3) replacing (1) and (2) – currently not valid Kotlin:
        //     fun <MoreSpecificModel = SpecificModel : SpecificModel> get() = modelCache[modelId]!! as MoreSpecificModel
        //
        //     Note the specification of a default type ` = SpecificModel` which shall be used if type inference cannot
        //     determine a result.
    }
    
    @Suppress("UNUSED_VARIABLE")
    fun main() {
        val modelId = 42
    
        modelCache[modelId] = DateModel("2021-08-18")
    
        val attributeModelReference = ModelReference<AttributeModel>(modelId)
    
        // Some code would access attribute models like this:
        val attributeModel1 = attributeModelReference.get()
        // Does not compile if `get()` variant (1) is not defined: Not enough information to infer type variable MoreSpecificModel
    
        // If `get()` variant (1) is not defined, we would have to specify the type redundantly like this:
        val attributeModel2 = attributeModelReference.get<AttributeModel>()
    
        // A date view might want to access its model like this:
        val dateModel = attributeModelReference.get<DateModel>()
    
        println(attributeModel1)
        println(attributeModel2)
        println(dateModel)
    }
    Is this too exotic or do there exist better solutions for the above case?
    e
    • 2
    • 4
  • y

    Youssef Shoaib [MOD]

    08/22/2021, 2:01 PM
    Here's a bit of a crazy idea: "transparent" `value class`es (I'm asking this here first to gather some feedback because currently I really don't think this is a good proposal at all lol) Simply, if there's a value class with 1 parameter, you could add a
    transparent
    modifier to it so that, whenever you have a value of that value class, it acts like if it is of the aforementioned type, but you may still access the functions that the value class itself provides. In a way, this is just a way to provide scoped extension functions, which I admit is practically solved by multiple receivers already, but there's some use-cases that don't quite fit that bill. Let me first just start with a simple example that is solved by context receivers:
    transparent value class NumericalString private constructor(val underlying: String) {
        constructor(value: Int): this(value.toString())
        ... etc for the rest of the number types
        val doubled: String get() = "${underlying.toDouble() * 2}"
    }
    
    fun main() {
        val fortyTwo = NumericalString(42)
        val four = fortyTwo.doubled.lastLetter()
        println(four + fortyTwo)
    }
    fun String.lastLetter() = last()
    Re-writing this with context receivers is messy-ish, but it's kind of doable:
    interface NumericalStringOperations {
        val String.doubled: String
        companion object Default: NumericalStringOperations {
            override val String.doubled: String get() = this.toDoubleOrNull()?.let { "${it * 2}" } ?: this
        }
    }
    
    fun main() {
        with NumbericalStringOperations:
        val fortyTwo = "42"
        val four = fortyTwo.doubled.lastLetter()
        println(four + fortyTwo)
    }
    fun String.lastLetter() = last()
    The issue is, however, that first of all this is not typesafe, since it has no idea if a String is numerical or not. The second issue is a bit niche, which is that what if you want to shadow a function that already exists:
    transparent value class NumericalString private constructor(val underlying: String) {
        constructor(value: Int): this(value.toString())
        ... etc for the rest of the number types
        val doubled: String get() = "${underlying.toDouble() * 2}"
        // Kind of assuming that no boxing will really happen and that the compiler is smart enough to not force `other` to be boxed
        // The point of this is that "42" and "42.0" should be considered equal
        override inline fun equals(other: Any?) = if(other is NumericalString) other.underlying.toDouble() == underlying.toDouble() else underlying == other.underlying
        fun last(): NumericalString = NumericalStirng(underlying.last())
    }
    
    fun main() {
        val fortyTwo = NumericalString(42)
        val four = fortyTwo.doubled.last()
        val doubleFour = NumericalString(4.0)
        println("$four == $doubleFour returned ${four == doubleFour}") // Should be true
    }
    In fact, this absolutely can't be done with context receivers (right now) because
    @HidesMembers
    is limited in its usage to a handful of functions, and even if you do hack around the compiler to allow it to work everywhere (which I did try), it still doesn't resolve the shadowing correctly because call resolution with
    @HidesMembers
    only takes into account normal static extensions and not member extensions. Even if
    @HidesMembers
    was extended properly to handle this, I still believe that making it a first-class citizen in Kotlin gives it more validity, if you will. So far, the case I've mentioned is basically just a refined type, but this feature can extend beyond that. For example, let's take a detour into functional programming with a simple
    Either<A,B>
    perhaps like this:
    f
    • 2
    • 2
  • e

    elect

    09/22/2021, 5:23 AM
    There is a very nice article about returning multiple values in kotlin without any allocation whatsoever by Louis. Beyond Android, in real time 3d graphics this is also quite an important concern. So since there are several fields where this would be happily welcomed, I think the best would be to have kotlin support built-in in the language itself. Is there any KEEP in this regards? Would also other people find this useful?
    e
    l
    +3
    • 6
    • 37
  • e

    elect

    10/04/2021, 7:56 AM
    what about escaping in triple quotes/multiline strings?
    e
    • 2
    • 4
Powered by Linen
Title
e

elect

10/04/2021, 7:56 AM
what about escaping in triple quotes/multiline strings?
e

ephemient

10/04/2021, 8:28 AM
https://youtrack.jetbrains.com/issue/KT-2425
e

elect

10/04/2021, 8:29 AM
99 votes, almost 100
nice
thanks though for the link
View count: 1