The changing landscape of OOP (from class to struct)
-
To be fair, this was the beginning of the example, but the main thing you get is the compiler can check the type and warn you that you are using the wrong type. This also means the code is quite a bit more explicit about what it wants so a future dev who may have thought, "hmm....wonder why orig-dev wanted a double when a float would do" would be guided away from such a thought since there is a specific type. That's all I got. :)
Orig-dev could/should have provided a comment if choice of the primitive type was significant. "Keep it as simple as possible, but no simpler". Many developers have a tendency to introduce complexity for the sake of it, because it looks clever, it's an interesting exercise, or other similar reason, when it achieves little but obfuscation.
-
Just started reading this (just released) book, The C# Type System (no starch press)[^] and the first chapter is kind of blowing my mind. Step 1 Author starts out with the following example and says, "You must use better named variables so dev users know what they mean."
Displacement(double t, double v, double s)
{
var x = v * s * Math.Cos(t);
var y = v * s * Math.Sin(t) - 0.5 * 9.81 * Math.Pow(s, 2);
return (x, y);
}Yes, that makes sense. Step 2 Then he says, "Oh, you can add meaning with this new idea of named arguments so users don't have to remember order that they should be passed in."
var result = Displacement(angle: .523, speed: 65, elapsedTime: 4);
Ok, yes, that is good advice with the modern capabilities. Step 3 May Blow Your Mind He mentions that the code is still confusing because all three arguments are the same primitive type (double) and this leads into...
From the book:
Primitive Obsession code smell, which describes any code that has an overreliance on primitive types—that is, those types that are built into the language, such as int, double, and string.
The solution is... Wrap All the Primitive Types In Structs 🤯🤯🤯🤯🤯
public struct Angle
{
public double Size {get; set;}
}
public struct Speed
{
public double Amount {get; set;}
}The Paradigm Has Shifted Now, when the user attempts to call the
Displacement
method the compiler will know that the argument type is wrong. Now, there's no way to pass the wrong value into the method, because the compiler will know the type. Wow, that is a very different paradigm!! Step 4 Is Immutability Now, make each struct immutableWhile I can see the value in some corner cases perhaps, I feel like the acceptor, such as a parameter name on a method should describe what it accepts. Maybe it's just because I grew up with that, but putting the units for example, on the data type itself seems just ... unusual, and kind of awkward to me. Maybe that's not the best argument against it, but I place a lot of value on being able to lean on habits, so long as the habits aren't actually counterproductive. All else considered equal, I place more value in doing something in a way that's supported by "muscle memory" than I do on implementing something perhaps in a more formalized way, and the reason is, if you can lean into your habits, as long as you develop decent habits you get less bugs and more productivity.
Check out my IoT graphics library here: https://honeythecodewitch.com/gfx And my IoT UI/User Experience library here: https://honeythecodewitch.com/uix