Define Reusable Code in Functions

There are several ways to create reusable code in Kotlin. In Java, we would create code that can be called from elsewhere in the application in a method and in Kotlin, we put this code inside a function. This is similar to Java methods but there are some important differences.

The biggest difference is probably the fact that unlike a Java method, functions in Kotlin do not have to be created inside a class. We could, for example, create functions in our top level file.

			fun main(args: Array<String>) {
			val num1 = 4.0
			val num2 = 3.5
		}
Figure 27 - an example of a function called main in Kotlin

Like Java, every application must have a main() function (or method) that acts as the starting point for execution of the code.

Note that functions in Kotlin start with the keyword fun. For the time being, I will ignore the arguments other than to point out that our Kotlin functions can take a variable number of arguments and like a typical Java main() method, in this case the main() function can accept an arbitrary number of string parameters.

			fun addValues(param1: Double, param2: Double): Double {
				return param1 + param2
			}
Figure 28 - another example function, in this case called addValues()

Figure 28 shows a second function called addValues(). Note:

	•	After the dun keyword, we have the name of the function.
	•	We have two parameters called param1 and param2.
	•	We have not used either val or var for the parameters.  This is because all function parameters in Kotlin are immutable.
	•	The data type for each parameter comes after the parameter name and is separated with a colon.  These are not optional and cannot be inferred so you will get an error if a parameter type is not specified.
	•	Unlike in Java where you would use the void keyword as the return type when the function does not return anything, in Kotlin you simply omit this.  However, in this example a Double value is returned and so the return type is specified and this goes after the parameters and is again separated with a colon.

We can call the addValues() function from within the main function and print out the result with something like:

		val result = addValues(num1, num2)
		println("The result is $result")

The function call looks pretty similar to Java syntax but we can also call it by specifying the parameters by name as in:

		val result = addValues(param2 = num2, param1 = num1)
		println("The result is $result")

Note that since we have specified the parameter names, the order of the parameters is not important and to illustrate the point here, I have switched the parameters around and it still works.

Another nice feature of Kotlin is that we can create a parameter that is essentially optional by specifying a default value. Let’s say that we want to create a function called calcValues() which will either add the two parameters or subtract the second from the first. We can add a third parameter which we will call op, we will specify it as a String although I guess we might actually use a char and we will give it a default value of “+”. This method is shown in figure 29.

			fun calcValues(param1: Double, param2: Double, op: String="+"): Double {
				if (op.equals("+")) {
					return param1 + param2
				} else if (op.equals("-")) {
					return param1 - param2
				} else {
					return 0.0
				}
			}
Figure 29 - the calcValues() function

Again, we can call the function from within the main() function with:

	val result = calcValues(param2 = num2, param1 = num1)
	println("The result is $result")

In this case, we have not provided a value for op and so the default value has been used and the function returns the result of adding the two parameters together.

We can call the function with:

	val result = calcValues(param2 = num2, param1 = num1, op="-")
	println("The result is $result")

This time, the value returned is the result of subtracting param2 from param1 and of course, we can also call it with:

	val result = calcValues(param2 = num2, param1 = num1, op="+")
	println("The result is $result")

In this case, the op parameter is not required because the result is the same as we would see if it was omitted but you might want to include it in order to make it clearer that you had intended to add the two values together.

Inside the function, as can be seen in this example, we can access the parameters with the parameter names but recall that these parameters are always immutable. This means that if we want to perform some calculation(s) on the parameter inside the function, we will have to make a copy of it with a statement such as:

		var copy = param1

This allows us to manipulate the value of the parameter passed to the function by referencing copy rather than param1.

			fun addValues(vararg numbers: Int):Int {
				var result=0
				for (i in numbers) {
					result += i
				}
				return result
			}
Figure 30 - a function in Kotlin that accepts a variable number of arguments

n figure 31, we have another function called addValues() which, in this case, accepts an arbitrary number of integer values and returns the sum of these values. Note that these is a constraint here in that the function can accept an arbitrary number of arguments but they must all be of the same type.

We can call this with:

		val result = addValues(1,2,3,4,5)
		println("The result is $result")

Note that the integer values are passed as an array and the function iterates over that array in order to produce the required result.

