https://kotlinlang.org logo
#announcements
Title
# announcements
s

Stephan Schroeder

11/25/2019, 11:10 AM
Does anybody know if Contracts (https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) are close to leaving experimental (and if/how the final form is different from the 1.3 version)? I played around with the current version and immidiately have a feature request 😆 In Example 1 of the Contracts Proposal (https://github.com/Kotlin/KEEP/blob/master/proposals/kotlin-contracts.md#examples) they show a Smart Cast use case:
Copy code
[Returns(true) -> x is String]
fun isString(x: Any?): Boolean = x is String
so I was interested in seeing if I can write a reified generic version (https://pl.kotl.in/XNSuwtkvC, which would be pretty useful for custom equals-methods):
Copy code
inline fun <reified T:Any> T.hasSameClass(other: Any?): Boolean {
    contract {
        returns(true) implies (other is T)
    }
    if (this === other) return true
    return other!=null && this.javaClass == other.javaClass
}
Unfortunately currently this fails due to “references to type parameters are forbidden in contracts”. References to reified type parameters should be doable (<- my feature request).
k

karelpeeters

11/25/2019, 11:25 AM
I hope they don't leave experimental yet, as you can see there's a lot to be done still.
Some bigger questions as well, like getting
val result: List<String> = list.filter { it is String }
to compile.
s

Stephan Schroeder

11/25/2019, 11:30 AM
k

karelpeeters

11/25/2019, 11:31 AM
Yes, but that's unfortunate. It would be better if this worked in general so there's no need for duplicate functions.
For example
takeIf
should work too, and maybe you want to filter on multiple things as well and then you need
.filterIsInstance<String>().filter { it.length == 5 }
and that's starting to get both slow and ugly.
s

Stephan Schroeder

11/25/2019, 11:38 AM
but
filter
on it’s own can be applied to all kinds of predicates, type checks is actually quite rare. But the contrats definition (for filter with smar cast) is specific to type checking predicates. Contracts are written into the executing function, but your usecase would require the lambda-parameter to be identifieable as “provides smart cast guarantees”. At the least your usecase is considerably more complicated than my usecase. So I get why the devs when with a specifc
filterIsInstance
instead.
k

karelpeeters

11/25/2019, 11:41 AM
Type checks and other predicates combined isn't that rare in my code. They went with
filterIsInstance
because contracts didn't even exist back then. And this very similar to other contracts but on a collection. The KEEP has this as something to consider as well.
s

Stephan Schroeder

11/25/2019, 12:02 PM
ok, my “is rare”-argument was garbage. So how do you even want to write this?
Copy code
fun <T,R:T> List<T>.filter( predicate: (T)->Boolean): List<R> {
  contract {
    "if predicate smart casts T to subtype X" then R = X else R = T" 
  }
  ...
}
So 1) you would need the “does parameter lambda smart casts it’s argument”-functionality which is very sideeffect driven (the type of the lambda doesn’t contain this possible smart cast). But isn’t the bigger problem that 2) the return type of
filter
(either T if the lambda doesn’t smartcasts it’s argument or R otherwise) isn’t computable from the type definitions given?!? Again, nothing in the definition of
predicate
says that it’s smartcasts, so I guess you would need “second-level contracts: contracts”!. Contracts that work on arguments that have contracts.
13 Views