Kotlin Flow Control - readln()!!.toInt() - kotlin

I started learning Kotlin a few days ago and I don't really understand why in this case you should use readln()!!.toInt(), from where the number is taken and to which "line" it refers.
fun main(args: Array) {
var number: Int
var sum = 0
for (i in 1..6) {
print("Enter an integer: ")
number = readln()!!.toInt()
It would be extremely helpful if someone could explain that.
Thank you!

readline() (not readln()) returns a line from the standard input stream, or null if the input stream has been redirected to a file and EOF (end of file) is reached. Its return type is String? meaning it could either be a String, or it could be null.
!! is "We are sure this will never be null; force this into a non-nullable type." It means you don't have to deal with the condition where the object you're working with is null.
In this case, the !! is saying "We're sure that system input hasn't been redirected to a file (or if it has, that EOF hasn't been reached); wait for the user to input something."
It looks like someone has mixed up readline() and readln() (which I did when I first answered this question) - #Tenfour04 is right; there's no need to use !! with readln. It does the same thing, except it throws an exception if EOF is encountered.

Related

Error in inputting array and outputting it | Kotlin

I am new at Kotlin (and my English is terrible :).
I want to define the size of the array and elements in it by inputting it from the keyboard.
fun main() {
val array_size = readLine()!!.toInt()
val arr = IntArray(array_size)
for (i in 0..array_size){
arr[i] = readLine()!!.toInt()
}
for(i in 0..array_size){
println(arr[i])
}
}
[I got this message][1]
[1]: https://i.stack.imgur.com/DRk9F.png
This is my first question in StackOverFlow tho, hope it is understandable for those who want to help.
The NullPointerException is probably because the call to readLine() is returning null and then you're forcing that to non-null using readLine()!! which gives you the NPE.
In recent versions of Kotlin a new method was introduced: readln(). It is recommended to use that instead of the old readLine. If and END OF FILE is found, the new readln method will throw a more descriptive exception, whereas readLine will return null which makes it more difficult to see where you went wrong.
You might get an end-of-file condition if the input is redirected from a file or other source. This often happens if you run your program in an IDE or an online compiler service. If you run your program from the command line, it will work, until you get to enter the last line. This is because for(i in 0..array_size) includes the value array_size which is 1 more than the last index, so you get an out-of-bounds exception.
Instead of using 0..(array_size - 1), it is recommended to use arr.indices which gives you the range of valid indices for the array.
readLine() is returning null, and so when you do readLine!!... you're getting a NullPointerException. Perhaps you want to use readln instead.

I'm trying to take names and the amount of groups from a user. Then separate them into groups. Kotlin

fun main(args: Array<String>) {
//receive names from user
print("Enter the names: ")
val names = readLine()?.split("/n")
//receive number of groups from the user
print("Enter number of groups: ")
val group = readLine()
print(names.chunked(group))
}
I was trying to print the users into evenly separated groups. I found that I could use chunked to accomplish this. But when I try to input the amount of groups to the chunked function nothing happens. it outputs "kotlin.Unit" I'm guessing this is an error code. But I don't know how I messed up my code.
As mentioned in the comments, this code does not compile. It still has the following problems:
names can be null, so you'll either have to ensure that it isn't, which you could do using the Elvis operator:
val names = readLine()?.split("\n") ?: return
Or you can use a safe call on names wherever you use it:
names?.chunked(group)
If you look at the documentation for chunked, you'll see that it has one parameter, size of type Int. However, you are passing a String to it, which you've read from the user. You'll have to try to convert this string to an int before passing it into chunked:
val group = readLine()?.trim()?.split(" ")?.first()?.toInt() ?: return
Note that I'm trimming and splitting the user input to increase chances of retrieving a valid int.
Fixing these problems makes your code compile. However, there's one more thing to fix. Assuming you meant the newline character with /n, you are now using the newline character as a separator for the names as well as to indicate that the user is done entering names. I suggest you use something different, like a comma. In total, this could give something like the following.
fun main() {
//receive names from user
print("Enter the names (separated by a comma): ")
val names = readLine()?.split(",")?.map { it.trim() }
//receive number of groups from the user
print("Enter number of groups: ")
val group = readLine()?.trim()?.split(" ")?.firstOrNull()?.toInt() ?: return
print(names?.chunked(group))
}

How to register the enter key using readline() in Kotlin

I am currently using readline() function in Kotlin. However, I want it to continue after registering the enter key ten times. I don't know how to do this.
using the function readline() on a console application that is reading from the keyboard, you dont need to register the enter-key because ENTER represents a valid end of the line. So a simple loop which is executed 10 times will fully work out here. for(i in 0..9) { <READ INPUT> }
Using it on files works the same. Normal editors will show a text in X lines if the border window is reached even without ENTER. readline() will not do that and read a single line in a file until a line-end sign is found. So here again - just loop it 10 times for 10 lines.
From your question it is not very clear, what you are trying to achieve. I assume you want to read ten lines from the console with Console.readLine().
The code
val lines = (1..10).map { readLine() }
will read ten lines from the console and store them in the variable lines as list of strings.

Kotlin input first and last name with a twist

Seems a pretty simple program, but I can't figure out what I'm doing wrong. Any help is greatly appreciated!
TASK Write a program that reads the first name and the last name of a person, each on a separate line. Then, print the first letter of the first name with a dot and then the last name (with a single space in between): for example, Arthur Dent would be A. Dent
I've tried the following code:
fun main() {
val s1 = readLine()
val s2 = readLine()
println(s1.first() +"." + " " + s2)
}
Which returns an error: Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
This is pretty straightforward in Python, but been struggling to solve it in Kotlin.
Thanks in advance!
Looking at the readLine docs it states that:
Return the line read or null if the input stream is redirected to a file and the end of file has been reached. (also if you fake an end file indication)
This means that both s1 and s2 are nullable. You would have seen this if you would have explicitly declared the type of the vals (something that beginners in kotlin should probably always do), as they would have been String?.
So, if we want to get the first letter (or do more or less anything), we need to use the ? safe call to avoid a NPE. The reason you don't get any error with s2 is because the default invocation of .toString will just return a String with the value of null.
Now even if you do add the safe call you will still get an error, that being that you can't concatenate null to a String. And you can simply solve it by using template instead of concatenation (which is actually the prefered way in kotlin). So we will have this:
println("${s1?.first()}. $s2")
Some changes due to the single input requirement. If you only have one input of type John Doe then the above code won't work, because you are reading 2 separate lines, one of which does not exist, making the lastName null. Doing is for a single input needs a bit more work:
val line = readLine()?.split(" ")
val firstNameInitial = line?.getOrNull(0)?.first()
val lastName = line?.getOrNull(1)
println("$firstNameInitial. $lastName")
This assumes that there are no people with a space in their names (not sure if true or not),that nobody will enter a middle name, and that the first and last name are separated by a " " space.
As per Joffrey's comment, we can also use the elvis operator to ensure that the readLine is not null, by throwing our own exception stating that the input is not readable.
val line = (readLine() ?: error("Unexpected end of input, expected first and last name in format \"John Doe\"")).split(" ")
val firstNameInitial = line.getOrNull(0)?.first() // in case we receive an empty string
val lastName = line.getOrNull(1) //in case we only receive one name
println("$firstNameInitial. $lastName")

Is there any good defacto standard 'everything went smoothly' message in a method that returns string errors?

So my class takes data and does it's thing, returning an error message if anything went wrong. What should I make the string if everything went fine? null? "1"? "OK!"? "success"?
Please support your answer.
Unix standard return codes use '0' as OK - by analogy, it's often recommended to use empty string (length 0), at least in languages where you can treat the "" value as "false".
E.g., in Perl: if ( $error = my_method_call() ) { print "Failed: $error\n" }
In a language where there's no such implication (use "" as false), any string can be chosen as "OK", as long as it's obvious and readable ("OK" fits the bill).
Methods should never return string errors. They are way too error prone and are more costly than the obvious alternative, returning integer codes, which you can translate to descriptive constants and have a single method which translates those codes to strings.
If you will use error codes to print them out (or log them), then it might be fine to use strings, but then again, there is nothing preventing you from printing or logging the error in the erroring method itself and returning a failing status code to the caller.
If you will use string error codes to check internally in code for different conditions, strings are a pain:
rv = some_function();
if (rv == "The file could not be read") {
take_corrective_action();
}
About including details in error code, the caller (usually) has the details and can compose the complete error message:
rv = read_data(FILE);
if (rv == READ_PERMISSION_ERROR) {
log("The file " + FILE + " could not be read. You don't have permissions");
}