140 ms·
Very good point! I'm caught between a rock and a hard place... Apart from their other downsides, stackful coroutines can make asynchronous code less readable.
by fleabitdev 6y ago
Very good point! I'm caught between a rock and a hard place...
Apart from their other downsides, stackful coroutines can make asynchronous code less readable. For example, it's not obvious that your self:move() call is split across several frames.
Implicit coroutine construction has the silent failure mode which you describe.
Explicit coroutine construction, (coro f), would make `yield-from` even more noisy than it already is!
I wonder whether a naming convention would solve the problem? If all coroutine functions and methods have names like fire-arc* and move* , then your synchronous call to fire-arc* would stick out like a sore thumb. This would also force the programmer to visit every callsite after changing a synchronous function into an asynchronous one, or vice versa. It wouldn't exactly be convenient, but I think I value explicitness more highly than convenience in this case.
- john-shaffer 6y ago> I wonder whether a naming convention would solve the problem? If all coroutine functions and methods have names like fire-arc* and move* , then your synchronous call to fire-arc* would stick out like a sore thumb. That'd be fine as long it's simple to write a wrapper of a different color. If I change fire-arc to fire-arcSTAR, but I can do a quick (def fire-arc (to-sync fire-arcSTAR)) then I don't have to visit call-sites. If it's not possible to make a wrapper, then that would be a major pain point. Edit: Can't get HN to print the asterisks.
- fleabitdev 6y agoBut the * suffix marks functions which might stagger their execution over multiple frames. If a function calls fire-arc* , then that function should also have the * suffix; otherwise, the suffix would be meaningless. You're asking for the ability to refactor a synchronous function into an asynchronous function without needing to review the function's callsites. By definition, this would come with a high price: when writing a step handler, you'd need to assume that any function call could be refactored so that it doesn't return until several frames in the future. Even for a Lisp, that seems chaotic!
- john-shaffer 6y agoOh, thanks for the explanation. That makes things very clear. I'm not sure when I'll get time to play with GameLisp, but it looks absolutely brilliant. I'll keep an eye on it; maybe some interesting open-source project will turn up that I can hack on.
- anonymoushn 6y agoI think we have different views about the process of scripting behaviors, which determines most of our conversation so far. I don't like taking algorithms in my mind, breaking them up into basic blocks by hand, and writing a switch statement in a step handler. I especially don't like iterating on code that has been manually turned inside out in this way. So I do not write any step handlers at all, barring extremely general things like "things move in the direction they are moving."
- fleabitdev 6y agoSounds like an interesting approach - can you point me towards any open-source code written in this style?
- anonymoushn 6y agoI don't have any particular project in mind, but every BulletML game and many Danmakufu games are written this way. My favorite BulletML game is rRootage[0], but the scripts used in rRootage are procedurally generated combinations of scripts from other games, so they may not make good reading. I think Shiroi Danmakukun[1] features handmade scripts. BulletML and Danmakufu's scripting language are not my favorite languages for other reasons. [0]: http://www.asahi-net.or.jp/~cs8k-cyu/windows/rr_e.html http://www.asahi-net.or.jp/~cs8k-cyu/windows/rr_e.html [1]: https://shinh.skr.jp/sdmkun/ https://shinh.skr.jp/sdmkun/