Although, out variable list of parameters must be of the same type, we can also provide additional arguments, including another variable list although I assume that we cannot pass two variable lists of the same type.

			fun calcValues(vararg numbers: Int, op: String="+"): Int{
				var result=0

				if (op.equals("+")) {
					for (i in numbers) {
						result += i
					}
				} else if (op.equals("-")) {
						for (i in numbers) {
							result -= i
						}
				}
				return 0
			}
Figure 31 - the calcValues() function with a variable list of arguments

Figure 31 shows this where we have a variable list of integers as one parameter and a string (with a default value) as an additional parameter. Note, also, that in this case, Kotlin objected to the fact that there was no return statement not included as part of a conditional statement and this is why the final return statement is not inside an else clause.

Final note on this, Kotlin actually does not permit multiple vararg parameters so we can only have one variable list of parameters.

Evaluate Conditions With If and Else

In Kotlin, evaluation of conditions is identical to the way this works in Java so I don’t really need to cover it here. One interesting point from the video is that we can get some user input via the readLine() method which will look something like:

	println("Enter a state abbreviation: ")
	val state = readLine()

In Java, we would first create an instance of Scanner so that we could use its readLine() method but in Kotlin, this is a top level method so we can call it form anywhere and this means that we don’t need to create an instance of Scanner.

Evaluate Multiple Conditions With When

Where you would use a switch statement in Java, the Kotlin equivalent is when. As an example, let’s say we have a function that accepts a string as an argument which represents a US State abbreviation and returns the corresponding state capital.

			fun main(args: Array<String>) {
				print("Enter a state abbreviation: ")
				val state: String? = readLine()

				if (state == "CA") {
					println("The capital is Sacramento")
				}
				else if (state == "OR") {
					println("The capital is Salem")
				}
				else {
					println("I don't know that state")
				}
			}
Figure 32 - example of a function to return a state capital given a two character state abbreviation

Figure 32 shows an example of how this function might be written using a series of if/else if/else clauses. This is not too unmanageable given that only two state capitals are known to the function but would be a lot harder to read if we coded this for all 50 possible states.

Note the question mark after the type declaration for state which denotes that this variable can have a null value. Essentially, this means that it does not have to be initialized straight away.

			fun main(args: Array<String>) {
				print("Enter a state abbreviation: ")
				val state: String? = readLine()
				val capital: String?

				when (state) {
					"CA" -> capital = "Sacramento"
					"OR" -> capital = "Salem"
					else -> capital = "unknown"
				}

				println("The capital is $capital")
			}
Figure 33 - the same function as shown in figure 32 re-written to use the when statement

Figure 33 shows the same function, but this has been re-written to make use of the when statement. There are some similarities with the switch statement in. The first noticeable difference is that each possible value is followed by the Kotlin arrow operator (->) rather than a colon and there is no break statement.

In addition, rather than a default clause, we have an else clause to capture all possible values not covered by a previous clause.

Note that in this example, each possible value causes one line of code to be generated but we can, if required, but a code block after the arrow operator rather than a single statement.

We can also use a when expression to simply return a value and this is quite different from the switch expression in Java.

			fun main(args: Array<String>) {
				print("Enter a state abbreviation: ")
				val state: String? = readLine()
				val capital: String? = when (state) {
					"CA" -> "Sacramento"
					"OR" -> "Salem"
					else -> "unknown"
				}
				println("The capital is $capital")
			}
Figure 34 - the same when expression as seen in figure 32 re-written so that the when expression simply returns a value

This way using a when expression is shown in figure 33. In this case, we simply set the value of capital to the result of the when expression and you will notice that for each possible value, rather than setting the value of capital to, for instance, “Sacramento”, we simply return the string “Sacramento”.

Since in this new version of the code, we are only returning a string, this allows us to use the result in an assignment expression in this way.

A when expression can also be used to test for a variety of possible values as a group. In figure 35, we can see an example of this which adds a little bit to the previous code example by also telling us, for a given state abbreviation, which part of the US the state is found in and so we would want to group states for this.

			fun main(args: Array<String>) {
				print("Enter a state abbreviation: ")
				val state: String? = readLine()
				val capital: String? = when (state) {
					"CA" -> "Sacramento"
					"OR" -> "Salem"
					else -> "unknown"
				}
				println("The capital is $capital")

				val region: String?

				when (state) {
					"CA", "NM", "OR" -> region = "West Coast"
					"NY", "NJ", "MA" -> region = "East Coast"
					"MI", "VI", "NC" -> region = "South"
					else -> region = "unknown"
				}

				println("$state is in or on the $region")
			}
