Dilbert





The Daily WTF

CodeSOD: Don't be so Negative Online;

It's fair to say that regardless of their many advantages, "systems languages", like C, are much harder to use than their more abstract cousins.Vendors know this, which is why they often find a way to integrate across language boundaries. You might write critical functions in C or C++, then invoke them in Python or from Swift or… Visual Basic 6.

And crossing those language boundaries can pose other challenges. For example, Python has a built-in boolean type. C, for quite a long time didn't. Which means a lot of C code has blocks like this:

#define BOOL int #define FALSE 0 #define TRUE 1 #define FILE_NOT_FOUND 2

Carl C provides that block, just for illustration purposes. Awhile back, he inherited a big pile of antique COM+ and the associated VB6 front end, along with a herd of "COM Wizards" and "Junior VB Programmers" to help maintain it.

The idea of the system was that all the "hard stuff" would be done in C++, while the UI would be a VB6 application. The C++ COM layer talked to some hardware which could be attached to the PC, and the VB6 layer let the user check the status and interact with the device.

Unfortunately, the Junior VB Programmers quickly encountered a problem: they could NEVER get the device online. Plugging, unplugging, rebooting, trying different ports, different computers, it never worked. But when the "COM wizards" tossed them a diagnostic program written in C++, things worked fine.

"Must be a problem in your VB code," was the obvious conclusion.

Dim oHardware as New HardwareServer ' Initialize Hardware oHardware.Initialize 0 If oHardware.ONLINE = True Then Set oActuator = oHardware.Actuator Else MsgBox "Hardware did not initialize correctly." End End If

Reading through that code, it's hard to see at a glance what could be wrong about it. Could the problem be in the COM layer?

interface IHardwareServer : IDispatch { [propget, id(1)] HRESULT Actuator([out, retval] IActuator* *pVal); [propget, id(2)] HRESULT ONLINE([out, retval] BOOL *pVal); [id(3)] HRESULT Initialize(short interfaceID); }; coclass HardwareServer { [default] interface IHardwareServer; };

While the COM approach to defining a property is a little awkward, nothing at a glance looks wrong here, either. ONLINE is a property that returns a BOOL.

But this is a C++ boolean. Defined so that true is one and false is zero.

Visual Basic, in addition to letting arrays start at 1 if you really wanted to, had another quirk. It was pretty loosey-goosey with types (defaulting to the handy Variant type, which is a fancy way of saying "basically no type at all"), and the internal implementation of its types could be surprising.

For example, in VB6, False was zero, much like you'd expect. And True was… -1. Yes, -1. Carl suggests this was to "kinda sorta mostly hide the distinction between bitwise and logical operations", which does sound like the sort of design choice Visual Basic would make. This is also TRWTF.

Now, it's easy to see how the Visual Basic code above is wrong: oHardware.ONLINE = True is testing to see if ONLINE is equal to -1, which is not true. A more correct way of writing the Visual Basic would be simply to test if oHardware.ONLINE then…. Visual Basic is okay with falsy/truthy statements, so whether ONLINE is 1 or -1, that would evaluate as true.

That doesn't let the COM programmers off the hook though. COM was designed to work across languages, and COM was designed with the understanding that different languages might have different internal representations of boolean values.

As Carl adds:

Of course if they were really COM wizards they would have used the VARIANT_BOOL type in the first place, and returned VARIANT_TRUE or VARIANT_FALSE.

[Advertisement] ProGet can centralize your organization's software applications and components to provide uniform access to developers and servers. Check it out!


Error'd: A Pattern of Errors;

"Who would have thought that a newspaper hired an ex-TV technician to test their new CMS with an actual test pattern!" wrote Yves.

 

"Guess I should throttle back on binging all of Netflix," writes Eric S.

 

Christian K. wrote, "So, does this let me listen directly to my network packets?"

 

"I feel this summarizes very well the current Covid-19 situation in the US," Henrik B. wrote.

 

Steve W. writes, "I don't know if I've been gardening wrong or computing wrong, but at least know I know how best to do it!"

 

"Oh, how silly of me to search a toy reseller's website for 'scrabble' when I really meant to search for 'scrabble'. It's so obvious now!"

 

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


CodeSOD: This is Your Last Birthday;

