apologies in advance for the complexity here. try...
# getting-started
y
apologies in advance for the complexity here. trying to debug the following exception:
Cannot invoke "java.util.Map.get(Object)" because the return value of "A.getMethods()" is null
which we seem to get, but only sometimes. we have this: (
A
,
B
,
C
are all concrete classes, renamed to anonymize)
Copy code
abstract class A(/* ... */) : Lots, Of, Things {
    abstract override val methods: Map<B?, C>
    abstract override val someMethod: C?
    /* ... */
    override fun getMethods(): List<C> = methods.values + listOfNotNull(someMethod)
}
what could be the issue here? is it an order of initialization thing? is it related to the choice of the name
getMethods
? (since kotlin desugars getters to that name, no?)
s
> is it related to the choice of the name
getMethods
? maybe 🤷‍♂️, rename it and find out. >
the return value of "A.getMethods()" is null
this is indeed strange since looking at the implementation it can never be null (not even the return-type is nullable), but maybe the method's return-type is nullable (or null) in its supertype?
y
maybe 🤷‍♂️, rename it and find out.
sadly only happens in production and we haven't found the exact triggers yet, but I'll make that suggestion.
s
but even the methods-Map isn't nullable, so appart from "compiler bug" the only source of null I can think of is in the implemented interface, whereever
getMethods
(and potentially
methods
are defined). Maybe the interface not only has a nullable return-type but a
return null
default imlemementation?? Maybe the interface is defined in Java??
b
is
getMethods
called in the init block of the abstract class ? If so, this could be the case, because the implemented class initialization is not done when the
ìnit
block of the abstract class is called (see https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order)
h
I don't think the name of
getMethods
can be a problem. If it was, the compile would give an error. If
methods
and
getMethod
had the same return type, the compiler gives a
Platform declaration clash
-error. Based on the error message you gave, it seems that the property
methods
has a
null
value (it tries to call
Map::get
on it, and
getMethods
doesn't return a
Map
but
methods
does). This can be the result of using fields that aren't initialized yet. Here's an example where the
null
value persists even after initialization (and also demonstrates that it can happen without an
init
block). In the example I gave it may be obvious that it would either result in a null value or an error, but there are situations where you might expect it to just work.
y
follow up question while debugging this: let's say the instance of
A
that caused this is
a
. before this exception is thrown, we access a different property of
a
. the type of this property is non-null. if no exception was thrown by this access, does this actually guarantee that the actual value wasn't null?
h
If all you do is read the property and pass it around, I don't expect an error. Only when you try to access it as if it was not null would I expect an error.