fun mergeTwoLists(l1: ListNode?, l2: ListNode?): L...
# announcements
w
fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? { var k1: ListNode? = l1; var k2: ListNode? = l2; var head: ListNode? // interleave head = k1; k1 = k1?.next while (k1?.next != null && k2?.next != null) { head?.next = k2; head = head?.next head?.next = k1; head = head?.next k1 = k1.next; k2 = k2.next // why no '?' necessary? because checkced above already? } // rest of elems from longer one var rest: ListNode? = if (k1?.next == null) k2 else k1 while (rest?.next != null) { head?.next = rest; head = head?.next rest = rest.next } return head } }
g
why no ‘?’ necessary? because checkced above already
Yes, this is smartcast https://kotlinlang.org/docs/reference/typecasts.html
Did you try to debug your code? Maybe you just do not handle some case
w
@gildor That was my question in this particular case but thanks for answering the comment anyways!
I was wondering why no ? was needed
il take another look at the infinite loop and try to figure out why its happening
fun mergeTwoLists(l1: ListNode?, l2: ListNode?): ListNode? { var k1: ListNode? = l1; var k2: ListNode? = l2; var head: ListNode?; val bed: ListNode? head = k1; k1 = k1?.next; bed = head while (!(k1 == null && k2 == null)) { if (k2 != null) { head?.next = k2; head = head?.next; } if (k1 != null) { head?.next = k1; head = head?.next; } k1 = k1?.next; k2 = k2?.next; // only works because of Kotlin null check } return bed }
@gildor so this works...but I was initially surprised that it does
it does so because of the null safety of '?.' right?
i.e.
k1 = k1?.next; k2 = k2?.next;
will keep setting itself to`null` if end of list
g
it does so because of the null safety of ‘?.’ right?
What do you mean?
w
while (!(k1 == null && k2 == null)) {
the loop will run till head of both lists is null
k1 = k1?.next; k2 = k2?.next;
will keep advancing the head of each list
however, lists are different length
hence you would expect exception:
next
does not exist for
null: class
but it works alright...is it because:
k1 = k1?.next
will set
k1
to
null
if
k1.next
is null?
g
correct,
k1
will be set to null if
k1
is null or if
k1.next
is null
You can avoid assignment only if you wrap it to condition
w
@gildor right so when k1 is next and the loop's next iteration comes and it goes:
k1?.next
BUT k1 is already
null
, what happens then?
when k1 is null*
g
if k1 is already null you will assign null to this variable, so nothing changed
w
@gildor makes sense. but 'next' does't exist for
null
, so why no error?
is it how the
?.
operator works?
g
because of
?
this operated name is “safe call operator” https://kotlinlang.org/docs/reference/null-safety.html#safe-calls
w
@gildor so I can do
"gtgt"?.onfrionfreinfroinf
and it will just give null but no error?
g
yes
w
@gildor gotcha. doesnt this reduce code safety and allow inadvertent errors?
seems like what happens in dynamic typing
g
check docs from my previous comment. You have a few options how to handle nullability: smart cast (when you checked explicitly for null once, no need to do that again, but depends on case), null safe operator or double bang (
!!
) operator, which is unsafe one and throws execption if expression returns null
seems like what happens in dynamic typing
no, why? it’s not a dynamic typing, it’s actually more strict static typed than in languages without native support of nullable types
because for example even in dynamic language like JS, you cannot just call null:
Copy code
var foo = null
foo.bar // Crash on runtime
same in Java:
Copy code
String foo = null
foo.length // Crash on runtime
but in Kotlin you will get compile time error:
Copy code
val foo: String = null // Compile time error
Copy code
val foo: String? = null // this is fine
foo.length // this is restricted, compile time error
foo?.length // this is fine
foo!!.length // this is also fine, but will crash on runtime, it's unsafe operator
So it’s more safe approach.
?.
is just shorter version of if condition for null or ternary operator:
Copy code
foo = foo?.bar
//same as ternary operator for null check:
foo = foo == null ? null : foo.bar
also it’s just shorter version of this code:
Copy code
if (foo != null) {
   foo.bar()
}
the same with safe call operator:
Copy code
foo?.bar()
or even worse case:
Copy code
foo?.bar?.baz?.doSomething()
Now try to rewrite this with if condtion
w
@gildor Awesome explanation!
The last example really drives home the conciseness of this approach
I get it perfectly now
thanks a lot!
g
glad to hear that 👍
👍🏼 1