4 ms·
I 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
by nendroid 6y ago
I 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.
- AnimalMuppet 6y ago"It is useless to have a conversation with those who will not listen." Neither of us are listening, because we're both sure we're right. So I'm out. You get the last word, if you want.
- nendroid 6y agoDon't be stupid. I'm listening to you. I'm actually responding to you. You say theory is different from the real world so I present you with a real world solution and examples of how it works with embedded specifically. Your job should you choose to continue is to use other real world examples to counter my arguments. That's all, if you convince me it's done, If i convince you it's also done. Until then leaving the discussion before it's resolved is pointless. Don't back out, I'm not fighting for the last word. I'm having a discussion with you in hopes you can convince me. But you haven't really said anything substantial other than things along the lines of "Trust me I have lots of experience, your stuff is just theory." If you start introducing the real arguments then this discussion can actually go somewhere.
- AnimalMuppet 6y agoFine. void handleEvent1() { if (currentState == state1) { currentState = state2; setHardwareState2(); } else { currentState = state3(); setHardwareState3(); } } You can move state to the boundary, and IO to the boundary, and then... what's left? It was all boundary. A bit more realistically, here's an automobile cruise control that uses the same button for "reduce set speed" and "set the speed". (Don't blame me, I've had more than one car with that exact setup). void buttonXEvent() { if (cruiseControlEnabled) { if (cruiseSpeedSet) { cruiseSpeed--; } else { cruiseSpeed = currentSpeed; cruiseSpeedSet = true; } writeSpeedToEngineComputer(currentCruiseSpeed); } // else do nothing } How would you write this in your approach?
- nendroid 6y ago//combinators CruiseSpeed = int CruiseSpeed getNextCruiseSpeed(bool cruiseControl, bool cruiseSpeedSet, int cruiseSpeed, int currentSpeed) { if cruiseControl && cruiseSpeedSet return cruiseSpeed - 1 elif cruisControl && !cruiseSpeedSet return currentSpeed else return cruiseSpeed } bool getNextCruiseSpeedSet(bool cruiseControl, bool cruiseSpeedSet){ return cruiseControl && !cruiseSpeedSet ? true : cruiseSpeedSet } //IO functions void getCurrentSpeed() bool isCruiseSpeedSet() void setCruisSpeedSet(bool cruiseSpeedSet) void writeSpeedToEngineComputer(CruiseSpeed x) void handleButtonPress(bool cruiseControl, bool cruiseSpeedSet, int cruiseSpeed, int currentSpeed){ speed = getNextCruiseSpeed(cruiseControl, cruiseSpeedSet, cruiseSpeed, currentSpeed) cruiseSpeedSet = getNextCruiseSpeedSet(cruiseControl, cruiseSpeedSet) writeSpeedToEngineComputer(speed) setCruiseSpeedSet(cruiseSpeedSet) } Your example uses free variables extensively. It means that all your logic cannot move outside of the context of the free variable which means they cannot be reused. Even IO functions should not use external context. Combinators can be reused everywhere.
- AnimalMuppet 6y agoI see no respect in which your solution is superior. By the time you implement getCurrentSpeed(), etc., you're going to have a fair amount more code than me. (writeSpeedToEngineComputer() doesn't count, because I need to implement that also.) Your reason for doing so is, I think, in your last two paragraphs. But this isn't particularly reusable code - I'm not going to use getNextCruiseSpeed() or handleButtonPress() in the windshield wiper controller. It's pretty much tied to the specific use. (There may be a handleButtonPress() in the windshield wiper controller, but I can't reuse this one.) So you offer me something that is more verbose, based on a benefit that I can't actually benefit from. (I presume that getCurrentSpeed() returning void was just because of quick typing.)