I couldn't find it, so maybe it doesn't exist, but...
# announcements
m
I couldn't find it, so maybe it doesn't exist, but can I make a generic constraint where something MAYBE extends certain interfaces?
Copy code
interface Code{
    private val code: String
}

interface Keyable{
    private val key: String
}

fun <T> getThing(obj: T) : Pair<String, String?> where T : Code, T maybe Keyable{
    return obj.code to obj.key //implied that since we're not sure that Keyable is implemented, the field becomes nullable
}
d
I don't think this exists, you would just use
(obj as? Keyable)?.key
.
m
that's what I did too, but that splits the generic constraint in both function type and function execution. I think that's ugly
d
Well, its not really a constraint if it's not a requirement, is it? 😄
☝️ 1
s
I think you have to write two
getThing
methods, once that takes a
Keyable
and one (probably slightly different named) that takes another object. As Kotlin is a statically compiled language, the interfaces of your object need to be known at compile-time not run-time.
d
I am not sure what the difference is between specifying the "maybe" constraint and not specifying it at all...
👍 2
m
@diesieben07 you're right, it's not really a constraint if we don't know. It's just that, if the interface becomes bigger it would be unfun to declare as? on the class every time you need one of it's fields haha. (imagine an interface with 10 vals) just becomes easier to type
s
good point @diesieben07 how about:
Copy code
fun <T:Code> getThing(obj: T) : Pair<String, String?> {
    if(T is Keyable) {
    return obj.code to obj.key //implied that since we're not sure that Keyable is implemented, the field becomes nullable
   }else {
     return ...whatever you do if it isn't Keyable
   }
}
There is even smartcasting.
d
Alternatively:
Copy code
val keyable = obj as? Keyable
// more logic
keyable?.thing

...
keyable?.otherThing
s
as
throws an Exception if the object isn’t of that class, use
is
!
d
Not
as
,
as?
as?
returns null if the cast is not possible
s
as?
just means the type can be nullable, it’ll still throw that exception if your object isn’t of that type or null. Use
is
😉
d
No.
"foo" as? Int
is null
"foo" as Int?
(what you mean) throws exception
m
as? is indeed a safe cast
s
no,
is
is the safe cast! but only within the true-case if-block!
d
You are wrong, Stephan 😛 Read the link
m
it as? Int ===
Copy code
return when(it){
    is Int -> it //as Int smartcast
    else -> null
}
d
s
the block slightly undernies calls
as
the “unsafe cast” https://kotlinlang.org/docs/reference/typecasts.html#unsafe-cast-operator
d
Yes. "as" and "as?" are different.
They are separate operators.
s
I understand, but
is
is the one to use here.
d
I disagree 😉
That would require you to have completely separate code-blocks for "is instance" and "is not instance". instead of falling back on
null
, which is what was originally requested.
s
ah, because you’re fine with obj.key being null, I stand corrected.
I was thinking more generally not in this special case.
d
There is nothing wrong with
as?
, and it can be very useful. For example:
val something = (obj as? Foo)?.key ?: "default value"
Writing that with
is
is much more verbose
s
well, you don’t need a default value here, that’s why
as?
works but otherwise I’d still go for
val something = if(obj is Fee) obj.key else "default value"
d
well, let's agree to disagree I guess.
m
I'd still write that as
Copy code
(obj as? Fee).key ?: "default value"
I'm not a fan of onelining an if like that. But mostly because the ternary operator got wrongfully omitted from design (personal opinion)
s
again, the return type of this function is Pair<String, String?>, so yes,
return obj.code to (obj as? Keyable)?.key
is shortest here and the way to go.