# Two dimensional arrays with nulls [closed]

I'm new with Kotlin, and this is my first attempt of a two dimensional array.

 // private var roomGrid = arrayOfNulls<arrayOfNulls<Room>>(4)
private var roomGrid = Array(roomCountX) {arrayOfNulls<Room>(roomCountY)}

init {
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val pixelX = gridX * roomWidth
val pixelY = gridY * roomHeight
val room = Room(pixelX.toFloat(), pixelY.toFloat(), s)
roomGrid[gridX][gridY] = room
}
}

// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY]
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.let { room?.setNeighbor(Room.SOUTH, it) }
if (gridY < roomCountY - 1)
roomGrid[gridX][gridY + 1]?.let { room?.setNeighbor(Room.NORTH, it) }
if (gridX > 0)
roomGrid[gridX - 1][gridY]?.let { room?.setNeighbor(Room.WEST, it) }
if (gridX < roomCountX - 1)
roomGrid[gridX + 1][gridY]?.let { room?.setNeighbor(Room.EAST, it) }
}
}
}


Even though it works I don't like the look of these:

roomGrid[gridX][gridY + 1]?.let { room?.setNeighbor(Room.NORTH, it) }


They are harder to read, and I'm not really sure what .let and it are. I would like some simpler syntax/solution to a two dimensional array.

How might I improve this?

• can't you get rid of the nulls? Sep 4, 2019 at 12:42
• What are these arrays for? What is the actual problem you are working on? Sep 7, 2019 at 7:57

# let

If you use let, you ask Kotlin to create an invisible function with a parameter.

1.let { println(5) }
//changes to:
fun func(it : Int) {
println(5)
}
func(1)


Do you see the it? That's the name of the parameter. Therefor, you can use it inside let.

1.let { println(it) }
//changes to
fun func(it : Int) {
println(it)
}
func(1)


Now, the function returns something too, namely the result of the last statement. In this case, it's just Unit, or void in Java (emptyNess):

fun func(it : Int) : Unit {
return println(it)
}
func(1)


If we take another example, it will be clearer:

val a = 5.let { 3 + it }
//changes to
fun func(it: Int) : Int {
return 3 + it
}
val a = func(5)


# ?.let

?. is very simple:

val b = a?.foo()
//changes to:
val b = if (a == null) a else a.foo()


?.let is exactly the same:

val b = a?.let { it+3 }
//changes to
fun func(it: Int){
it + 3
}
val b = if (a == null) null else func(a)


# inline

Kotlin is smart. it actually uses an inline function for let.
An inline function is a function that actually doesn't exist.
Instead, the code is copy pasted into the real code.
The parameters are just variables with random names.

so

val b = a?.let { it + 3 }
//is actually changed to
val b = if (a == null) null else {
val ac432cd = a
ac432cd + 3
}


# simplyfication

roomGrid[gridX][gridY - 1]?.let { room?.setNeighbor(Room.SOUTH, it) }


## step 1

// I would check room first:
if (room != null) {
roomGrid[gridX][gridY - 1]?.let { room.setNeighbor(room.SOUTH, it) }
}


## step 2

// flip the rooms (and directions)
if (room != null) {
roomGrid[gridX][gridY - 1]?.let{ it.setNeighbor(room.SOUTH, room) }
}


## step 3

//remove let
if (room != null) {
roomGrid[gridX][gridY - 1]?.setNeighbor(room.SOUTH, room)
}


full code until now

 // neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY]
if (room != null) {
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
if (gridY < roomCountY - 1)
roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
if (gridX > 0)
roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
if (gridX < roomCountX - 1)
roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
}
}
}


## step 4

At the moment, we test in the beginning if room isn't null.
If it is, it skips the if-statement and continues with the next iteration.
We can tell to go to the next iteration immediately using the keyword continue.

// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY]
if (room == null) continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
...
}
}


## step 5

last, kotlin has another language feature: ?:

val a = foo() ?: bar()
//will be rewritten to
val tmp = foo()
val a = if (tmp != null) tmp else bar()


Just as return continue skips immediately to the next variable. This means that we can rewrite the code we wrote in step 4.

// neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY] ?: continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
...
}
}


## full code

 // neighbor relations
for (gridY in 0 until roomCountY) {
for (gridX in 0 until roomCountX) {
val room = roomGrid[gridX][gridY] ?: continue
if (gridY > 0)
roomGrid[gridX][gridY - 1]?.setNeighbor(Room.NORTH, room)
if (gridY < roomCountY - 1)
roomGrid[gridX][gridY + 1]?.setNeighbor(Room.SOUTH, room)
if (gridX > 0)
roomGrid[gridX - 1][gridY]?.setNeighbor(Room.EAST, room)
if (gridX < roomCountX - 1)
roomGrid[gridX + 1][gridY]?.setNeighbor(Room.WEST, room)
}
}

• Your right. val room = expr ?: continue. I update tomorrow, as I don't have access to a computer at the moment... Thx! Sep 8, 2019 at 9:24
• @RolandIllig fixed. Hopefully, it can helpsome people understand Kotlin better. Sep 10, 2019 at 8:04