Yes. The callback is not a natural construct (i.e. it does not map well to our intuitive understanding of X is doing something while Y is doing something else). I'm annoyed when coroutines are reserved for use only in high performance, c10k-type of situations. For example, the KJ library's doc says: "Because of this, fibers should not be used just to make code look nice (C++20's co_await, described below, is a better…
I want to add to the callback vs coroutines and async/serial discussion that it all depends on how you treat errors. Are errors mere exceptions or do you want to handle errors in the control flow ? For example turndeg(90), Move(10), PickupItem(), turndeg(180), Move(10) you treat errors as exceptions, if the robot fail to pickup the item, or if it ends up at the wrong place it's an exception. Now if you put all these…
-- -------------------
-- Load in some modules.
-- The first makes a gopher menu item of type link
-- The second allows us to do a TCP connection
-- --------------------------
local mklink = require "port70.mklink"
local tcp = require "org.conman.nfl.tcp"
-- ------------------------------
-- tcp.connect() connects to the given address and port and timeout
-- (in seconds). This function will create a socket, set it
-- to non-blocking, call connect, then yield. When the socket has
-- connected, the coroutine is then resumed with the connection; if
-- 1 second has passed before the connection is done, then nil is
-- returned when resumed. This just calls a local QOTD service.
-- ---------------------
local ios = tcp.connect("127.0.0.1",'qotd',1)
if ios then
local res = ""
-- --------------------------------
-- The following loop will yield the coroutine until a line
-- of data has been accumulated from the network. The coroutine
-- is then resumed with the line of text.
-- ---------------------------------------
for line in ios:lines() do
-- -----------
-- We're just accumulating the text into one long blob of
-- text that we'll return
-- -----------------
res = res .. mklink { type = 'info' , display = line }
end
ios:close() -- another yield point, when closed, resume
return res
else
return mklink { type = 'info' , display = "Not Available" }
end
No exceptions here. If we can't connect, it's a simple 'if' test and do something else. The functions `tcp.connect()`, `ios:lines()` and `ios:close()` are all blocking points that cause the coroutine to yield. Yes, if I put something like `while true do end` that will block the entire process as there is no preemption, but aside from that detail, I find this code easy to read.[1] https://github.com/spc476/port70/blob/master/share/index.por...
[2] gopher://gopher.conman.org/