4 ms·
>Yeah, I suspected that you and lerptime were the same person. to get around the post limit. Keep it on the DL. >When you make such a statement, you sound lik
by nendroid 6y ago
>Yeah, I suspected that you and lerptime were the same person.
to get around the post limit. Keep it on the DL.
>When you make such a statement, you sound like someone with fairly limited experience. In particular, from your example, I suspect that you've never worked in a multi-threaded embedded system. somethingToBeInSyncTo, done that way, means that any other thread holding a reference, holds a reference to the old value, while this thread has the new one. And updating running threads with new values on the fly is... problematic.
I find that you're the one who seems inexperienced. My example is thread safe ... makeNewState is a combinator. It makes no mutations. Like IO, and mutations, the problems with threading happen with mutation. Thus, locks and other procedural commands used to deal with threading live in the void IO function.
We're more referring to coupling functions with external data and mutations via objects. If you're talking about synchronizing two threads, this again needs to be handled with parent IO function outside the logic of your pipeline combinators. You can still segregate logic away from threading and IO.
My combinator in this case is useable for your example case of synchronizing two threads. If you organized your code in ways where my combinator will be unusable than you have failed to decouple your logic away from threading, IO and mutation.
- AnimalMuppet 6y ago> I find that you're the one who seems inexperienced. 35 years professional software engineering, 30 years in embedded. I'm going to guess that you have less. Your way of organizing code works great, on paper. Maybe on a small project. For a real embedded system, with multiple threads, with state data being used everywhere... your approach doesn't make much sense. It makes a much worse design than shared mutable state. (Yes, shared mutable state is in fact as evil as you have think it is. It's still better than trying to make your alternative work in that environment.) Why is state data used everywhere? Because embedded systems often respond in different ways depending on the state of external inputs, and don't go read the state at the time they make the decision on how to respond. If those decisions are spread through the bulk of the code, there's really not much left to put in your combinator. And there's no point in trying to add that paradigm to a system that's going to have tons of shared mutable state anyway.
- nendroid 6y ago>35 years professional software engineering, 30 years in embedded. I'm going to guess that you have less. Doesn't change the fact that you're wrong and 35 years of programming doesn't ensure that you're a good developer. There are examples of crap code and patterns that have been around perpetually. >Why is state data used everywhere? Because embedded systems often respond in different ways depending on the state of external inputs State being everywhere doesn't preclude it to being segregated from logic. >If those decisions are spread through the bulk of the code, there's really not much left to put in your combinator. And there's no point in trying to add that paradigm to a system that's going to have tons of shared mutable state anyway. The decision is what goes in the combinator. #IO functions. Data getIOFromModuleA() void sendIOToModuleA(Response r) Data getIOFromModuleB() void sendIOToModuleB(Response r) .... # combinators, reuseable in both module A and module B because of segregation from IO and State Decision makeDecision(Data x) Response createResponse(Decision x) It's the same pattern for State. Just replace the word IO with State. Response can be anything, it can be the entire new state of the program. It can represent a delta of a change, it can be a response specific to a module. Also again, all threading commands go into State or IO functions. OOP fails to segregate code this way and if you don't organize your code like this then you have 35 years of experience of navigating someone elses mess or your own.
- AnimalMuppet 6y agoSo I said you were inexperienced. You said I was. I listed my experience. You said it was the wrong experience, but conspicuously declined to state your own. So I'll just leave you with this. "In theory, there is no difference between theory and practice. In practice, there is." You've got your theory. Nice theory. Use it for a decade of actual real-world work, and let me know how it works out. I'll be especially interested if any of that work is in embedded.
- nendroid 6y agoI said it as a minor minor retort. You want the full story? The full story is I don't care for experience. I find experience doesn't correlate with actual skill. Many experienced developers act and seem very inexperienced which is what I said about you: You "seem inexperienced" because you act that way. The very act of bringing up experience is off topic and a sign of lack of maturity. If you have to know I'd say I have about 15 years of experience in research, gaming, embedded and web. I will say that the pattern I described can be followed in every one of those fields but it's a niche pattern because it is indeed promoted by people who do FP. I don't know why you focus on embedded, but embedded people tend to follow these patterns the least due mostly to C++. The overall promoted pattern in C++ is to pass references everywhere and it's highly unlikely that someone in that world will follow this pattern because you have to go out of the way to do it and learn about it. It requires a disciplined approach. The big problem is if you need to slightly modify a bunch of values in an array of 100 objects. It's hard to figure out the right way to do it in a combinator. The common pattern used nowadays is instead of having combinators handle it, have the combinators generate logical instructions to send to the IO function similar to how in web development your stateless servers pass SQL instructions to the SQL server. The IO function processes the instructions and handles the threading, mutation and IO. Here's a library that does this: https://github.com/google/cpp-frp <---- real world example. Nothing I said is "theory" in the sense that you put it. These are rare but actual patterns that are used successfully by people in the know. You are not in the "know" despite your experience. As a result for most of your program experience you've just been dealing with and fixing mess after mess after mess.