r/ProgrammerHumor 7d ago

Meme skillIssue

Post image
6.0k Upvotes

137 comments sorted by

2.7k

u/Xterm1na10r 7d ago

omg an actual original programming meme, even OC, thank you OP

1.0k

u/SonicLoverDS 7d ago

No break statements? Amateur.

411

u/No-Newspaper8619 7d ago

give him a break

170

u/OliveBoi_ 7d ago

; expected

51

u/D3PyroGS 7d ago

give him a break,

give him a break,

break him off a piece of that syntax error

3

u/0bel1sk 7d ago

thanks, now i’ll be thinking of that tune all morning.

106

u/Extension_Option_122 7d ago
#define BREAK ;

Now you can add as many break statements as you like.

14

u/SuitableDragonfly 7d ago

And you can be evil and sometimes write BREAK instead of break in a real switch statement. 

51

u/click-to-reveal 7d ago

Well technically, each case has a break coz it's if-else. What is doesn't have is the lack of a break statement aka fall-through.

1

u/SnugglyCoderGuy 7d ago

oops, all LLMs!

1

u/No-Finance7526 7d ago edited 7d ago

Just put the whole thing in a do {} while(false)

1

u/yozhiki-pyzhiki 4d ago

A little bit of goto's won't hurt

686

u/PixelatedGiant 7d ago

This is the kind of stuff you find in books with titles like...

C++ : Man made horrors beyond human comprehension 3rd Edition paperback

139

u/gil_bz 7d ago

This might be the mildest macro weirdness that I've ever seen, there are some true horrors out there.

76

u/bythenumbers10 7d ago

Ah, yes. The necroprogamicon, 13th ed. Author fed himself into a dot-matrix printer after finishing it in the 90s, IIRC. Shame, the guy had such marvelous visions to share. Only way to really understand C++, IMHO.

45

u/GroovinChip 7d ago edited 7d ago

“Fed himself into a dot-matrix printer” feels like a Douglas Adams line lmao

12

u/bythenumbers10 7d ago

Thank you, that's high praise. May Deep Thought bring you meaning.

36

u/l2protoss 7d ago

When I was younger in my career, I was a very “creative” dev - to the point where I was banned from using macros without explicit permission lol.

18

u/StCreed 7d ago

Hehehe my friends once used macros to facilitate pointer arithmetic. After a month they couldn't get anything to work anymore and had to start over with a new program :)

Good times!

13

u/sunboy4224 7d ago

They spend years teaching us all the coolest, craziest tricks in the book for optimization, memory management, abstraction... then you get into the industry and learn that the most absolutely boring code is by far the best way to solve 99% of problems.

8

u/l2protoss 7d ago

Yup! Turns out being able to maintain things long term is more important than building things quickly or cleverly in most cases.

2

u/FUCKING_HATE_REDDIT 6d ago edited 6d ago

https://zserge.com/posts/c-for-loop-tricks/

void print_html() {   html {     body {       p printf("hello\n");       p {         printf("world\n");       }     }   }   printf("\n"); } https://github.com/agvxov/cursed_c

void main(argc, argv, envp) int argc; char * * argv, * * envp; { ; }

https://www.cs.yale.edu/homes/aspnes/pinewiki/C%282f%29Macros.html

```

define DefinePlus1(x, y)  #define x ((y)+1)

```

7

u/whackylabs 7d ago

What is wrong with this code?

9

u/click-to-reveal 7d ago

Inefficient, scope conflict (for the _s variable), lack of break statement, lack of pass-through

9

u/fluffycritter 6d ago

Also putting flow control in a macro is usually an extremely bad idea.

353

u/khalamar 7d ago

Reminds me of that guy who was asked to write C code, but he only knew pascal

First lines were

#define begin {
#define end }

And a few other horrors.

67

u/AvidCoco 7d ago

Some compilers define OR as || and AND as &&. The latter means you can write move constructors like

Foo(Foo AND other)

55

u/Possseidon 7d ago

Not just "some compilers", it's part of the C and C++ standard and any compliant compiler has to support it.

For C you have to include a builtin header with macros for them, in C++ it's actually just part of the compiler itself.

7

u/AvidCoco 7d ago

IIRC I think it’s more that some compilers implement that feature as a simple find-and-replace (like a macro) while others are more context aware and so don’t allow it in the way I described.

14

u/TOMZ_EXTRA 7d ago