Figure 35 - an example of using a when expression where the possible values are grouped

Another way in which we can use a when expression is to use in to evaluate a value in a range and this is demonstrated in figure 36.

			fun main(args: Array<String>) {
				val theAnswer = 42
				when (theAnswer) {
					in 1..39 -> println("Not yet")
					in 40..45 -> println("Close enough")
					else -> println("Definitely not")
				}
			}
Figure 36 - using a when expression to evaluate a value in a range

In this case, because the value of the answer is in the range 40..45, we will see that “Close enough” is printed.

Manage Null Values

The handling of null values is a valuable innovation in Kotlin. As in Java, a null value indicates the absence of a value (that is, a value has not yet been set) and all variables are nullable unless explicitly declared as Not null. This means that in Java, you will see a lot of conditional expressions testing for a null value in order to avoid the seemingly ubiquitous “null pointer exception”.

Kotlin provides a number of ways of handling null values that pretty much eliminate this type of exception. Firstly, unlike Java where variables are nullable by default, Kotlin variables are not nullable unless explicitly specified as such.

			fun main(args: Array<String>) {
				var nullValue: String? = null
				println(nullValue)
			}
Figure 37 - an example of a variable declared as nullable in Kotlin

Figure 37 shows an example variable which has been declared to be of type String and there is a question mark after the keyword String which denotes that this value is nullable.

In this case, the value of the variable has been set to null and this has some implications for us. For instance, if we try to obtain the length of the variable with a statement such as:

		val l:Int = nullValue.length

we get an error and this can be seen in figure 38.

Figure 38 - trying to obtain the length of a string when the value of that string is null

From this, we can see that only a safe or a non-null asserted call is possible when a string is nullable. Note that this applies because the string is nullable, not because its value is set to null so if we provide it with some legitimate string value such as “Pip”, the error will still appear.

