3 ms·
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 t
by z3t4 3y ago
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 in try/catch, have the functions return error code (or 0 for success), or use callbacks, the code will be more "ugly" yes, but you then treat errors as "first class citizens", if the robot for example fail to pickup the item you want to try something else, maybe apply more vacum to the suction arm, or switch to a grip arm. And if the robot goes off course you want to make a course direction.
async/await, coroutines, futures, promises, do make the code "look nice", but that nice look comes from treating errors as exceptions.
- spc476 3y agoI have a gopher server written in Lua [1] that uses coroutines to handle each connection. This bit of code is executed as the main menu page [2] is being displayed (with comments) -- ------------------- -- 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.port70 https://github.com/spc476/port70/blob/master/share/index.por... [2] gopher://gopher.conman.org/
- z3t4 3y agotip: In order to flatten those if-statements you can return early, so if you start with if not ios then return - you get rid of one if..else.
- jcarrano 3y agoI don't agree. You can handle errors how you like on both approaches. The callback code, however, will get pretty messy once you have a branched control flow. With coroutines you are using the language's control structures directly. The program counter is your state and a branch is an `if`. With minimal debugger support you will be able to see at which line is the execution on each coro. With callbacks you would have to inspect which ones are pending, unless you have made the state explicit in a variable. These is not a huge deal for those who have been programming for a while but for beginners coros will feel more like an extension of the language than something built on top.
- taeric 3y agoIsh. You can also have error recovery in the form of the "conditions/restarts" system of common lisp. Such that you can have "look nice" things if you want with many different setups.