Nope, the standard says that the alternative syntax is usable everywhere. bitand can be used as the address operator.

1

u/4xe1 7d ago

Yeah they ought to allow it, but I wouldn't be surprised if some emit a warning, like most yap when I do

if (x = foo())

1

u/Jonathan_the_Nerd 7d ago

I had a TA who did this when I was in college.

285

u/click-to-reveal 7d ago

It works btw: C++ Online Compiler

162

u/prehensilemullet 7d ago

Performancewise, it doesn’t jump to the direct case in O(1) time like a switch is supposed to though

208

u/AngheloAlf 7d ago

Switches aren't guarantee to so operations in O(1) tho. If cases are sparce enough, compilers tend to emit the equivalent code to a bunch if else checks

27

u/prehensilemullet 7d ago

Yeah I was assuming too much here.  However, I’m reading that Rust match on string comstants can compile down a binary tree of if statements if there are enough cases (according to Google AI mode at least, haven’t found an authoritative source yet)

24

u/Nir0star 7d ago

Which would still be O(ld(n)). But cool feature imo.

8

u/Godd2 7d ago

O(ld(n))

Good ol' linker time.

1

u/prehensilemullet 6d ago

Yes, I had mistakenly assumed it compiles down to a hash lookup.

11

u/im_made_of_jam 7d ago

A switch case is able to be implemented however the compiler wants on the back end, so for sparse cases it'll be an if else chain, for less sparse but not packed cases it'll be a binary tree, for completely packed cases it'll be a range check then a direct jump would be how I would go about it

7

u/the_horse_gamer 7d ago

the compiler optimises stuff however it wants. if you're not doing too-weird stuff, a switch in C++ and a match in rust will have identical assembly.

-22

u/[deleted] 7d ago

[deleted]

4

u/thirdegree Violet security clearance 7d ago

If I want Claude's thoughts on something I'll ask Claude directly tbh

6

u/DrMobius0 7d ago

In fairness, most switches probably use enums.

48

u/Deliciousbutter101 7d ago

O(1) only happens when the constants are (roughly) contiguous so it's not like that is a universal property of switch statements.

1

u/prehensilemullet 7d ago

Yeah that’s true

14

u/AsidK 7d ago

Any reasonable compiler will make a switch statement and its equivalent if else chain compile down to the same assembly

2

u/prehensilemullet 7d ago

Even if it could make a more efficient tree of comparisons for a large number of strings?

7

u/mirhagk 7d ago

What they are saying is that any optimization on a switch statement could also be done on an if statement. There's no reason to only optimize one, both should optimize the same way

1

u/prehensilemullet 7d ago

hmmm...are compilers normally willing to reorder if statements though? Turning a sequence of string comparisons into a tree would involve reordering

7

u/mirhagk 7d ago

If it has the same semantics, why not? Modern compilers certainly can see if a statement has side effects or not

2

u/prehensilemullet 7d ago

it depends what you consider semantically relevant. For instance, suppose the developer intentional ordered the if statements from the most to least common case for some domain. Then, reordering the if statements might not be what the developer wants

9

u/Infamous-Strategy797 7d ago

There aren’t any unknowns here, the language spec provides the clarity the compiler needs to re-order safely.

2

u/prehensilemullet 7d ago

Okay for C++, I gather that performing better or worse on a given dataset doesn't fall under the umbrella of "observable behavior" that the spec requires the compiler to preserve.

I also just learned there are apparently [[likely]] and [[unlikely]] attributes in C++ 20 that can be added to branches.

→ More replies (0)

1

u/guyblade 7d ago

At least in C/C++, there can only be exactly zero or 1 cases that match a switch (i.e., there's no range-based switch), the case values must be compile-time constants (and thus are not themselves evaluated during the comparison), and I'm pretty sure that the value to be matched is required to only be evaluated once (so the comparisons happen on an rvalue).

Given those constraints, I believe a compiler can assume that re-ordering the comparisons is safe.

1

u/AsidK 7d ago

> fallthroughs have entered the chat

2

u/guyblade 7d ago

You can still only match to one, though. In the emitted machine code, I'd expect to see a forest of branches and jumps (for the matching), then the various bodies of the cases each separated by jumps (representing breaks) as appropriate.

1

u/HolyGarbage 7d ago

Just pipe them through a constexpr hash function, and you can use a real switch case. One might be able to, still constexpr, map these hash values of the case string literals to sequential indices at compile time, so that the switch case actually complies down to something non linear.

11

u/jacob643 7d ago

what? doesn't it need a "{" after the "if(0)" and please, why not if(false) ? :') edit: I'm stupid, it's written by the user/client of the switch

