Direct comparing of two QVariant variables
-
[quote author="Gerolf" date="1326709312"]a double is represented by 8 bytes, mantisse and exponent[/quote]
Yes, 64 bits
[quote author="Gerolf" date="1326709312"]They have influence on how to read each other. If you do a byte compare, that does not work.[/quote]
It will. Just use 64 bits integers. Check yourself
-
By the way, if all numbers are allowed (positive as well as negative) you can safely check the sign of the difference between the two values, so the method seems to be universal
-
If you do things like this, please leave a note for the next developer to start debugging right here if the application starts to crash somewhen.
@
void lessThan(void* left, void* right)
{
return (quint64)left < (quint64)right;
}
@
Another rule one might stick to: even if it is possible, it doesn't mean that it should be done that way. -
[quote author="Lukas Geyer" date="1326717017"]If you do things like this, please leave a note for the next developer to start debugging right here if the application starts to crash somewhen.
@
void lessThan(void* left, void* right)
{
return (quint64)left < (quint64)right;
}
@
Another rule one might stick to: even if it is possible, it doesn't mean that it should be done that way.[/quote]If the code is like this, it might crash if the value is not 64 bit long and not enough memory to read is there. Additionally, it might bring problems with little / big endianess, right?
-
As long as you stick to the OPs self-imposed limitations [limited set of datatypes, fixed size of 64 bit for every datatype, fixed floating point format, non-portable (including endianess)] this code actually does work. However, this usually does not justify the use of such code in production, as it will break on first occasion.
-
[quote author="Lukas Geyer" date="1326717017"]If you do things like this, please leave a note for the next developer to start debugging right here if the application starts to crash somewhen.
@
void lessThan(void* left, void* right)
{
return (quint64)left < (quint64)right;
}
@
Another rule one might stick to: even if it is possible, it doesn't mean that it should be done that way.[/quote]Just add the lengths of the byte arrays to the function declaration and make proper use of them within and almost all of the pitfalls you talk about will go away
You cannot take measures of safety against everything. If you try, you will inevitably fall into an endless loop
-
But if you add the length, you add information that is type specific. This means some if at call, which you wanted to remove.
-
[quote author="deisik" date="1326724760"]
You cannot take measures of safety against everything. If you try, you will inevitably fall into an endless loop[/quote]You can by avoiding a design that is broken from the very beginning.
I'm not now.
-
[quote author="Gerolf" date="1326726540"]But if you add the length, you add information that is type specific. This means some if at call, which you wanted to remove.[/quote]
For sanity check. I personally would not need it since I know that other constraints make it redundant. Period
This is what the word "integrity" stands for
-
[quote author="Volker" date="1326726676"]You can by avoiding a design that is broken from the very beginning[/quote]
Sorry, this won't help you. If it would, there would be no bugs in the software which is written with the aim "of avoiding a design that is broken from the very beginning"
-
[quote author="deisik" date="1326724760"]
Just add the lengths of the byte arrays to the function declaration and make proper use of them within and almost all of the pitfalls you talk about will go awayYou cannot take measures of safety against everything. If you try, you will inevitably fall into an endless loop[/quote]
You lose the limitation of fixed sizes, but you are still limited to some datatypes, you are still limited to a fixed floating point format and your code is non-portable by any means, because you rely on archtictural and implementational details.
What happens if the two sizes do differ? Do you start creating buffers within <code>lessThan()</code>? What if the size exceeds <code>sizeof(quint64)</code>, for example QINT64_MAX in string representation? Do you add your own comparison algorithm? How can you assure that <code>lessThan()</code> is only invoked with supported datatypes, as every datatype fits in void*? What if you compiler or FPU implementation does not support or use IEEE 754?
Of course you can't take measures of safety against everything, but you still have to assure that your code is as least error-prone as possible. One way to achieve this is to make use of C++s type safety, which is completely nullified by void pointers and C-style casts. Your code doesn't get flexible, it just gets error-prone.
It was a nice brain-twister, for all of us; and there is a use case where it actually works - but do yourself a favor and just use "correct" code. Everything else will lead to serious problems sooner or later.
@
bool lessThan(int left, int right)
{
return left < right;
}bool lessThan(double left, double right)
{
return left < right;
}bool lessThan(const char* left, const char* right)
{
// if you need further saftey or error handling use
// stringstream, boost::lexical_cast or just QStringreturn atoi(left) < atoi(right);
}
// An implementation for QVariant is found in other posts of this thread
@
This solution is just a few more lines (or, if you handle most of the limitations in your implementation, a lot less lines), absolutely type-safe, easily extensible and understandable and as least error-prone as possible. -
[quote author="Lukas Geyer" date="1326727414"]You lose the limitation of fixed sizes, but you are still limited to some datatypes, you are still limited to a fixed floating point format and your code is non-portable by any means, because you rely on archtictural and implementational details. What happens if the two sizes do differ? Do you start creating buffers within <code>lessThan()</code>? What if the size exceeds <code>sizeof(quint64)</code>, for example QINT64_MAX in string representation? Do you add your own comparison algorithm? How can you assure that <code>lessThan</code> is only invoked with supported datatypes, as every datatype fits in void? What if you compiler or FPU implementation does not support IEEE 754?[/quote]
It is for sanity sake only. As I said before there is no need for it because other limitations and conditions would exclude it to a certain degree. And at that you cannot write code that fits everyone or is suitable for every purpose or supposed to run everywhere, you have to make trade-offs - it is just a matter of understanding what is possible and what is not in the given conditions (please, note). Yes, conditions may change but they may also change in such a way that your software will come to be just a piece of garbage despite it being of a "correct design"
[quote author="Lukas Geyer" date="1326727414"]It was a nice brain-twister, for all of us; and there is a use case where it actually works - but do yourself a favor and just use "correct" code. Everything else will lead to serious problems sooner or later[/quote]
Everything potentially can lead to any kind of problems - it is just a matter of time
-
It is beyond me why anybody would add such a malicious piece of code on purpose, especially if I could add code with the same or even less effort that works in 95 out of 100 cases and is absolutely type-safe instead of code that breaks on 95 out of 100 cases and has a load of potential pitfalls and limitations attached. But I think this has been stressed enough. In the end it is your decision and your accountability, not mine.
-
[quote author="Lukas Geyer" date="1326781097"]It is beyond me why anybody would add such a malicious piece of code on purpose, especially if I could add code with the same or even less effort that works in 95 out of 100 cases and is absolutely type-safe instead of code that breaks on 95 out of 100 cases and has a load of potential pitfalls and limitations attached[/quote]
Do you actually think that type safety imposed by other means is always less strict?
-
Something that I don't get is why you insist on doing it this way? What do you think is your benefit? Having one line of code less? Do you think this has better performance?
-
[quote]
Do you actually think that type safety imposed by other means is always less strict?
[/quote]Of course not, because the sole purpose of type safety is to be restrictive. It prevents developers from using code that has been written to work with a specific set of datatypes with any other datatype. There is nothing that hinders me to pass any object through the void* pointer in your implementation, not just int, double and const char*. This can be fatal and this is what I meant by saying your code doesn't get flexible, it just gets error-prone.
-
[quote author="KA51O" date="1326785780"]Something that I don't get is why you insist on doing it this way? What do you think is your benefit? Having one line of code less? Do you think this has better performance? [/quote]
In short, because chaining ifs (in whatever form) is a wrong way of doing things (let alone those deadborn template structures). The found solution may be dangerous but to me it is by far a more genuine and elegant way of doing this. Surely, it is not qt's fault that you have to hard-code your types, in c/c++ you cannot just write something like reinterpret_cast<type> where <type> is purely a run-time variable. So the idea of a void* pointer is brought forth as a revolt against this drawback. Yes, it is a wild beast that can kill you in a glimpse but if you know how to handle it all its power is at your disposal
Look, I have QDateTimes which are stored on disk as plain seconds and it takes ages to convert them back and forth. I could bear time when bulding index, but it would be hell to use them to retrieve data. Why not make comparison between those ints leaving these QDateTimes alone, you would ask me. Well, but why then stop half-way and not make direct comparisons between byte arrays, I would ask you? In fact, such comparisons make things even simpler since I already have to deal with raw data, so it won't actually get much worse than that
-
[quote author="Lukas Geyer" date="1326787337"]Of course not, because the sole purpose of type safety is to be restrictive. It prevents developers from using code that has been written to work with a specific set of datatypes with any other datatype. There is nothing that hinders me to pass any object through the void* pointer in your implementation, not just int, double and const char*. This can be fatal and this is what I meant by saying your code doesn't get flexible, it just gets error-prone.[/quote]
Yes, because such is the nature of a void* pointer. The pistol shoots and somebody will surely shoot himself - you cannot make everything bullet or fool proof
-
[quote author="deisik" date="1326790752"][quote author="KA51O" date="1326785780"]Something that I don't get is why you insist on doing it this way? What do you think is your benefit? Having one line of code less? Do you think this has better performance? [/quote]
In short, because chaining ifs (in whatever form) is a wrong way of doing things (let alone those deadborn template structures). The found solution may be dangerous but to me it is by far a more genuine and elegant way of doing this. Surely, it is not qt's fault that you have to hard-code your types, in c/c++ you cannot just write something like reinterpret_cast<type> where <type> is purely a run-time variable. So the idea of a void* pointer is brought forth as a revolt against this drawback. Yes, it is a wild beast that can kill you in a glimpse but if you know how to handle it all its power is at your disposal
Look, I have QDateTimes which are stored on disk as plain seconds and it takes ages to convert them back and forth. I could bear time when bulding index, but it would be hell to use them to retrieve data. Why not make comparison between those ints leaving these QDateTimes alone, you would ask me. Well, but why then stop half-way and not make direct comparisons between byte arrays, I would ask you? In fact, such comparisons make things even simpler since I already have to deal with raw data, so it won't actually get much worse than that[/quote]
I understand your approach and there may be uses cases were this solution is valid, but unless it is absolutely neccessary I would not use this solution.
-
[quote author="deisik" date="1326790823"]Yes, because such is the nature of a void* pointer. The pistol shoots and somebody will surely shoot himself - you cannot make everything bullet or fool proof[/quote]
[quote]The found solution may be dangerous but to me it is by far a more genuine and elegant way of doing this.[/quote]
Well, let's just agree that we have different development principles.
I wish you the best with your solution, but I'm officialy out now as this discussion obviously leads nowhere and is rather pointless at this moment.