14,277 karma · joined March 19, 2015
Nearly all of the devices you use employ these approaches in one form or another. A watchdog timer[2] is a pretty simple and powerful version of this. Timeouts and retries follow a somewhat similar approach, Erlang just embraces that across the whole language. It really is a fascinating approach to a different design space(latency and reliability over throughput) through the requirements a telecom stack necessitated.
My tech director in games used to have a ~40mb static array at the top of main.cpp with a big comment along the lines of "DO NOT TOUCH". When we'd come up on a demo or critical milestone and just could not get everything to fit in the ~512mb of ram we needed because the art team put in too many textures or our new subsystem too much memory he'd go in and knock 5-10mb from it and "save the day".
The same tech director removed mip level zero to get back ~33% of our texture memory. About a week later he told the art team that we'd optimized the game and asked if they noticed any visual differences. The art team said they didn't, about 4 weeks later it got out what he actually did and they were livid.
I briefly toyed with the idea of building out some open source hardware/software but I didn't really seem like there was enough of a userbase to make it viable. Anyone using it professionally wants support and 10+ years of parts, most maker/hobby projects want direct access to code.
Still some pretty neat concepts for putting together highly customized processes with extensible and interchangeable hardware.
It was pretty illuminating how many parallels ladder has with the visual and scripting solutions I'd worked with in GameDev. Hot-reload under running processes, visual debugging very reminiscent of node based visual editors. I ended up automating our greenhouse with a P100[2] from Automation Direct and was pretty impressed with how straightforward it was to use.
Structured text is making in-roads in some places from what I can tell but ladder still seems to dominate because it's easily understood and maps well to a "relay based" mental model. It seems to be very sticky, at least more than most visual scripting languages I'm familiar with.
[1] https://en.wikipedia.org/wiki/Ladder_logic
[2] https://www.automationdirect.com/adc/shopping/catalog/progra...
Most radio groups tend to be disaster recovery and communication adjacent so they care about infrastructure even if it's not directly on the ham bands.
I also rebuilt our audio streaming system over the course of 48 hours to use the texture streaming subsystem when we exceeded the 64 file handle limit on an certain platform. We needed to hit a date for a TGS demo and I can guarantee you that we had things which were even more YOLO for a fairly decently sized team/game.
Go look up dead reckoning, those types of games are built to handle 100-250ms of latency which is way outside a frame/tick.
After turning in the assignment the next class he grabbed one random assignment from the class and added some quick benchmark instrumentation and if I remember right then asked the class how fast we think it could run. The next 30 minutes was a total geek out on cache lines, prefetching, alignment and all the other dark arts of performance optimizations. I don't remember how fast he got it to go over the naive for loop but it was many orders of magnitude. There's a few classes that really stick with you and that was definitely one of them.
[1] https://mekka-tech.com/posts/2018-08-09-the-difficulty-ancho...
I would argue that if you don't understand the ownership of your data you don't really understand C++(or C) and you're still learning the language. That's usually the big shift I see when developers who have a background in higher level languages moving down to C++. I've seen plenty use after free and heap corruption happen in C++0x11 and onward codebases both staying completely within modern best practices and when code diverges since there's no guardrails(ex: std::string::c_str, std::unique_ptr::get and the like).
Once you include all the footguns that exist(yes, even in modern C++) and the legacy parts of existing codebases or code that diverges from modern C++ that's why I think it has a much higher learning curve to be producing code that is at the same quality as a passing compile from Rust in aggregate.
Language difficulty I'm having trouble seeing how C++ isn't harder there. You have decades of features, lots of gotchas that I could rattle off and a bunch of implicit behavior that you only learn about when it blows up at runtime(if your lucky). Heck, I've seen heap corruptions stay latent in codebases for 6+ months only to have a new field added that causes them to cascade into a failure that took 3 weeks to debug across 2 different teams. I've still seen modern compilers not catch basic use after free scenarios in code today.
I won't disagree that you can get code to compile quicker in C++ but if your goal is feature velocity you're better served by a high level language. If your goal is stability, performance and memory which is the domain of systems programming then I think C++ has a bunch of hidden failure modes that Rust frontloads in an elegant way.
There are projects where you'd pick C++ for portability on platforms LLVM doesn't support or momentum with existing codebases but if I had to pick between the two my personal bias is towards Rust for all the reasons above.
With C++ unless you have someone experienced on a team there's a host of "unknown unknowns" that feel like the team is making progress but then having to pay the cost when it blows up and usually when schedule pressure is near the highest point. Same for the build systems, retrofitting LTO is not a fun experience.
Rust in contrast calls out many of those things upfront, I've found those guardrails prompt conversations in tradeoffs and conscious choices(to say use Rc/RefCell) you'd be making anyway in C++.
Having seen teams go Java -> C++ and other teams go C -> C++ I don't really think that's the case. The former leans on shared_ptr everywhere, the latter ends up hitting footguns with implicit behavior around move semantics, RAII(seen more than a few use after free here) and the like.
ASAN and other tools help, but assume they are run regularly and kept to a level of rigor I haven't always seen in codebases.
Last week it was a combination of forgetting the exact specifics of RVO hitting the implicit copy constructor that was causing things to go sideways. The number of implicit behaviors are pretty wide and things like move semantics still feel pretty brittle.
To take that further the most successful teams weren't the "smartest" or the "hardest working" but ones that had the fastest iteration loop. It drives everything else about the process, relentlessly optimize that loop and it was like a superpower that enabled teams to take more chances at whatever difficult thing they were trying to solve.
Sorry but I'm going to call bullshit on your bullshit. Spent ~5 years in the industry and every place I worked crunched like hell and every place that my coworkers came from crunched like hell. There are companies that limit crunch but they are few and far between.
My experience was that those who survived crunch perpetuated a culture of needing to "pay your dues" and you weren't a "team player" if you didn't put in the extra hours on salary.
In theory when they sort that out Rust should be able to turn on restrict where it applies globally "for free".
The PLC sends me a mail each morning with how much water it used, the max temperature of the water pump(I repurposed a RV water pump with a PID PWM + SSR driven from the PLC) all running from a 24v solar system. They're very much designed to be in-the-loop on systems that need to be robust with pretty extensive error report/alarms and the like.
I sometimes wonder what the world would be like if Lua had zero based indices and saw a bit broader adoption. It's such an easy language to embed/extends although QuickJS looks like it's going to give it a run for the money in the long term given the similar goals on ease of embedding.
I wonder if anyone has compiled QuickJS to WASM and run it in the browser.
With print debugging your inserting the whole build + deploy + repro setup loop into your debugging, if that's a long time(say 20 minutes in one job I had with production hardware) you're in for a world of pain. I find that just about any other tool usually is an order of magnitude more efficient.
Also even the "step debugger" tools do the same thing you'd do with a print. LLVM for instance uses the IR JIT API to generate watch/eval values: https://releases.llvm.org/9.0.0/docs/ORCv2.html#use-cases
IMO you should relentlessly optimize your iteration times, that's the inner loop of development speed and print debugging fares pretty poorly in that area for all the reasons above.
In my domain which doesn't usually cover distributed systems printf can be worse because it introduces synchronization primitives that have caused race conditions to disappear(and that race condition causes second order heap corruption or the like). On one platform system memory was so small(8mb total) that each output to stdout went over the serial link slowing performance down to 1/20th of a realtime process under any real logging.
Like I said, different tools for different uses, and really depends on the context. If there was one size fits all then we'd just use that but the diversity of debugging tools I think shows that you need a variety of techniques to approach the problems we encounter.
I also don't think they're nearly as no-code as you call out. VS' watch window has very few limitations compared to printf back when I was working on win32 things.
Also important to consider iteration time. I once worked on a system where adding a printf was a 20 minute process due to the need to heavily optimize for a memory constrained platform(scripting fit in 400kb block with the asset bake step).