2

I'm new to this platform and I'm still learning to program in Lua, so, if any newbie errors appear, forgive me.

The following code is from one of the functions in my project that reads the insert of the user and validates whether or not it is a data of type "Number". If, the loop will be broken and the function will return the user input, otherwise, the program will ask the user to enter the data again:

function bin.readnum(text)
    local insertion
    if text == nil then text = "Text: " end
    while (insertion == nil) do
        insertion = nil
        print(text)
        insertion = io.read("number")
        if insertion ~= nil then break end
    end
    return insertion
end

But, if the user enters a wrong data (string) the function prints the text madly instead of asking the user to re-enter the data.

2 Answers 2

2

When io.read fails to parse the data it got into a number, it doesn't discard it, but instead leaves it in the buffer for the next call to it. That means that in your code, instead of letting the user enter something else, it'll just keep trying to parse the same non-number forever. To fix it, in your if insertion ~= nil then block, do io.read() right before break, to read and discard the whole invalid line.

Sign up to request clarification or add additional context in comments.

Comments

2

In addition to what Joseph Sible said:

  • io.read("number") is wrong: 5.1 docs demand "*n" and 5.4 docs demand just "n" for reading numbers. It probably works nevertheless due to Lua just searching for the chars in the string.
  • I recommend just replacing insertion = io.read("number") withinsertion = tonumber(assert(io.read(), "EOF")) - this will read a line and try to parse it as a number; the assert gracefully deals with nil being returned by io.read for EOF.
  • You don't need to set insertion to nil, the later assignment will do that already if what was read is not a valid number.
  • Style: Consider replacing your explicit nil checks with truthiness checks and removing the parentheses around the while-condition. You don't need a break, you can immediately return the read number; finally, you can even replace the entire loop with tail recursion.

All in all I'd rewrite it as follows:

function bin.readnum(text)
    print(text or "Text: ")
    local num = tonumber(assert(io.read(), "EOF"))
    if num then return num end
    return bin.readnum(text)
end

or alternatively using a repeat-until loop:

function bin.readnum(text)
    local num
    repeat
        print(text or "Text: ")
        num = tonumber(assert(io.read(), "EOF"))
    until num
    return num
end

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.