Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get lua to run sequentially

Tags:

io

buffer

lua

I am learning Lua via this site. I am in the very beginning of the tutorials and am trying this program (enter a number, x, it returns x!):

-- defines a factorial function
function fact (n)
  if n == 0 then
    return 1
  else
    return n * fact(n-1)
  end
end

print("enter a number:")
a = io.read("*number")  -- read a number
print(fact(a))

However, when I run it, the io.read seems to come before the prompt. I am running it in Notepad++ console like so:

"C:\Program Files\Lua\5.1\lua.exe" "Path\To\factorial.lua"

The output is (seemingly) blank but if I enter a number, the function runs.

5
enter a number:
120

While this is not much of an issue here, I can only imagine the issues that come up from variables getting used prior to creation. So, how can I get this program to prompt for a number before reading an input?

like image 892
David Starkey Avatar asked Oct 14 '13 19:10

David Starkey


1 Answers

What's happening is not that the code is running out of order, but that the prompt isn't getting displayed to the terminal immediately.

Internally, anything you output is stored in an IO buffer by the operating system. Periodically, the buffer is emptied and its contents are displayed on the terminal (it is flushed). On most systems, the terminal is is line buffered by default, meaning that every time you write an end-of-line character - which print() does automatically - it is flushed; on some systems, however, it defaults to being fully buffered, meaning it is automatically flushed only when it fills up.

There are two ways you can address this. If you want to disable or change buffering for all IO operations on a file (and for these purposes, the terminal counts as a file), you can use the file:setvbuf() function; in particular, io.output():setvbuf("no") will disable buffering for standard output, meaning anything you write will be displayed immediately. You can also use io.output():setvbuf("line") to enable line buffering, on systems where that is supported but not the default.

The other approach is to manually flush the buffer, which is useful when you want some particular output to display immediately, but don't want to universally disable output buffering. You can do this with the file:flush() function, which immediately flushes the buffer, for example:

-- no newline, so even on line-buffered systems this may not
-- display immediately
io.write("Enter a number: ")
-- so we force it to
io.flush()

Note that io.write() and io.flush() are just convenience functions for io.output():write() and io.output():flush(), i.e. they get the current output file and then call :write() or :flush() on them.

(Why bother with buffering at all? Because it's faster - writing data to a terminal or a file is expensive, and writing one large thing is faster than writing lots of small things. In most cases, it doesn't matter if things don't get written the very instant the code runs, so the OS saves the data to be written in a buffer and then makes a single large write when the buffer fills up.)

like image 149
ToxicFrog Avatar answered Oct 20 '22 09:10

ToxicFrog