• Vilx- (unregistered)

    Fun facts: in .NET the default backing type of an enum is an int. Thus, it's not even really a ByteBool. :D

  • TheCPUWizard (unregistered)

    99% probability of being a WTF.. but not 100%. The 3 valued enum will be smaller and faster...which might have mattered.

  • TheCPUWizard (unregistered) in reply to Vilx-

    As far as the underlying type... are people willing to be that something was not dropped in the editorialization of the original code???

    The approved types for an enum are byte, sbyte, short, ushort, int, uint, long, or ulong.

  • remib (unregistered)

    We have the samething with a "yes/no" enum, my colleague didn't know bool existed :)

  • ichbinkeinroboter (unregistered)

    Brainache. just e.g. with ConvertNullableInt. Because I am not sure what to do about someone who doesn't realise that -1 is a totally valid int...

  • wiseguy (unregistered)

    Sometimes you just have to byte the boolean...

    Why is it called 'ByteBool' though? as opposed to e.g. 'IntBool'

  • Bert (unregistered)

    7 comments in and no sign of it - should I call in the Maybe/Option Evangelism Strike Force?

  • No (unregistered)

    Neinth

  • Peter (unregistered)

    So this code is definitely strange, but I'd really like to see how it's used before declaring it a WTF.

  • Chronomium (unregistered)

    This looks like the handiwork of a guy who:

    1. Doesn't want to deal with getting errors out of nulls, or more accurately, to deal with properly coding to stop such errors.
    2. Is certain that for whatever the application is, negative numbers will never show up.

    Can I hazard a guess that this code was only unearthed because a valid -1 caused a difficult-to-find error?

  • I dunno LOL ¯\(°_o)/¯ (unregistered)

    “I found a ByteBool,” is called out when someone trawls through legacy code, in the same tone of voice as a lifeguard finding a “floater” in the pool.

    BOOL'S CLOSED! EVERYONE OUT!

  • KattMan (nodebb) in reply to I dunno LOL ¯\(°_o)/¯

    After reading this again I realized what it was talking about. It's the internet of shit again I see. The problem I had before is I read this was a bit more morbid, having been in the coast guard for a few years, when we referred to floaters it was something completely different and smelled a lot worse.

  • Jérôme Grimbert (google)

    There is optional field in relational database (where a missing string is not an empty string), but trying to handle that kind of data in classical languages with basic types is not a good idea.

    I even wonder if hierarchical database did not have that notion already, but I can't remember.

  • Appalled (unregistered)

    "in the same tone of voice as a lifeguard finding a “floater” in the pool." should be: "in the same tone of voice as a Custodial Engineer finding a “floater” in the toilet".

  • Herby (unregistered)

    Yes, this is bad. But wait... modern compilers have an attribute on a pointer called "NULLABLE" which is used to describe pointers that can/can't have the NULL value assigned to them. They seem to think that this can help the compiler writers in optimization (I may need a clue here), but for the most part just clogs up the declarations of library include files with (again I may need a clue here) needless fluff.

    Of course, they do it in wildly weird ways with underscores and such, but it is all weird to me.

    The concept of "NULL" as a pointer that isn't pointing to anything seems pretty easy for me, but lots of people seem to want to "complicate" it! (SIGH)

  • Gus (unregistered)

    I really did have a cow-orker that suggested we define a type ( false, true, existential ). We had enough brains to suggest they sandbox this to their own application, not part of our standard header files.

  • Jeremy Hannon (google)

    The code I introduced, I am still not sure if it is a WTF or was a good idea. We have a data element that can constantly be a Yes, a No, or a Both as in the item applies to both situations. Null is a different choice. I made a class specifically to handle this and help with comparisons where one needed to check if something was Yes without having to specifically code for "is yes or both" each time.

    Unfortunately I had to reduce the functionality of the class because of compiler optimizations. Originally I had it so you could do Boolean comparisons such that Object == True would work if the value was Yes or Both. Unfortunately the compiler will sometimes optimize this as Object != False which would normally make sense, but would not work correctly if this particular object because a Both value would mean that Object == False as well as True.

    As it is, though, it seems to still be of value, though less value that I originally planned, and possibly causes more confusion than it actually helps with.

  • Tim! (unregistered) in reply to Herby

    The problem is that, by and large, null pointer is implemented not as "pointer to nothing" but as "pointer to address 0x0." Address 0 is in theory a perfectly valid address to point at. Hardware, OS, and compiler vendors have had to alter their implementations over time to prevent easy-to-make mistakes from causing massive damage.

  • ooOOooGa (unregistered) in reply to Jeremy Hannon

    Try a bit vector.

  • siciac (unregistered) in reply to Tim!

    The problem is that, by and large, null pointer is implemented not as "pointer to nothing" but as "pointer to address 0x0."

    Only C compilers have to worry about this because the language has pointer arithmetic and has defined NULL as 0 for so long and there's a huge body of code that depends on it being 0.

    It's misleading to claim that a single language doing a thing is "by and large" even if it's a very commonly used language.

  • Tim! (unregistered) in reply to siciac

    Null reference and null pointer are different things. I was responding to "The concept of 'NULL' as a pointer that isn't pointing to anything" with "but the NULL pointer is in fact pointing to something: the value at address zero."

    I agree that many languages lack pointers and thus lack a NULL pointer. Feel free to refer me to a language with a NULL pointer that actually points at nothing.

    Most (all?) machine languages have the same issue as C/C++ with null pointers. All other languages with pointers that I am aware of have built in "pointing to zero is a signal value that means raise an exception instead of doing what the code says." Machine languages often have similar behavior at the hardware or VM level. Hence "hardware, OS, and compiler vendors have had to alter their implementations."

  • Patrick (unregistered)

    Jeremy Hannon: Uhm, use a bitmask? Unless you are coding COBOL or another of the (few) languages that don't support binary arithmetic...

  • I dunno LOL ¯\(°_o)/¯ (unregistered) in reply to Tim!

    ...which of course can lead to suffering in an embedded environment where RAM begins at 0x00000000.

  • Starchild (unregistered) in reply to Patrick

    I think you could do it in COBOL as well, though it'd probably require some violence. I'm thinking a lot of dividing/multiplying by 2 in loops here. And you could probably still call routines in libs written in some other language.

  • Steve_The_Cynic (nodebb)

    All of you talking about NULL pointers being pointers to address 0, or address 0 normally being some sort of signal value are wrong.

    C/C++ NULL pointers are, indeed, pointers to nowhere. The typographical convention of 0 in a pointer context to mean a NULL pointer is just that: a typographical convention defined by the language. Code that uses memset or bzero to nuke the contents of a pointer-containing structure will get a surprise if it is run on an AS/400 (now called iSystem), where a NULL pointer is NOT the all-zeroes bit pattern.

    On x86's 16-bit tiny, small, and medium (large code, small data) memory models, a NULL pointer (a) does not point to linear address zero, and (b) points to accessible memory.

    Conclusion: a NULL pointer must be treated as a pointer to nowhere, and you should not, in general, treat the 0 as anything but a typographical convention. The consequences of dereferencing one (for read OR for write) are undefined. The standards don't guarantee a crash, nor any specific behaviour.

  • Ulysses (unregistered)

    And I'll throw a wrench into the mix: pointer-to-member, which amounts to an offset. In my MSVC, NULL/nullptr yields -1 and &Foo::firstMember yields 0.

  • Steve_The_Cynic (nodebb) in reply to Ulysses

    Sort of. Like anything exotic in C++, there are corner cases that make life really hard.

    Pointer-to-member-function is ... complicated. Getting them to behave sanely in the face of virtual member functions and in-class definitions of functions is really hard without extra information, but it is made significantly easier if you can force the compiler and linker to work together to restrict in-class definitions to a single block of code in the compiled and linked program.

    Pointer-to-member-variable is made difficult when you have a virtual base class, because your object might not be contiguous, and the gap is not guaranteed to be fixed in size.

    Consider an ultimate base class B; three derived classes D1, D2, and D3, which all derive from B using virtual inheritance; and some ultimately-derived classes, D12 derived from public D1, public D2; D21 derived from public D2, public D1; D31 derived from public D3, public D1; and the full set of six variants derived from all three of D1, D2, and D3.

    Now consider that B contains a protected-inheritance int member called b, and D1, D2, and D3 each contain an int member d1, d2, and d3, as appropriate. It must be possible that a member function of D2 can form a member pointer to D2::d2 (int D2::*p = &D2::d2;), and that pointer must compare equal to a member pointer to a different D2 instance's D2::d2, no matter which ultimately-derived class the D2s are a base class of. It must also be possible to form a member pointer to D2::b and have it obey the same restriction. This is hard, and requires a lot of supplementary information.

  • Patrick (unregistered) in reply to Steve_The_Cynic

    As to NULL pointers and x86 16-bit realmode, at least with Microsoft's compiler the (near model, i.e. no segment, only offset, so can only address 64KB of memory) NULL pointer actually is 0. What it does is have the start of each segment contain some magic bytes and check that those are unchanged when the function returns so it can actually crash the program on NULL derefs like expected. In realmode, there is no memory protection and literally any combination of 16 bit segment:offset is a valid address, so I suppose NULL being 0 is as good a choice as anything for near pointers. For far pointers, 0:0 is a pretty bad choice for NULL however, since that's the location of the realmode interrupt vector table. Writing anything there is basically guaranteed to crash the system. I know that Win95 actually did some things to prevent DOS boxes from writing there to avoid NULL derefs in DOS applications whose compilers actually used 0:0 for far NULL from bringing down the entire system (they are allowed to scribble on most other memory below 1MB).

  • Jeff W. (unregistered)

    At my last gig, there was a similar construct, without the baggage, that they called a "Troolean" -- the tri-state boolean, with null being the third state. Might as well have called it Schroedinger's Boolean....

  • Steve_The_Cynic (nodebb) in reply to Patrick

    It might be zero in the 16-bit pointer variable, but it doesn't point to linear address 0. It points to DS:0x0000 which is ... somewhere ... in linear space, but almost certainly not at 0. (Heck, the real-mode interrupt table is there...)

    And Microsoft C for DOS merely printed a message on exit if the magic bytes were corrupted. "Null pointer assignment", if memory serves. There was no crash because you mustn't expect a crash when dereferencing NULL. You must, instead, expect that demons will rip open your face as they try to fly out of your nose. Dereferencing NULL, whether for read or for write, is UB, and therefore anything can happen. Too bad for the good citizens of Denver if you run it on a DeathStation 9000.

    And yes, 0:0 is a perfectly reasonable value for far NULL, and, indeed, in protected mode it is the only value that makes sense. Well, 0:something, anyway, since the offset doesn't matter if the selector is zero. You might argue that 0:0x8000 would be better, to guarantee breaking code that uses memset / bzero to "clear" structures.

  • LazyCubicleMonkey (unregistered)

    Why are there break; statements after return statements? How does that make sense?

Leave a comment on “ByteBool”

Log In or post as a guest

Replying to comment #:

« Return to Article