With functional languages, it tries to enforce some explicit type signatures in the function arguments so things are cleaner within the functions themselves.
With functional languages, it tries to enforce some explicit type signatures in the function arguments so things are cleaner within the functions themselves.
Structs have the issue you describe and they aren't really OOP.
Yes, if the first thing you do when you write a class is make a setter method for each field then you will have problems. That's not really a property of OOP.
All of these logical errors that are easy to commit are terrible because they are usually runtime bugs, not compile time.
As I think of it, I think a neat feature of OOP would be conditional methods that are only callable under specific circumstances. For example, the “Customer.SendPasswordResetEmail()” method couldn’t be called (or didn’t even exist) until I verify that the “Customer.IsEmailVerified” property is true.
Being able to add these type of annotations to methods for expected object state would help catch some logic bugs at compile time.
Const-ness is one of the things I really miss from C++. I could look at an object and be reasonably sure I wasn't mutating it by calling foo.length() for example.
Sometimes I want to add one little extra thing that gets mutated in an otherwise "const" method, e.g. for debugging purposes. If the compiler doesn't let me do that because I valued the ideal of const-correctness higher than practical concerns, I know I've done something wrong.
In the vast majority of cases it reduced my cognitive load significantly because I could just look at the method declaration and see that my code would be fine.
However, IME there is a big problem with const for more database-y, more stationary in-memory data. This is the kind of data that is almost always going to be mutated by at least some part of the code at some point in time. There is a fundamental problem of communication between mutating code and non-mutating code (the "strstr()" function, that has to apply a const-cast hack internally to implement its interface, is a trivial example here).
As said there are certainly situations where such "communication" isn't needed, but I'm anxious about precluding the possibility in the name of const-correctness.
I feel that instead of const (or whatever static formalized description of what a function is doing), good naming is most helpful to intuit broadly what that one function was doing again.
In C at least, I've ended up leaving const almost exclusively for the cases where the data is truly const - i.e. in the .ro section of the binary, and I know for sure it won't ever have to be modified, and basically I have to apply the const qualifier lest it puts the data in the wrong section / it needs an awful cast to remove the const. The majority of those are string literals typed as "const char *".