Hi wonderful people, I have been wondering whether...
# announcements
w
Hi wonderful people, I have been wondering whether there is a difference between using
as
and setting the type of a variable, for instance:
val ids: List<Int> = environment.getArgument('ids')
VS
val ids = environment.getArgument('ids') as List<Int>
j
Yes, there’s a difference. Giving the variable a type will result in a compile time error if the original type is not assignable to the variable type. Using
as
will let this happen (although your IDE may warn you) and then fail at runtime.
s
You’d have to do the 2nd one if the
getArgument
function does not accept generic type-parameters. But if it does, and both of your statements compile, i think the 2nd one may not be optimized away by the compiler and would incur a slight performance hit due to the explicit cast.
w
interesting, since I can use the 1st one and it compiles with no errors I can keep it, I guess.
j
That sounds like a good idea 🙂
w
Thank you so much for your answers 😉
p
If
getArgument
function has only one generic type parameter, then I would prefer to write:
val ids = environment.getArgument<List<Int>>('ids')
But of course I am just guessing function signature.
s
I’d prefer to use the 1st line that @wathek showed
val ids: List<Int> =  ...
, if I wanted to write out the type of
ids
as well. This would keep the variable name
ids
as close as possible to the variable type
List<Int>
j
@Pavlo Liapota I have in the past generally preferred that as well, but I’m rethinking — if the signature changes to have no type parameters or more than one type parameter then you’d need to change this code whereas when declaring the variable’s type directly on the variable then you wouldn’t. A minor thing really but it does seem preferable to use the version that minimizes future reasons for change
p
I see your point 👍 On the other hand, if you would need to rewrite your code and eliminate
ids
variable declaration for some reason, then you would need to change how you call the function.
s
True. However, in this case, with the
getArgument
function, that situation would rarely occur. You usually would wind up assigning the return value of the
getArgument
function call to either a local variable (e.g.
val ids
) or to a parameter of another function or a property, and parameters and properties have a type-definition,
w
actually
getArgument
signature is as following
<T> T getArgument(String name);
p
Imagine this example:
Copy code
val list = listOf(1, "one", 3.14)
val ints = list.filterIsInstance<Int>()
I know the following code wouldn’t compile (maybe with new type inference it will 🙂 ), but would you write it like this?
Copy code
val list = listOf(1, "one", 3.14)
val ints: List<Int> = list.filterIsInstance()
My point is that I like to treat this kind of generics as basically arguments to a function call.
j
Yeah, I think both ways have their advantages 🙂 Depends what’s most likely to change I guess!
s
@Pavlo Liapota I see. In this case, I agree with you. I also would call these types of functions (i.e (inline) functions that have a reified type parameter) like you prefer to call them:
filterIsInstance<Int>()
. However, I tend to write functions with a regular (non-reified) type parameter using your
val ints: List<Int>
example instead. (I must admit, this is probably because
val ints: List<Int> = list.filterIsInstance()
does not compile because this function is defined as
inline fun <reified R> Iterable<*>.filterIsInstance(): List<@kotlin.internal.NoInfer R>
). The
NoInfer
kinda forces your hand 🙂 The new type inference is not needed; the NoInfo annotation prevents type-inference.
p
Ah, thanks! Good to know.