```fun <T> identity(t: T): T = t fun <T,...
# getting-started
y
Copy code
fun <T> identity(t: T): T = t

fun <T, E> Iterable<T>.allSameValue(f : (T) -> E = ::identity) : E? { /* ... */ }
I'm getting
Required: T, Found E
for the default value on the parameter. why? what's wrong with
E = T
?
g
When
T = E
, everything is OK. But compiler says, "What if
E != T
? Then
::identity
function does not fit the type
(T) -> E
."
plus1 2
thank you color 1
And the code that breaks your concept may look like this:
Copy code
fun main() {
    listOf(1, 2, 3).allSameValue<Int, String>()
}
y
oh... yeah.
p
e.g. if you don’t use a callable reference but instead a lambda to call
identity
you have to make an explicit unsafe cast
thank you color 1
y
the caller can instantiate this with any
E
and then
::identity
doesn't agree with the requirement of returning
E
1
s
You could bound generics so that
T
must be a subtype of
E
:
fun <T : E, E> Iterable<T>.allSameValue(f: (T) -> E = ::identity): E?
With such signature
identity
function would always fit into generics bound, and mapping function could be used with its result matching supertypes of T. Example:
Copy code
val l = listOf(123)
val x: Number? = l.allSameValue { it.toDouble() }
y
@SJ yep but that makes the function less general. I figured out I can just add another overload of `allSameValue`:
fun <T> Iterable<T>.allSameValue(): T? = allSameValue { it }
s
Sure, but using signature with
T : E
and not not passing any arguments would achieve basically the same, since from the default value of of
f
being
identity
function,
E
would just be inferred as
T
, since
indentity
takes and returns same generic type:
Copy code
val l = listOf(1, 2, 3)
val x = l.allSameValue() // inferred as Int?
val z = l.allSameValue<_, Number>() // inferred as Number? because of explicit generics type declaration