I have a philosophy on birthdays. The significant ones aren’t the numbers we usually choose- 18, 21, 40, whatever- it’s the ones where you need an extra bit. 2, 4, 8, and so on. By that standard, my next birthday landmark isn’t until 2044, and I’m a patient sort.

Christian inherited some legacy C# code which deals in birthdays. Specifically, it needs to be able to determine when your last birthday was. Now, you have to be a bit smarter than simply “lop off the year and insert this year,” since that could be a future birthday, but not that much smarter.

The basic algorithm most of us would choose, though, might start there. If their birthday is, say, 12/31/1969, then we could ask, is 12/31/2020 in the future? It is. Then their last birthday was on 12/31/2019. Whereas, for someone born on 1/1/1970, we know that 1/1/2020 is in the past, so their last birthday was 1/1/2020.

Christian’s predecessor didn’t want to do that. Instead, they found this… “elegant” approach:

static DateTime GetLastBirthday(DateTime dayOfBirth)
{
    var now = DateTime.Now;

    var former = dayOfBirth;
    var current = former.AddYears(1);

    while (current < DateTime.Now)
    {
        former = current;
        current = current.AddYears(1);
    }

    return former;
}

Start with their birthdate. Then add one to the year, and store that as current. While current is in the past, remember it as former, and then add one to current. When current is finally a date in the future, former must be a date in the past, and store their last birthday.

The kicker here, though, is that this isn’t used to calculate birthdays. It’s used to calculate the “Start of the Case Year”. Which operates like birthdays, or any anniversary for that matter.

var currentCaseYearStart = GetLastBirthday(caseStart);

Sure, that’s weird naming, but Christian has this to add:

Anyways, [for case year starts] it has a (sort of) off-by-one error.

Christian doesn’t expand on that, and I’m not entirely certain what the off-by-one-like behavior would be in that case, and I assume it has something to do with their business rules around case start dates.

Christian has simplified the date calculation, but has yet to rename it: it turns out this method is called in several places, but never to calculate a birthday.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!


CodeSOD: Is We Equal?;

Testing for equality is hard. Equal references are certainly equal, but are equal values? What does it mean for two objects to “equal” each other? It’s especially hard in a language like JavaScript, which is “friendly” about type conversions.

In JavaScript land, you’re likely to favor a tool like “lodash”, which provides utility functions like isEqual.

Mohsin was poking around an old corner of their codebase, which hadn’t been modified in some time. Waiting there was this “helpful” function.

import _ from 'lodash';

export function areEqual(prevProps, nextProps) {
  if (_.isEqual(prevProps, nextProps)) {
    return true;
  }
  return false;
}

In this case, our unknown developer is the best kind of correct: grammatically correct. isEqual should rightly be called areEqual, since we’re testing if two objects “are equal” to each other.

Does that justify implementing a whole new method? Does it justify implementing it with an awkward construct where we use an if to determine if we should return true or false, instead of just, y’know, returning true or false.

isEqual already returns a boolean value, so you don’t need that if: return _.isEqual(…) would be quite enough. Given that functions are data in JavaScript, we could even shorten that by export const areEqual = _.isEqual.

Or, we could just not do this at all.

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!


A Vintage Printer;

IBM 1130 (16758008839)

Remember Robert, the student who ruined his class curve back in the 1960s? Well, proving the old adage that the guy who graduates last from medical school is still a doctor, he managed to find another part-time job at a small hospital, earning just enough to pay his continued tuition.

Industry standard in those days was the IBM System/360 series, but it was out of the price range of this hospital. Instead, they had an IBM 1130, which was designed to be used in laboratories and small scientific research facilities. It used FORTRAN, which was pretty inappropriate for business use, but a set of subroutines offered by IBM contained routines for dealing with currency values and formatting. The hospital captured charges on punch cards and those were used as input to a billing program.

The printer was a monstrous beast, spinning a drum of characters and firing hammers to print characters as they went by. In order to print in specific boxes on the billing forms, it was necessary to advance the paper to a specific point on the page. This was done using a loop of paper tape that had 12 channels in its width. A hole was punched at the line in the tape where the printer needed to stop. Wire brushes above the tape would hit the hole, making contact with the metal drum inside the loop and stopping the paper feed.