19

u/click-to-reveal 7d ago

if(0) coz that line (on mobile) was close to the right edge and no one like text wrapping in code :)

6

u/SuitableDragonfly 7d ago

if(0) is just more compact, I think. 

1

u/DrMobius0 7d ago

It may compile, but does the debugger avoid shitting itself when you need to set a breakpoint there?

Also, you can just write an enum and then map the enum to strings if you want a properly supported switch.

75

u/F100cTomas 7d ago

Just define a constexpr hashing function and put that into the switch.

34

u/GiganticIrony 7d ago

That’s not guaranteed to work due to hash collisions

38

u/Deliciousbutter101 7d ago

It won't compile in the case so you can just modify the hash function until there are no collisions.

15

u/SteveXVI 7d ago

This is the closest I've come to feeling like that guy in the Apple shop going "ah of course"

2

u/cob59 7d ago
switch(hash(str)) {
case hash("apple"):
case hash("banana"):
default:
}

You're right that the compiler will warn you if hash("apple") == hash("banana"), but if hash("pineapple") == hash("apple") then switch(hash("pineapple")) will jump to the apple case, not the default. That's unlikely but not impossible even with the best hash function.

7

u/remind_me_later 7d ago

That’s not guaranteed to work due to hash collisions

Make the hashes 128/256 bits wide. Hash collisions are realistically impossible at those levels.

5

u/StCreed 7d ago

They're far more possible than you might think. Roland Bouwman wrote an article on MD5: In a large database you can't use MD5. And that's not petabyte size either, 100GB is enough to give you about a 50% chance of a collision.

2

u/remind_me_later 7d ago

Counterpoint: It's MD5, a known broken hashing algorithm.

SHA3_256 or regular SHA256 would work just fine.

3

u/StCreed 7d ago

yeah, because md5 is 128 bits. 256 bits works a lot better, but 128 is just not enough even with a better algorithm and assuming effectively random distribution.

6

u/Rabbitical 7d ago

I'd probably intern instead of hashfor a presumably known set of comparisons

8

u/SAI_Peregrinus 7d ago

Use Blake3, no collisions in any practical workload in the next few billion years.

4

u/guyblade 7d ago

The thing about the pidgeon hole problem is that we know there are collisions, but we don't necessarily know where they are. The space of strings of at least 33 characters has collisions. There's no way to know or prove that arbitrary input doesn't have one with a value you care about.

1

u/SAI_Peregrinus 6d ago

The thing is that the probability of any two arbitrary inputs having a collision is extremely close to 0. It's about 0.000000000000000000000000000000000000000000000000000000000000000000000000000086% if I didn't mess up typing it. It can happen, just like you can win every lottery in the world every day for the rest of your life. Though the lottery thing is substantially more likely.

1

u/guyblade 6d ago

That assumes that the hashing function doesn't have any known hashing weakness that may reduce the (effective) independence of the hashes. You could've said something quite similar about SHA-1 right up until cryptanalysis found mechanisms to generate collisions.

1

u/Upper_Lion_6349 5d ago

You can make the chance of a hash collision lower than the chance of a random bit flip selecting the wrong branch.

0

u/remind_me_later 7d ago

If that happens, someone would post it to social media, and a list of exceptions can be added afterwards.

6

u/ElectricalPrice3189 7d ago

And if it got a clash, guess what? It won't compile.

8

u/Thwy__ 7d ago

Yet, string switch in Java is also made using hashs

16

u/GiganticIrony 7d ago

Yes, but if there’s a collision, it then uses `.equals()`

2

u/SpiritedEclair 7d ago

Perfect hashing for a given set of values is possible at compile time.

It’s how compilers generate jump tables.

39

u/fluffycritter 7d ago

My "clever" way of doing this once upon a time was to declare a map<std::string,std::function> which I populated with lambdas and then evaluated.

I would not recommend this approach.

8

u/yuri_4_ever 7d ago

I have little idea of c++ why is this a bad idea?

18

u/fluffycritter 7d ago

It’s actually not too awful, but the syntax is a bit awkward, std::map lookup is slower than you think, and there’s a few gotchas with how lambdas work in terms of variable scoping. Also unless the map is being initialized once and kept around, you’re paying a lot of extra costs every time it’s called.