We can fix this by adding two question marks to the code as shown in figure 39.

			fun main(args: Array<String>) {
			fun main(args: Array<String>) {
				var nullValue: String? = null
				println(nullValue)

				val l:Int? = nullValue?.length
				println("Length is $l")
			}
Figure 39 - modification of the code shown in figure 38 so that we have a safe call

The question mark after nullValue makes this a safe call, essentially we are asking for either the length of the string or null if the string has a null value. Since this call may return a null and assign it to the variable l, the other question mark is required to denote that l may also accept a null value.

Now, if we run the code, it will print the value of the string and its length and this will work regardless of whether the string has a null value or some other value.

This method of determining whether a string is null could be considered to be the Kotlin way of doing this. In Java, we would use a conditional statement to check for a null value and, in fact, we can also use that type of syntax in Kotlin.

Figure 40 demonstrates this and if we run this code, we will see that the statement, “Length is null” is being displayed twice, once with the Kotlin style of code and once with the Java style of code.

			fun main(args: Array<String>) {
				var nullValue: String? = null
				println(nullValue)

				val l:Int? = nullValue?.length
				println("Length is $l")

				if (l == null) {
					println("Length is null")
				}
			}

We can also combine an assignment and an if statement like this:

	val message: String = if (l != null) "Length: $l" else "l is null"
	println(message)

To be more concise, we can also assign values from two options using something known as the Elvis operator which will look something like this:

		   val l2: Int = l ?: -1

This will return the value on the right hand side if the value being evaluated (in this case l) is not null. If it is null, the value on the right is returned. Note that we have not specified l2 as nullable because it will always be assigned an integer value, either the actual length of the string if it is not null or -1 if the string is null.

Now, let’s assume that we want to make absolutely certain that a variable is not null and we do want to throw an exception if it is. We can do thus using a null assertion.

			val l3: Int = l!!
			println("The value of l3 is $l3")
Figure 41 - a null assertion

In figure 41, we have created a new variable called l3 and assigned it the value of l. Note that there are two exclamation marks after the l and this is the null assertion and if we run the code when l has a null value, we will get a Kotlin null pointer exception.

In Java, we would handle this by using a try catch block and we can also do that in Kotlin.

			try {
				val l3: Int = l!!
				println("The value of l3 is $l3")
			} catch (e: KotlinNullPointerException) {
				println("l3 is null")
			}
Figure 42 - using a try catch block to handle our Kotlin null pointer exception

We can see the syntax for this in figure 43. Note that in the catch block we have created an exception variable and its type is KotlinNullPointerException and in this block we output the string “l3 is null”.

Iterate Through Collections of Data

Kotlin provides a variety of methods for iterating through a collection of data but we will start by looking at arrays.

In figure 43, we can see an example of both array creation and a loop which is probably the simplest method of iterating through an array but a couple of notes about the array first. With respect to the first array, this is an array of Strings but in this case, it has been created using the top-level function, arrayOf() and the type is simply derived from the fact that the values in brackets are strings.

We can see that the data type is shown as Array<String>. Compare this to the array of integers created with the function intArrayOf() which is an integer of arrays and the data type is IntArray.

			fun main(args: Array<String>) {
				val colours:Array<String> = arrayOf("Red", "Green", "Blue")
				val values:IntArray = intArrayOf(1, 3, 5, 7, 9)

				for (colour in colours) {
					println("The colour is $colour")
				}
			}
Figure 43 - two arrays and a simple method of iterating through the array

Note that in this case, the iteration syntax is similar to the for-each loop in Java but is slightly more intuitive. Of course, we can use this type of loop for any type of value held in an array.

The arrays also have a property called indices which is actually a range of the index values of all the elements in the array and we can use this to iterate through the loop as well.

			for (i in colours.indices) {
				println(colours[i])
			}
Figure 44 - using the indices property of an array in order to iterate through it

Figure 44 shows an example of iterating in this way.

			for (i in 1..100 step 2) {
				println(i)
			}
Figure 45 - the Kotlin equivalent of a for loop

In figure 45 , we have the Kotlin equivalent of a Java for loop. In this case, the loop will iterate 50 times because of the fact that we have specified step 2 which is the equivalent in Java of increasing the loop variable by 2 in each iteration. The result here is that we will print 1 and every 2nd number thereafter. In other words, this loop will print out all the odd numbers between 1 and 100.

I don’t know if Kotlin provides syntax for skipping the first value so that you are literally accessing the second and every second value thereafter. However, if you, for instance, want to print out all the even numbers you can simply start the loop from 2 rather than 1.

We can also use the size of the array itself in order to control the loop and we might, for instance, want to do this if the size of the array is unknown. This type of syntax is shown in figure 46.

			val l = colours.size

			for (i in 0..l){
				println(colours[i])
			}
Figure 46 - Using the size of the array to determine the correct range to iterate through

In this case, the size of colours is three since there are three elements in the array, but notice that we are counting from 0 os we are accessing elements of the array with index values, respectively of 0, 1, 2 and 3 and so we will see an ArrayIndexOutOfBoundsException.

We cannot fix this by counting from 1 because this would simply omit the first element (with index 0) and we would still see the same exception. Traditionally, in Java, the solution here is to subtext one from the size which leads to the code shown in figure 47.

			for (i in 1..l-1){
				println(colours[i])
			}
Figure 47 - the code from figure 46 corrected to avoid the ArrayIndexOutOfBoundsException

An alternative approach would be to count from 1 up to the size of the array but then subtract one from the index value in the print statement. The code for this is shown in figure 48.

			for (i in 1..l){
				println(colours[i-1])
			}
Figure 48 – an alternative method of correcting the code from figure 46 and this will also avoid the exception.

Actually, Kotlin provides a more elegant solution using the until keyword which means that we will iterate through the range until the specified value is reached and then terminate. The code for this is shown in figure 49.

			for (i in 0 until colours.size){
				println(colours[i])
			}
Figure 49 - yet another way to fix the code from figure 46, but in this case without the untidy -1.

So in this case, as with the code shown in figure 46, the loop counter runs from 0 to 3 but the loop terminates when the value 3 is reached without executing the print statement and so we don’t get the exception.

Iterate With Conditional Expressions

Kotlin allows you to iterate based on a conditional expression and as with Java, we are doing this via a while loop. The syntax of this is exactly the same as Java so it is probably not necessary to go into this further. However, as well as illustrating a while loop in Kotlin, figure 50 covers another point which probably is worth mentioning.

			fun main(args: Array<String>) {

				val colours:Array<String> = arrayOf("Red", "Green", "Blue")

				val l = colours.size
				var counter: Int = 0

				while (counter < l) {
					println("Counter is $counter")
					println("Colour is ${colours[counter]}")
					counter++
				}
			}
Figure 50 - sample Kotlin while loop

Similar to the for loops in the previous section, we can see that we are iterating over the array counter to identify each element in turn with the loop terminating, without attempting to access the array as soon as the counter equals the size of the array.

The point of interest here is actually nothing to do with a while loop, but notice that we are printing the value of the counter and the corresponding array element for each iteration. For the array element, we are specifying the name of the array as well as identifying the element and this is a little more complex than, for instance, simply specifying the value of a variable as we have with the counter variable.

For this reason, we put the variable name and the index in curly braces. Note that if we did not do this, we would see that Kotlin would interpret this as our variable name being $colours with [counter] being interpreted as additional text.

The result we therefore see when this print statement is executed is the text shown in figure 51.

			Counter is 0
			Colour is [Ljava.lang.String;@266474c2[counter]
			Counter is 1
			Colour is [Ljava.lang.String;@266474c2[counter]
			Counter is 2
			Colour is [Ljava.lang.String;@266474c2[counter]
			Process finished with exit code 0
Figure 51 - the result of executing a statement like println("Colour is $colours[counter]")

When we put this inside curly braces as we did in figure 50, the result is that the actual element is printed.

A slightly different syntax is to use the get function in place of the brackets to get the value of each individual element. This method operates on an array and takes an integer argument, returning the element corresponding to the argument.

The modified code would look like this:

		println("Colour is ${colours.get(counter)}")

and again it is worth noting that this syntax is not related to the while loop (or loops in general) with the loop simply being the mechanism by which we access each individual element.

Again, as with Java, Kotlin allows you to put the conditional statement at the end of the loop and this is also a do..while loop with syntax that is exactly the same as Java. For illustration purposes, I have re-written the code from figure 50 as a do..while loop which is shown in figure e52.

			counter = 0

			do {
				println("Counter is $counter")
				println("Colour is ${colours.get(counter)}")
				counter++
			} while (counter < l)

Note that the code inside the do while block is identical to the code inside the while loop.

Handle Exceptions With Try and Catch

As with loops, try catch blocks are essentially the same in Kotlin as they are in Java. In figure 53 we have some sample code that asks the user to input two values which are then converted to type Double and then simply displayed in a print message.

The code has two catch blocks so it can catch exceptions of types

	•	KotlinNullPointerException
	•	NumberformatException
	•	import java.lang.NumberFormatException
			fun main(args: Array<String>) {
				try {
					print("Value 1: ")
					val value1 : String? = readLine()
					val d1: Double = value1!!.toDouble()

					print("Value 2: ")
					val value2 : String? = readLine()
					val d2: Double = value2!!.toDouble()

				} catch (e: KotlinNullPointerException) {
					println("Value was null")
				} catch (e: NumberFormatException) {
					println("Unknown")
				}
			}
Figure 53 - sample code demonstrating the use of a try catch block.

It is worth noting that the second of these exceptions, the NumberFormatException, is actually a type alias and this is in fact using the Java exception. In fact, when typing the code, you may notice a list popping up that indicates the source of the exception. In this case, the source is java.lang.

It is worth noting that if you use readLine() in this way, it won’t ever return null although it can also be used to read data from files and in certain circumstances, it can return a null value when reading a file. This means that in order to see a null pointer exception here, the only way seems to be to explicitly set the value of either value1 or value2 to null.

The second exception will be triggered if a value is provided that cannot be converted to a Double value.

			import java.lang.NumberFormatException

			fun main(args: Array<String>) {
				try {
					print("Value 1: ")
					val value1 : String? = readLine()
					val d1: Int = value1!!.toInt()

					print("Value 2: ")
					var value2 : String? = readLine()
					val d2: Int = value2!!.toInt()

					println("Value 1 + Value 2 = ${d1+d2}")

				} catch (e: KotlinNullPointerException) {
					println("Value was null")
				} catch (e: NumberFormatException) {
					println("The number provided is not an integer")
				}
			}
Figure 54 - the code from figure 53 re-written to work with integer values only

This is actually a little bit clearer if we amend the code to work with integer values only as we have in figure 54. When this code is run, the user inputs a number (again, as a string) that is converted to an integer. So this assumes that the user has actually typed in an integer value so if a floating point number is entered or the user types non-numeric characters (such as “two” rather than 2) we will see the error message “The number provided is not an integer” displayed.

In these examples, we have simply printed an error message when an exception is caught. However, exceptions have a message property which we can display either instead of our own message or to add additional information to it. The syntax for this is simply:

		println("${(e.message)} is not an integer")

If we type a non-integer value into our program, an exception is thrown and as it happens, all exception classes in Kotlin have a common superclass called throwable (Kotlin.org, n.d.). This class has two properties, message and cause. It is not as complex as the Java Exception class but is sufficient for simple exception handling.

Note that unlike Java, Kotlin does not have the concept of checked exceptions which means you will never see a throws clause in a function signature. Java sometimes insists that when working with certain exceptions, you must either wrap the code in a try catch block or put a throws clause in the method signature and failing to do this would give you a compiler error. You don’t need to do this in Kotlin and this simplifies the error handling code since you only need to check for an exception in one place and that is by wrapping the code that might cause the exception in a try catch block.

Challenge: Create a Simple Calculator

The challenge here is to write a Kotlin program that allows a user to type in two numeric values followed by an arithmetic operator (+, -, * or /). The program will then perform the arithmetic operation selected on the two numbers.

For example, if the user types in 5 and 2 followed by a minus sign, the output will be the result of calculating 5 minus 2.

The program should catch two types of exception:

	•	A NumberFormatException if an invalid value is entered for one of the numbers.  The values are of type float so the numbers do not have to be integers.
	•	An Exception (that is, a generic exception) if an invalid entry is made for the arithmetic operator (that is, if anything is typed for the operator other than one of the four operators displayed in the prompt.

The code for this is shown in figure 55.

			import java.lang.Exception
			import java.lang.NumberFormatException

			fun main(args: Array<String>) {
				try {
					print("Number 1: ")
					val value1: String? = readLine()
					val num1: Double = value1!!.toDouble()

					print("Number 2: ")
					val value2: String? = readLine()
					val num2: Double = value2!!.toDouble()

					print("Select an operation (+ - / *): ")
					val op: String? = readLine()

					if (!validOp(op)) {
						throw Exception(op)
					}

					var answer: Double = 0.0
					when (op) {
						"+" -> answer = num1 + num2
						"-" -> answer = num1 - num2
						"*" -> answer = num1 * num2
						"/" -> answer = num1/num2
					}

					println("The answer is $answer")
				} catch (e: NumberFormatException) {
					println("{($e.message)} is not a number")
				} catch (e: Exception) {
					println("Unknown arithmetic operator")
				}
			}

			fun validOp(op: String?): Boolean {
				val setOfOps:Array<String> = arrayOf("+", "-", "*", "/")
				for(i in setOfOps) {
					if (i==op) {
						return true
					}
				}

				return false
			}
Figure 55 - the code for the simple calculator challenge

This solution differs in a couple of ways from the provided solution. A difference that I think is relatively minor is that the provided solution creates separate functions for each of the possible arithmetic operations and calls these from the when block depending on which operation has been selected.

Given that the operation in this case is a simple arithmetical expression, I don’t think this is a significant difference and possibly my solution may be slightly better. However, in more general terms, given that a real-life example will inevitably be much more complex, the provided solution is a more sensible approach since it works in this case but would work equally well regardless of the complexity of the called functions.

The other difference is that my solution has a routine which exists simply to check the operator selected is valid and if this returns a false value, the exception is thrown before the when block is executed. For this reason, I didn’t need an else block within the when block to catch any non-specified circumstances since the when block is only executed if a valid operator has been selected.

I think that the weakness in my approach is that this means that the operators are listed three times:

	•	In the print statement prompting the user to select an operation
	•	In the validOp function as part of an array called setOfOps which represents the set of all valid operators
	•	In the when block where each operator is one of the cases.

In the provided solution, the fact that an exception is thrown if none of the previous cases match (that is, if the string entered by the user is not one of the permitted operators) means that there was no need to create a function to check if the operator was valid. Essentially, this catch all means that anything else that the user might enter is treated will throw the exception but more importantly in this context, that the permitted operators are only being listed twice.

The difference here doesn’t seem too great but it means that if another operator is added, for instance a factorial, the provided solution would be modified simply by adding another call in the when block and ensuring that the prompt for an operator is updated to include the new operator. So this is two modifications.

In my solution, I need to make both these modifications and also update the function that checks for a valid operator so I need to change code in three places so my solution is more prone to errors if the application has to be updated.