There was one box in the billing form that was used infrequently, only every few days. When the program issued the code to skip to that channel, paper would begin spewing for a few seconds, and then the printer would shut down with a fault. This required stopping, removing the paper, typing the necessary data into the partially-printed bill, and then restarting the job from the point of failure.

IBM Field Engineering was called, but was unable to find a reason for the problem. Their considered opinion was that it was a software fault. After dealing with the problem on a fairly regular basis, things escalated. The IBM Systems Engineer assigned to the site was brought in.

Robert's boss, the author of the billing software, had relied on an IDEAL subroutine package provided by IBM—technically unsupported, but written by IBM employees, so generally one would assume it was safe to use. The Systems Engineer spent a while looking over that package, but eventually declared it innocent and moved on. He checked over the code Robert's boss had written, but ultimately that, too, failed to provide any answers.

"Then it must be the machine," Robert's boss stated.

This was the wrong thing to say. "It couldn't be the machine!" The Engineer, a prideful young woman, bristled at the insinuation. "These machines are checked. Everything's checked before it leaves the factory!"

Tempers flared, voices on the edge of shouting. Robert ducked back into the room with the computer, followed rapidly by the Field Engineer who had come along earlier in the day to do his own checks. Trying to pretend they couldn't hear the argument, the pair began another once-over on the machine, looking for any sign of mechanical fault.

"Hey, a question," said Robert, holding the thick cable that connected the printer to the computer. "Could it be a problem with the cable?"

The Field Engineer unplugged the cable and examined it. "The pin for that channel doesn't look seated," he admitted sheepishly. "Let's replace it and see what happens."

That day Robert learned two valuable lessons in debugging. Number one: when in doubt, go over each piece of the machine, no matter how unlikely. Number two: never tell an IBM Engineer that the problem is on their end.

[Advertisement] BuildMaster allows you to create a self-service release management platform that allows different teams to manage their applications. Explore how!


CodeSOD: Classic WTF: A Char'd Enum;
It's a holiday in the US today, so we're reaching back into the archives while doing some quarantine grilling. This classic has a… special approach to handling enums. Original. --Remy

Ah yes, the enum. It's a convenient way to give an integer a discrete domain of values, without having to worry about constants. But you see, therein lies the problem. What happens if you don't want to use an integer? Perhaps you'd like to use a string? Or a datetime? Or a char?

If that were the case, some might say just make a class that acts similarly, or then you clearly don't want an enum. But others, such as Dan Holmes' colleague, go a different route. They make sure they can fit chars into enums.

'******* Asc Constants ********
Private Const a = 65
Private Const b = 66
Private Const c = 67
Private Const d = 68
Private Const e = 69
Private Const f = 70
Private Const H = 72
Private Const i = 73
Private Const l = 76
Private Const m = 77
Private Const n = 78
Private Const O = 79
Private Const p = 80
Private Const r = 82
Private Const s = 83
Private Const t = 84
Private Const u = 85
Private Const x = 88

  ... snip ...

'******* Status Enums *********
Public Enum MessageStatus
  MsgError = e
  MsgInformation = i
  ProdMsg = p
  UpLoad = u
  Removed = x
End Enum

Public Enum PalletTable
  Shipped = s   'Pallet status code
  Available = a
End Enum
[Advertisement] Ensure your software is built only once and then deployed consistently across environments, by packaging your applications and components. Learn how today!


Error'd: Rest in &;$(%{>]$73!47;£*#’v\;

"Should you find yourself at a loss for words at the loss of a loved one, there are other 'words' you can try," Steve M. writes.

 

"Cool! I can still use the premium features for -3 days! Thanks, Mailjet!" writes Thomas.

 

David C. wrote, "In this time of virus outbreak, we all know you've been to the doctor so don't try and lie about it."

 

Gavin S. wrote, "I guess Tableau sets a low bar for its Technical Program Managers?"

 

"Ubutuntu: For when your Linux desktop isn't frilly enough!" Stuart L. wrote.

 

"Per Dropbox's rules, this prompt valid only for strings with a length of 5 that are greater than or equal to 6," Robert H. writes.

 

[Advertisement] ProGet supports your applications, Docker containers, and third-party packages, allowing you to enforce quality standards across all components. Download and see how!