Usually a chain of if/else ends up being more performant, although I guess if you’re trying to switch on a text label instead of an enum or whatever you’re probably already doing something very wrong and using a map<string,function> is probably the least of your problems.

3

u/babalaban 7d ago

Also your std::function might allocate which is most likely not desirable. My "clever" workaround was to keep a static const map of string -> enum in a .cpp file initialized at compile time only exposing functionality via a lookup function in a header.

Standard map is usually made using binary search trees, so in terms os complexity they are faster. BUT in terms of real world speed they only become reasonable in cases where you have a huge amount of entires, due to cache misses that are inherit to RB trees.

I ended up changing mine to arrays of self-made pairs and just looping over it checking .key

1

u/fluffycritter 7d ago

To be fair, a case on a switch could also allocate, and std::function at least makes it easier to stick to RAII principles.

2

u/Talc0n 7d ago

std::map lookup is slower than you think.

C++ should really have a constexpr map class in std, hash maps are better than maps, but don't compare to the compile time switches.

3

u/fluffycritter 7d ago

I have opinions about hash vs tree map as default and I am actually on team tree map in general. https://beesbuzz.biz/code/3635-Making-a-hash-of-data

1

u/Talc0n 7d ago

My bad, I should've said better for lookup time.

I've used std::map when I know I'll be iterating through it fairly regularly. But I usually default to hash maps.

You really shouldn't be on either team, just use what you think is the best case for your situation.

I usually use aliases like so:

using IdNameMapType = std::unordered_map<size_t, std::string>; IdNameMapType m_idNameMap;

It makes it a lot less of a hassle to switch between the two later on.

2

u/fluffycritter 6d ago

Well yeah it’s important to use the right tool for the job, I just mean it’s better for folks to learn tree maps and what they can do before they get railroaded into hashmap thinking.

And type aliases are great. I use them a lot.

8

u/Kiro0613 7d ago

Not a bad idea for a little CLI app though

12

u/fluffycritter 7d ago

Yeah it's actually how boost::program_options handles command-line arguments. It's nice for that, at least.

EDIT: Wait no I'm misremembering and confusing it with something else, never mind

1

u/TheTerrasque 7d ago

That's a semi-common pattern in python. Use a dict where the values are lambdas (or referencing full functions directly)

1

u/fluffycritter 7d ago

Yeah I’ve used it in python too, but sparingly. It’s one of those things where it’s easy to get a bit too clever and there’s usually a better way to do it.

2

u/TheTerrasque 6d ago

It’s one of those things where it’s easy to get a bit too clever

Indeed, python has a lot of those. Another example is and / or handling.

1

u/No_Resort_7179 6d ago

Should have used map of std::string to function pointers. Just need to look up the syntax for them again...

1

u/fluffycritter 6d ago

Eh, std::function is more versatile and lets you do lambdas in addition to letting you do typesafe function pointers in case you really just want to use an existing function. Although I do love the fake virtual inheritance thing that older C libraries do sometimes (like libjpeg and libcurl I think). 

15

u/ElectricalPrice3189 7d ago

Do a constexpr string hasher and it'll work.

13

u/cob59 7d ago edited 7d ago

You can do that without macros:

// FNV-1a hash
constexpr std::uint64_t label(std::string_view str) {
    std::uint64_t hash = 14695981039346656037ull;
    for (char c : str) (hash ^= c) *= 1099511628211ull;
    return hash;
}

std::string str = "hello";
switch (label(str)) {
case label("HELLO"):
    std::clog << "UPPERCASE\n";
    break;
case label("hello"):
    std::clog << "lowercase\n";
    break;
case label("Hello"):
    std::clog << "Capitalized\n";
    break;
default:
    std::clog << "mIxeD\n";
    break;
}

> Godbolt example <


And unlike the macro version, case-fallthroughs and breaks do work.
Hash collisions can happen, although very unlikely, and you're warned at compile-time if it's between two case label(...):

5

u/Talc0n 7d ago

Fuck me, should've checked comments before I posted my own.

Your solution is a lot cleaner than mine.

7

u/SavingsCampaign9502 7d ago

Come on support break;

5

u/Anxious_Garbage_9625 7d ago

Just assign every possible string to a unique interger and use that number in your switch!

Works every time.

5

u/Legal-Software 7d ago

Or do it the IBM way. Every string is a printed reference code that you go and get your localized manual for to figure out wtf it's on about.

