- Feature Articles
- CodeSOD
-
Error'd
- Most Recent Articles
- Scrollpocalypse
- Fast Quick
- 12345
- Said Different
- Ai Dios Mio
- Unrewarding
- Good Time
- Hello, New Mexico!
-
Forums
-
Other Articles
- Random Article
- Other Series
- Alex's Soapbox
- Announcements
- Best of…
- Best of Email
- Best of the Sidebar
- Bring Your Own Code
- Coded Smorgasbord
- Mandatory Fun Day
- Off Topic
- Representative Line
- News Roundup
- Editor's Soapbox
- Software on the Rocks
- Souvenir Potpourri
- Sponsor Post
- Tales from the Interview
- The Daily WTF: Live
- Virtudyne
Admin
You do not need to check the documentation, you just need to know that Guid is a struct
The default constructor on a struct will always create a zero initialised struct.
Admin
That's what they get for thinking of UUIDs as strings. They are and always have been 128 bit numbers that are rendered as dashed hex strings because they're shorter and because human brains malfunction in the presence of anything with more than 3 digits, which incidentallly is why we had to invent thousands separators.
Admin
So sayeth AGlezB in the year 2026.
Admin
And the solution was to replace it with "0000"?
Admin
Let me guess, the fix was adding a 4th "0" to the string (maybe a 5th if they were feeling particularly virtuous), to make an accidental hit "virtually impossible" :D
[Confession: I know essentially nothing about how GUIDs/UUIDs are actually generated - I've never needed to - but even I thought, on seeing that code, "what's special about 3 0's? Surely that could easily come up in practice?".]
Admin
Someone's going to mention an ethernet card MAC address and we've gone down a stupid rabbit hole.
Admin
I'm not sure how Nikolai measured it. I'm getting a mean of 0.464% with a standard deviation of 0.002% or so with my approach, which means it's 0.464 % +/- 0.0052 % to form the 99% confidence interval.
A calculation using a Markov Chain/Dynamic Programming gives something around 0.46456%.
When the UUID's are rendered with uuid.uuid4(), they are rendered as: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, where the 4 is static and the y can only be one of {8, 9, a, b}. The 'x's are 0 with 1/16 probability and obviously the dashes interrupt a test for '000'.
Admin
Even if the test for three zeroes is correct (it isn't), it's wrong anyway, unless the caller is careful to "toString()" the Guid using the "N" format (just a string of digits). The default is "D", "8 digits hyphen four digits hyphen four digits hyphen four digits hyphen twelve digits", and the other formats are even worse. If the three zeroes cross a hyphen ("...00-0..."), they won't be detected.
In the end, all that's necessary is to compare the Guid to
Guid.Emptyornew Guid().Admin
An ex-colleague of mine forced me down the MAC address hole. Fortunately I had reviewed the RFCs before going into that discussion
Admin
I've seen 'homebrew' implementations of globally unique identifiers such as "CRC32", "start at 0 and increment a counter" in the kind of industries where there's major property damage or death when things go bad.
In one case when I pointed out there's nothing globally unique about the 'incremeting counter' approach I was told. "Yeah, but it gets people used to thinking in terms of the idea of GUIDs, which we'll implement in the future".
Another case where the CRC32 of a blob of data was being used as the primary key to a database. The database was being updated with new values a few thousand times per minute (it was really an overengineered logging aggregator for devices all over the country). They couldn't figure out why a couple times a month there was an insertion failure. Had to explain the birthday paradox to them. Worse yet they weren't actually querying the database by the key. They were selecting on some other field entirely. I was never able to get an answer as to why they did what they did. I suspect it was some misguided de-duplication logic.
Admin
CI/CD failing because of a deterministic check is one thing - at least there's a definite cause. It's the oddball failure that has no reasonable explanation that is most maddening.
One was at another company - the build will occasionally fail, and the only solution was "re-run the build". The reason was completely random - usually for some reason the server (local on site mirror) was unavailable. Other times it was completely unknown. Just the build fails for a random reason and it isn't reproducible. We did eliminate the issue of random numbers because the build was made binary-reproducible so every time you built the same source code, even on different machines, you got an image that was exactly the same as it was when the code was released months or years ago.
Admin
For bonus points, when you implement the crc32 algorithm, the table-lookup form, realise that one of the entries is 32 bits of zeroes and replace it with a value copied from another table position because it can't be good to have an entry with all zero bits.
This actually happened, in a commercial product most people would recognise if I mentioned the name here.
Admin
The Guid.Empty constant which is the default used for uninitialized UID in .NET languages has 0 in all of its numeric spaces. So as a string it comes out as something like: 00000000-0000-0000-0000-000000000000. Someone "clever" thought that if you just picked up any length of 0 that'd do for a check. And they forgot that 00000000-0000-4000-8000-000000000001 is still a valid UID that absolutely can happen.
Admin
In addition to the already well-covered dumbness of how they performed their empty check ...
I wonder if that
Assert()is needed at all? What part of the CI/CD process generates a GUID, but leaves it empty on failure?I'd sooner expect that whatever object contains the GUID would be null. Or there'd be a FILE_NOT_FOUND. Or a non-zero or negative return code. Or something else similar. What there would (probably) not be is a nice shiny fresh GUID whose non-zero value meant success and whose zero value meant failure.
Admin
That can actually happen in .net. Basically GUID is a non nullable type by default. That means that if you just define a GUID variable but newer initialize it to something it ends up initialized to GUID.Empty.
And there are plenty of situations where the GUID variable might just newer get a different value. The first thing that comes to mind is if it was reading data from some external source which treats the UID as optional. Or if you had objects created in one place and initialized in another and you wanted to make sure everyone was using the proper process. Etc.
Admin
Since it's an
Assert(), presumably in "correct" operation (tests all pass) it doesn't fail. Except for the bogus false-positive assertion condition, that is.Admin
Since it's an
Assert(), presumably in "correct" operation (tests all pass) it doesn't fail. Except for the bogus false-positive assertion condition, that is.Admin
I would do it by replacing the assert with a simple counter increment and running the test many times in a tight loop. The final answer is probably dependent on many variables like the algorithm used - it isn't necessarily variant 1 version 4. Also there may be flaws in the RNG that skew the results.
Admin
Try saying the year. Did it came out as
twenty twenty sixinstead oftwo thousand twenty six? Now read this number:1600. Odds are you're going to read that assixteen hundredinstead ofone thousand six hundred. I'm kidding, obviously. The shortening has nothing to do with the numbers. Also other languages have names that are already shorter, i.e. Spanishdos mil veintiseis.Regardless the fact is our brains are not good with numbers. Ask the average adult on the street to add two random 3 digit numbers in their mind and watch them break for a while. Heck, ask the average college student and watch them do the same.
Admin
If you stopped me in the street, and asked me to add two, random, three-digit numbers in my mind, it would take me time, and the answer might be wrong; I'm not good at that sort of math.
But there are other ways of doing math (which don't involve using fingers, toes, etc.), ways which use other parts of one's brain.
At work, I cut pieces of wood with power saws. My instructions come from sheets of paper -- essentially, "parts lists" -- covered with numbers.
A project might call for, among other things, twelve 4x4s, each 27¼ inches long. I stack these in a pattern, say, 3 across and 4 high. I don't keep a tally in my head. I'll glance at the stack, do "visual math", and the pattern-recognition part of my brain will tell me I need to cut seven more to make up the full twelve.
Sometimes I need to go to the lumber storage area, put "some" boards on a cart, wheel it to my area, and then cut them. How many boards will I need?
If a project calls for 30 2x6 boards, each 37 inches long, I do the math this way. I know the 2x6 boards we have are 16 feet (aka 192 inches) long. I'll think, "thirty-seven, seventy-four, one hundred-forty-eight, another seventy-four, no, that's too long, another thirty-seven, yeah, that works, so five cut boards from each raw board, so I need six 2x6s."