Juliean said:
The type of an object-instance is that, by which you created it. If you create a “HMesh", eigther on the stack or heap, that's its type. If you try to cast it down to a HMeshProcessing, this is UB.
That's the point where i am unsure. (I do understand the derived also is a base, but not vice versa. Sorry about the clumsy question formulation.)
Probably i'm just desperate, but look at this:
class Base
{
int milk = 1;
void Drink() {milk++;}
};
class Derived : public Base
{
};
void Main ()
{
Base base;
Derived ref& = (Derived&) base; // this can't be UB, since such cast does nothing yet. there is no unspecidief way to cast one thing to another.
ref.Drink(); // this should be no UB either, since both classes are equivalent.
};
If i would try to read the C++ standard for some confirmation, i'd probably need a lawyer to figure it out.
But if the answer is ‘no worries, this is specified to work’, then i would win the first round, and the next question becomes 'What if i move the Drink() to the derived class?'.
Juliean said:
However, any other strongly-typed language would except on the cast.
Sure, but that's the reason why i actually use C++. I want the low level hackery which came with C. It was low level enough to compete tedious machine code with a high level language. That's historically the reason why C++ is now the standard language for games, and it still relevant. Thus i'm not sure if specifications indeed declare things, which technically just work, UB.
Juliean said:
Well, that's exactly like saying “I went through a minefield 100 times, and never exploded, so I assure you its safe”, is it not? 😉
No it's not. Because i have exploded 100 times. I'm good at exploding, and i know what's common reasons, rare reasons, and never a reason like this. :D
Juliean said:
Creating an object like my example will be optimize out, so there is no runtime overhead.
The compiler might optimize the object away but there is no guarantee.
But i'm not worried about that, it's just that i would prefer to give as parameter, avoiding a need for extra awareness about object construction and member data.
Juliean said:
Well, actually no, not to anybody.
You make assumptions. Actually you can only believe my argument about the parameter making it harder to read, since that's all data you have. This is an exceptional case and problem, and general examples you provide are negligible to the case.
processMesh(500);
Juliean said:
Would that make your program and your coding experience more safe, or less safe?
Come on, the probability somebody would do such a mistake are tiny. But still, i would not turn off compile time type checks ofc.
It's not that i have fun with using hacks, nor do i think casting things is good practice. But sometimes it's the simplest and / or fastest way to get the job done. Like any tool, it has its applications.
But i can tell a related story. Recently i have changed my vector classes to accept only one number in its constructors. So i can make a vec(0,0,0) or Vec(1,1,1) easier. Same for a matrix to set its diagonal.
It's convenient, but it caused a kind of bug, similar to the things you expect here.
Writing stuff like
RenderCircle (5, pos, r,g,b);
can be affected, because the function actually wants more parameters: RenderCircle(radius, center, direction, colors…)
It wants a direction, which i had forgotten. So it takes the red color and makes a direction out of it. This happens because the colors have default initializers. So it compiles now, previously i would have got an error message.
This kind of bug happens pretty often now to me. And it did not see it coming.
But: There are no good coding practices which would help, and those bugs are always very easy to find and fix.
Still, for the bad coding practice discussed here, such form of bugs do not happen.
Juliean said:
Maybe you never refactor code to a way where parameter-types change. But the question is, would you not want your compiler to spot those things?
That's a price i was consciously willing to pay when i cam up with this, and i did not regret it. Well, til yet at least.
Juliean said:
If you think that's fine, so be it 🙂 I also do my fair share of stuff thats UB or unsafe, but more locally in functions and class-implementations, not really in code that could be considered user-facing/API; which I'd consider your example to be.
Yeah, i see it makes a really bad impression. It violates the standards people expect, and after the code works and no big changes are needed anymore, the advantage vanishes and confusion and doubts is all that's left.
That's what you guys have made clear to me. I did not think it would be that bad.
So i will continue using this until i'm out of this geometry processing shit-hole.
After that i will just use the derived modeling class everywhere instead the base class.
And i'll modify the other classes to take a parameter.
That's little work, and won't bother me at this point.
But i am a bit sad that i can not use my ‘creative method of grouping things’ more often.
It's a bit like my father forcing me to cut my long hair, because ‘boys do not have long hair’ :D
Thanks, guys!