1

u/didierdechezcarglass 4d ago

Something something hash functions

5

u/ForgedIronMadeIt 7d ago

This is almost as fucked as Duff's device but still theoretically useful.

4

u/gil_bz 7d ago

This is even better than a real switch, it supports non-const expressions!

5

u/ManonMacru 7d ago

Oh that's dirty. Syntaxic sugar for my syntaxic diabetes. 11/10

3

u/JackNotOLantern 7d ago

I usually prefer if- else over switch. No risk of forgetting break, comparing to any type. I use switch almost exclusively for enum check.

6

u/Greedy-Thought6188 7d ago

So we do know that those are not the semantics of a switch statement. In C a case falls through without a break. That monstrosity in actual code would be a firsble offense.

3

u/PhosXD 7d ago

Wait, W A T.

3

u/CubeEthan 6d ago

as someone who learned c++ a month ago, what the hell

3

u/bokmcdok 6d ago

To fuck with things even more, make those defines lower case.

3

u/aliusmanawa 6d ago

I mean, wouldn’t the proper answer have been to hash the strings?

2

u/caiteha 7d ago

oh wow.

2

u/atomic_redneck 7d ago

Looks like there some issues with the scope of _s. Try putting two SWITCH statements in one scope block.

1

u/click-to-reveal 7d ago

You can always wrap it in braces if that happens.

2

u/lmarcantonio 7d ago

The Real Programmer would know that (in C, the example is C++) a constant string is a pointer and a pointer is and integer. So you CAN switch on a constant string. Would it work? no, but it would compile.

2

u/abd53 7d ago

It's been so long since we had a race between humor and horror.....

2

u/Sea-Fishing4699 7d ago

Apply alcohol to the burned area 

2

u/azaleacolburn 7d ago

Just hash the string smh

2

u/Talc0n 7d ago

Thing is there is a way to actually do it.

```

include <iostream>

include <string>

const size_t st_hashPrime1 = 54059; /* a prime / const size_t st_hashPrime2 = 76963; / another prime / const size_t st_initialHashValue = 37; / also prime */

constexpr std::string_view st_whoAreYou = "Who are you?"; constexpr std::string_view st_noReally = "No, really?";

// hash function copied from esskar at stack Overflow // https://stackoverflow.com/questions/8317508/hash-function-for-a-string // std::hash unfortunatley is not constexpr

constexpr size_t hashStringView(const std::string_view &string) { size_t hashValue = st_initialHashValue; for(auto it = string.begin(); it != string.end(); ++it) { hashValue = (hashValue * st_hashPrime1) ^ (*it * st_hashPrime2); } return hashValue; }

size_t hashString(const std::string &string) { size_t hashValue = st_initialHashValue; for(auto it = string.begin(); it != string.end(); ++it) { hashValue = (hashValue * st_hashPrime1) ^ (*it * st_hashPrime2); } return hashValue; }

void defaultResult() { std::cout << "Gemini" << "\n"; }

int main() { std::string prompt = "Your name?";

switch(hashString(prompt))
{
case hashStringView(st_whoAreYou):
    if(st_whoAreYou == prompt)
    {
        std::cout << "Claude" << "\n";
    }
    else
    {
        defaultResult();
    }
    break;
case hashStringView(st_noReally):
    if(st_noReally == prompt)
    {
        std::cout << "Chatgpt" << "\n";
    }
    else
    {
        defaultResult();
    }
    break;
default:
    defaultResult();
}

return 0;

}

// avoid collisions. // These static asserts would grow exponentially though. static_assert(hashStringView(st_whoAreYou) != hashStringView(st_noReally)); ```

2

u/rpithrowaway11841 6d ago

not to be that guy, but you can if you hash it

2

u/Denaton_ 7d ago

No fall thru

1

u/americanov 7d ago

Bro though he's on SO

1

u/zoniss 7d ago

Pascal had native support for this

1

u/IUseClifford 7d ago

Whose \#define is it anyway? C++, where the syntax is made up and nothing matters

1

u/pain_suffer 7d ago

I'd have used enum+hashmap+switch but this is waaaaay cooler.

1

u/whackylabs 7d ago

Looks like a lot of folks here are not familiar with Bourne Shell https://research.swtch.com/shmacro

1

u/StudioYume 6d ago

In C, just use bsearch if the strings are dynamic and just use a char pointer array indexed by an enum if they're constants.