Live data from Hacker News

Coroutines make robot code easy

bvisness.me

111–120 of 127 posts

Re: Coroutines make robot code easy

#111
post #28

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…

I 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.por...

[2] gopher://gopher.conman.org/

Re: Coroutines make robot code easy

#112
I had a similar revelation a few months ago when working on a little game in Lua.

Since a game runs as a loop, all synchronous code needs to be able to execute within one frame.

So you end up making overcomplicated state machines to represent processes that last for multiple frames.

Coroutines make writing this code sooooo much easier. You can actually start to see the logic again at a glance rather than having to dive into a big stateful mess.

Re: Coroutines make robot code easy

#114
post #30

I don’t understand why doing this with normal Java is difficult. Just have a list of objectives. Each objective is a class. The autonomous loop picks the next objective from the list and each tick, asks if it has finished, if so get the next objective and so on. All the details about the actual commands to complete the objective and checking the state and so on go into the classes. If no more objectives in the list,…

It's addressed in the article... you sort of end up with a meta-programming language when you do that, which ends up being less ergonomic than your initial code. Then you have questions like how do you do control flow within that list? Can you branch or loop over multiple objectives? If you add support for that you end up even closer to a meta programming language, with worse syntax than if things were directly in th…

> you sort of end up with a meta-programming language when you do that, which ends up being less ergonomic than your initial code

I would say that what you end up with is a program.

> Then you have questions like how do you do control flow within that list

You don't. Each objective has an "isDone" method. That method returns true if done, false if not. If unable to complete its objective for some reason, throw an exception. Seems like pretty canonical object orientation to me.

> Can you branch or loop over multiple objectives?

No, but you could easily have an objective that groups together multiple smaller discrete objectives.

> If you add support for that you end up even closer to a meta programming language, with worse syntax than if things were directly in the base language.

Again, I just think you end up with a program, using the syntax of the language in which you're writing.

Like if you write a story, you end up with a story, written using the language in which you wrote it.

Re: Coroutines make robot code easy

#115
post #30

I don’t understand why doing this with normal Java is difficult. Just have a list of objectives. Each objective is a class. The autonomous loop picks the next objective from the list and each tick, asks if it has finished, if so get the next objective and so on. All the details about the actual commands to complete the objective and checking the state and so on go into the classes. If no more objectives in the list,…

Having taught FRC students to use Java: when you're talking about people with very little experience programming before, the multiple class abstraction is itself an obstacle to accomplishing the goal. I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "Bu…

> the multiple class abstraction is itself an obstacle to accomplishing the goal.

Not if your goal is to learn about object orientated programming!

> I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "But we already said 'drivetrain' in the constructor, and over here in this other class. Why do we have to say m_drivetrain in the class also and do m_drivetrain = drivetrain?" And there isn't actually a better answer than "in other languages that learned from Java's mistakes, you don't. But we happen to be using a language that dates back to when Animaniacs was teaching kids the names all the countries, so some parts are just bad."

Do they also have nervous breakdowns every time the spell or read the word "knight"? The etymology of a language can be interesting, and they're welcome to look it up on their own time, but the sooner they learn that all of these decisions are arbitrary, the better.

When I was first learning how to use FreeBSD I was equally confounded by trying to apply logic and reason to how the commands looked and worked. Once I just accepted the fact that it was no different to questioning why the buttons were on the left side of the toaster rather than right side, or why sought and sort are two different words pronounced the same my life got a whole lot easier.

When I'm teaching kids about code and they ask "why ... " it's an opportunity for them to learn that oh-so-important lesson that in almost all cases the design decisions in software are totally arbitrary or of such obscure etymological origin that, unless you actually want to be a computer science historian, the best answer is "because".

Re: Coroutines make robot code easy

#116
post #115

Earlier quoted context omitted.

Having taught FRC students to use Java: when you're talking about people with very little experience programming before, the multiple class abstraction is itself an obstacle to accomplishing the goal. I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "Bu…

> the multiple class abstraction is itself an obstacle to accomplishing the goal. Not if your goal is to learn about object orientated programming! > I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "But we already said 'drivetrain' in the constructor,…

They're students, of course they ask why.

And while nobody had a nervous breakdown, yes, the need to pass references around extremely redundantly because this language lacks any way to establish a global context and top level non-class variables was a continuous impediment to their ability to accomplish the task.

I've seen some good suggestions in this topic though; I think next year I may recommend a top-level container class that has init called on it one time and can then be referenced in all other class files. It's the closest thing to global variables Java has to offer, and would save them a lot of hardship passing references around for no other reason than passing references around.

Re: Coroutines make robot code easy

#117
post #72

Coroutines are covered in Knuth's first volume. And, I confess, I think I went years thinking he was just describing method calls. Yes, they were method calls that had state attached, but that felt essentially like attaching the method to an object and calling it a day. Seeing them make an odd resurgence in recent years has been awkward. I'm not entirely clear that they make things much more readable than alternative…

With these examples I think the author would still be stuck with stepping through the state machines with the students. Unless what you wrote would allow for the "autonomousPeriodic function to keep ticking" another way?

Re: Coroutines make robot code easy

#118
post #115

Earlier quoted context omitted.

> the multiple class abstraction is itself an obstacle to accomplishing the goal. Not if your goal is to learn about object orientated programming! > I can't tell you how many times students have gotten frustrated trying to understand why you have to pass arguments into the constructor or, for that matter, Why the constructor is different from other method calls. "But we already said 'drivetrain' in the constructor,…

They're students, of course they ask why. And while nobody had a nervous breakdown, yes, the need to pass references around extremely redundantly because this language lacks any way to establish a global context and top level non-class variables was a continuous impediment to their ability to accomplish the task. I've seen some good suggestions in this topic though; I think next year I may recommend a top-level conta…

Right, yeah that sounds like the task for which I typically use a Singleton:

https://www.digitalocean.com/community/tutorials/java-single...

Things like connections to databases, network resources, motors and those types of things.

Re: Coroutines make robot code easy

#119
You could have used Kotlin if you wanted to stay on the JVM and use coroutines.

Your desired pseudo-code in Java would look like this in Kotlin:

    coroutineScope {
        // Drive backward
        launch {
            while (drivetrain.getDistanceInches() > -48) {
                drivetrain.arcadeDrive(-0.5, 0)
            }
            drivetrain.arcadeDrive(0, 0)
        }

        // Grab for two seconds
        launch {
            val grabTimer = Timer()
            while (grabTimer.get() 

Re: Coroutines make robot code easy

#120
post #2

If you want to make it easy for high schoolers, just don't use java in the first place...

Having learned Java in high school and later taught Java, Python and C++ to high-schoolers, things have improved greatly in Java. The days of memorizing the entire BufferedReader try-catch snippet are over. The new file and stream APIs are almost as clean as in Python and making GUIs (Swing for basic and JavaFX for advanced) is even easier than Tk in Python.

For me, it boils down to a choice between typed and "non-typed" languages, where the best typed option is Java and the best "non-typed" are Python or maybe JavaScript (NodeJS). Everything else is some combination of not mainstream enough, not powerful enough out of the box or requires too much knowledge to get started. Java and Python read like English, have most of what you'll need included and are very useful languages for students to get their first internships/summer jobs working with.

Post reply on HN