Showing posts with label char. Show all posts
Showing posts with label char. Show all posts

Monday, 23 October 2023

Job Interview : switch(char) again! Twenty years on!

I've spoken about some of the strange interviews I've enjoyed over the years; notable engineering highlights were having test driven development spooned to me, when I simply didn't know the particular syntax they were demanding, or having StringBuilder suggested for a C# task where they actually needed to cross-core thread their problem, or pointing out that the CI solution being described would lead to an alien environment of folks being paralysed by fear of red flags; only to witness their development floor being paralysed by exactly those issues as I walked out the door.

Today however, I'm going to go way back and talk about one of the very early development interviews I had; this maybe like the third interview I ever had after graduating, it was with a rail rolling stock company, in a very bright and sunny room with three guys who seemed to know their entire universe was correct and they'd take no new information into their sphere of understanding.

I share this one as a friend of mine was in touch over the weekend, he had an interview, and strangely he had the exact same conversation I had... THE EXACT CONVERSATION, twenty something years later.

Let us start by sharing some perfectly valid C++ code:

bool validate(const char& value)
{
switch (value)
{
case 0: return true;
case 'x': return true;
default: return false;
}
return false;
}
int main()
{
const bool isValidOne{ validate('a') };
const bool isValidTwo{ validate('x') };
const bool isValidMe{ validate(12) };
}

Read this code, we should see an output (if we output the bools) of "false", "true" and "false"... I think we can all agree.  This is perfectly valid C++.

It isn't very clean nor pretty, we're relying on the compiler standard decaying char to int and vice versa; which is not very nice and I wish compilers would complain here, that we're comparing int to char in the first case and we're converting the integer 12 to char, I think it should really strong type this.

But that is not the point, the point is that both in my friends case and mine all those years ago the interviewers got really uppity about that "switch" statement.  They insisted that you can not "switch" on a character type...

Just flat insisted.

I remember in my experience they had me write up what they wanted on a blackboard, with chalk, and they wanted me to go through the code line by line; I wrote more or less the above, they insisted they had a character not a byte (uint8_t: though there was no standard for this at the time) and then they went off on this tangent amongst themselves about the value of the if-elseif-else stanza's they insisted would work over my solution above.

Now I was talking to these guys in the early 00's, my friend however was talking to them in 2023.  He jumped on this with the point of "well if the character is known at compile time, yes then constexpr maybe of use" and he showed them:

if constexpr(foo) and if consteval(bar) examples.

He described their faces screwing up and two of the chaps he was talking to staring at each other before making subtle notes on their paper.

It was very clear at this point that the CTO performing the interview was not keeping his knowledge up to date, the group seemed to cluster onto the idea of just maintaining what they have, stagnation like this in our joint experience can be problematic.  Both team morale and high turn over of engineers always happens when things stagnate.

I have to say in my interview I actually sat it out from beginning to end and just knew I was not interested in the role; and I did not hear from them again.

My friend however, he was genuinely concerned he'd done a good interview and they'd be offering him a role, they kept him talking for over an hour and a half!

He's a late 40's engineer of 25+ years experience, just like me; the three chaps interviewing him, including the CTO, were ten or more years his junior, it seemed they were looking to back up their team with an older head to lend legitimacy to things; and they had lost two original engineers of their project to literal retirement without replacing them.

He saw the issues and he thanked them for his time and left, with a negative to whether he would be interested in going further.  This stunned them.

It has to be said, so many interviewers forget that though they are interviewing you, you are also interviewing them like most all human interaction it is a two way street and it's crucially important to remember that in a job interview.  We spent a significant amount of our time at work, if you are not comfortable there or feel you are going to be acting out a role instead of filling one and making it your own.

Saturday, 12 March 2022

Using Const Char* in Template

Compile Time Template Strings.... Yeah, these are a thing and I'm going to show you a live example of how to do them.  First lets take a moment to just understand what we want in some C++ pseudo code.

template<typename T>
T Square(const T value)
{
   return value * value;
}

const auto result = Square<int>(2);

const auto result = Square<double>(2.42);

In a template like this we can see this requires a number and more advanced writers might use SFINAE and type traits to ensure that the type is an arithmetic type, this would stop us doing something like...

const auto result = Square<"Hello">(2);

In this case we can not even compile, not because "Hello" is not operable with the multiplication, but that it's not that, the issue is that a const char* isn't allowed in the template itself.  You can't define a typename as const char*... Or can you?

Well, it seems you can in C++20.  The idea I had was to accept the template but treat it like a decaying length, copying the buffer in the template each step.  How could I do this?  Well, I need to compare the template somehow and determine the length of "Hello"... The buffer containing the data "Hello\0" itself is there in the code, what I needed was to think about how to treat that as type 6, the length...

The spaceship operator is what sprang to mind, but then I had the issue that the comparison result type wasn't known.... At least I don't know it, I don't know what string literal maybe being passed in, how to know it?  Well I didn't need to, I just return auto!

Here is the key code....  

  template<std::size_t Length>
  struct TemplateString
  {
    // Constructor is constexpr and simply copies the payload text
    // into the member data setup
    constexpr TemplateString(const char(&pPayloadText)[Length + 1])
    {
      std::copy_n(pPayloadText, Length+1, mText);
    }
    
    auto operator<=>(const TemplateString&) const = default;
    
    // Default is just an empty buffer of the Length+1
    char mText[Length+1] = {};
  };
  
  // Make decaying the template Length possible
  template<std::size_t Length>
  TemplateString(const char(&str)[Length])->TemplateString<Length-1>;


The template string is simply copying the buffer given locally, and the unwinding is stopped when the template length is met in the comparator.  I think this is a little strange, I may even be wrong (probably am) in explaining how this unrolling works.

However, what use do I have for this?

Well, my main use is in parameterising on the template the NAME of a thing... I have long seen code where the onus is on the engineer to put some static constant string into their derived class to allow some other feature to know what your class is called, or what it does.

Systems, Events, Services... These sort of things, general things that need a name for us mere humans all introduce this pattern of:

Base Class --> Derived Class :: sName

Where this sName is brittle, it can be forgotten, it can be mangled, it can be copy I paste... All sorts of issues with it.  I personally have my statemachine code up on github and I use an event within that, which could sorely use this very string trick... so I will be using it.

Lets take a look at the code in action on CompilerExplorer here.

And you can get hold of my personal example on github here.

As ever, if you liked this, subscribe on YouTube to let me know, comment below and if you use this trick feel free to buy me a coffee with the tip jar up top of this page.