Trip C++Now 2024 – think-cell
think-cell.com
think-cell.com
I got it, my friends got it, my work mates got it, everyone gets spammed periodically, it has become the laughingstock of job ads.
Why? Read the Glassdoor reviews. The CTO is a terrorist obsessed with complexity, they overengineered themselves into a corner by using every freaking C++ feature that ever existed, making sure that there's only 3 or 4 people in this world who can understand their code. Of course the usual pattern goes: guy learns #feature on-the-fly appearing both incredibly smart and embelishing his resume, until of course reality hits and the complexity of the crap he wrote outclasses his "genius" intellectual capacity so then he leaves, leaving the mess for future hires to deal with.
Consequently there's maybe 3 people left in this world capable to understand the atrocity that's running there, not saying fix it. So good luck finding them. These people, if they exist, already work for more that $130k.
Also, why do they need the absolute raging brinking edge of C++ features? What does this company do? Trillion dollar ultra low latency / high throughput high frequency trading? AAA+ games running on 4 x 4k monitors at 200+ fps?
No. They do some farty charts.
Again. Good luck with the recruitment! :)
As for why the latest version of c++? Personally I have found the dx improvements of some of them to be worth the upgrade. I really like constexpr and the build time errors it gives (opposed to runtime). The newer standards let you use constexpr in more places with more stl types.
Well, maybe also with some very limited template facilities.
Shoot... Did I just describe Ada95 somewhat?
But..but.. think-cell says that:
"Our CTO Arno maintains a close working relationship with all of our developers. Together, they review code, troubleshoot, and brainstorm. Most likely due to Arno's and Markus' academic roots, think-cell is flourishing without program managers and lengthy meetings."
Those are all the traits of a good manager and pleasant work environment. And you get to work in Berlin!
€130k for a good C++ dev is a steal in most markets, but I can see this 'perk' as a huge draw for people tired of shops where "bringing key stakeholders into conversations at the appropriate time" is valued over simply building product.
In most markets? Definitely not.
To reign you back to reality, in Europe not even FANGs pay that kind of salaries. They only pay that kind of cash to senior and staff-level engineers.
As a contractor, you have B2B contracts which means you have to pay taxes over your revenue. In general this amounts to a tax rate in a range of 20%-30%.
> This is a low rate for an experienced (...)
I repeat: in Europe, FANG salaries only start to come close to these values if you are principal/staff engineer. Your "experienced" weasel word contrasts with reality.
No shit Sherlock. You have to pay the taxes as a regular employee too. Go figure.
As a matter of fact, 130k with B2B contract actually earns you more net profit then the 130k of a regular employee contract.
> I repeat: in Europe, FANG salaries only start to come close to these values if you are principal/staff engineer.
Again, you're talking nonsense. Go check levels.fyi if you don't believe me.
From my personal experience be let assured that earning 130k in Europe is very much possible, and without being a staff/principal engineer, and without working for the FAANG. You need to be decently experienced and know how to make your shit done.
Yes, go figure that 130k in B2B contract is largely equivalent to 70-80k as a full-time employment.
Which is the whole point.
> As a matter of fact, 130k with B2B contract actually earns you more net profit then the 130k of a regular employee contract.
It really doesn't, unless you're doing dodgy taxes. Tax rates for salaried employees only surpass VAT and other taxes charged to self-employed professionals when you reached the highest income brackets.
Also, as a self-employed professional you are forced to pay your own contributions to social security, which for salaried employees are paid by the employers.
Do your math.
That nonsense stopped the very moment I onboarded clang-format, but the guy unexplainably refused to run the tool on personal PRs. Insane.
Usually even the least criticism on this 'holy' language [that emphasizes 'intent' and glorifies people who truly understand 'const correctness!' and the correct usage of dynamic_cast] gets immediately downvoted.
The sad truth being, tons of impossible to understand code bases exist in the wild, due to, for example, the mix of old, less old and new memory handling strategies having been applied.
Regarding love of complexity and C++, they’re sitting on the C++ committee. Complexity is their bread and butter. :)
I also kinda doubt “Trillion dollar ultra low latency / high throughput high frequency trading/AAA+ games running on 4 x 4k monitors at 200+ fps” people are such enthusiasts of the bleeding-edge of C++. The standard library and the style of programming popular in the committee isn’t very concerned with high performance it seems.
To me the think-cell guys sound like they are gung-ho on clout-chasing, to the point that this side of theirs even eclipses their own products and services.
It sounds they got the whole point of software engineering entirely backwards: their goal is to pile complex tech showcases in their product line and presentations as a proxy to being competent in their field,and instead they unwittingly put together unmaintainable and convoluted code that requires a high cognitive load just to troubleshoot the simplest issues.
Wow, I didn't know that, it explains a lot. There was a post on HN a while ago titled '“Modern” C++ Lamentations' (https://news.ycombinator.com/item?id=29898955). My eyes bleed when I see that "N Pythagorean triples" program in "C++". That's as close to classic C++ as Chinese is to Latin. And it's barely 10+ years since 2011. At this rate I don't even dare think what the "Modernest C++" of 2034 will look like, given the incentives the committee guys run on. If programming was done with pen and paper, I'd bet on making us stick a pen in our ass and write with that. Either way I'm expecting some equivalent proctology intervention needed to comply with the standard 10 years from now.
I was recently appointed co-chair for the std::ranges group and I'm trying to bring some of the improvements to C++.
We should blog more about the other stuff. For example, we've implemented a pretty cool lossless compression scheme for the preview of powerpoint slides in search, and have acquiried a cool technology to search for existing slides by drawing a sketch of their layout. But the people working on that are too busy to blog about them...
But the company itself is interesting.
They built an add-on for PowerPoint for which they charge more than MS charges for the entire Office Suite (my company pays around €130 per year and user).
With a million users served by approximately 20 devs they are very profitable, which they highlight in their job ads.
As a small company with a relatively boring product, they need to do something to attract new people. And they can afford to approach every c++ programmer individually, support community efforts (standards committee) and sending people to Aspen for a conference. They might be a little clumsy so their recruiting comes across as spam.
As for latest c++ features not being appropriate: as a user, I don’t care as long as the product works as intended, which it has been doing for me since over 10 years now.
I remember discussing this exact problem for boost range in the boost mailing list almost 20 years ago. My proposal was to make ranges be their own thing and generate the iterators on the fly when begin/end was requested, instead of always storing them internally. But I think it was not considered a big issue in practice.
Today we have sentinel end-iterators that can be stateless, so it should be possible to avoid blowout without fundamentally rethinking ranges.
Another paradox was that the exceptions were disabled because of reasons while at the same time std::ranges (range-v3) implementation did not support this. I wonder how Google solved this problem since AFAIK they also disallow exceptions.
I have no doubt this observation is true, but I haven't been able to picture it, can somebody explain? I don't think ELI5 (let alone an explanation suitable for a Golden Retriever) will work here, but in terms that say a C programmer would grasp. What exactly gets shoved onto the stack when we're using a std::views::filter ?
Slide nr. 21 (nr. 26 in PDF).
I can only guess that it is those return values that are temporarily put on stack so that the consequent | operations could be chained. My hypothesis, without knowing much about this stuff, is that since the compiler cannot elide them (according to the godbolt link from the presentation), stack usage, as found by Google, has cubic growth. I don't quite understand why since I guess it's expected to grow linearly, e.g. 48 bytes at a time.
In my case, the blowup happens mainly because the Ranges style tends to turn easily fungible code like `if x < y` into relatively non-fungible data like the capture-list of `[y]() { return x < y; }`. The former is easily subjected to optimizations like the hoisting of loop invariants; the latter is not. Another way to put this is: The compiler is happy to mess with the layout of the function stack frame up until the very last minute; and to mess with the coroutine frame almost as long; but the layout of a lambda (or std::bind) capture frame is set-in-stone very early, by the front-end. And Ranges loves lambdas.
Yet, when I print the final size of the chained filter ranges and I saw it increasing superlinearly with the number of stages, so I must be missing something.
There is also additional wasted stack space for each temporary range. In theory the compiler should be able to optimize them away, but it probably doesn't always.
You can ask A for the next() item and get back an Option<Item>, this literally iterates as an inherent part of getting your answer, there's no current() or previous() and there's no separate finished() if you ran out of items you got None instead of Some(item). A can be asked for a hint about how much is left, but it's allowed to say it has no useful idea: between zero and more than you can count, inclusive.
B is expected to provide a richer, albeit unsafe, API.
I believe somehow this means it's only reasonable for B to cache answers, as it can be asked to give the same answer again and it'd be inefficient to re-calculate it, whereas there is no way to ask A to repeat an answer so it makes no sense for it to cache (obviously there are special purpose Rust iterators which can have any feature, but the Iterator trait itself doesn't need to cache).
A Rust iterator can be fully implemented by a closure that either returns the next element or signals it's done. This minimalist interface composes well, especially that it always uses single ownership, so there's always only one copy of the state accessed only from one place.
They can't describe collections. They don't remember their beginning. They don't need to know their end until they reach it. They can't be sorted. They don't need to support splitting or iterating in reverse.
Its underspecified, but then has automated tests, that, after failing twice, automatically reject you as a candidate. Of course it doesnt give examples or example test cases or real test cases, so you're shit outta luck trying to solve it. The challenge itself would be fun and solvable in 4 hours, but around the 2 hour mark you start having questions and from there its just bad.
You can google this coding test ("think-cell interval_map") and youll get a lot more info.
I complained to them just in case they cared, and they did seem to care, but failing to specify an automatically tested coding challenge is the kind of psycho shit you do if you think youre the smartest guy in the room (but arent).
ETA: To be clear, I stopped the second I realized it was an underspecified test. I'm not that mad, just mad I fell for spending a whole saturday morning doing it, without ever talking to anyone there in a call or anything.
That and the fact that theyre just building a powerpoint plugin and seem to overcomplicate it to such a massive degree: Yeah no thanks.
I love -faddress=sanitizer or -fsanitize. The historically growing number of warnings which should be turned on are an issue. For example the options -Wconversion, -Wsign-conversion and -Warith-conversion shall be default with C++XX. And if your code doesn’t compile, fix it, use and older revision or turn it deliberately off (saying: I’m aware, read the handbook, I take the risk). Doing such changes with language revisions allows people to take notice about it without surprise.
I want some ideas of CPP2/cppfront[1] in C++XX. Finally using #unsafe when needed, like Rust. C++ does evolve over decades, more like other languages.
[1] https://github.com/hsutter/cppfront
BTW. Use the AddressSanitizer. Please! The toolchain improved the usage and safety of the language so much. It wasn’t available twenty years ago but it is now.
- https://github.com/BjarneStroustrup/profiles
Ie. rather than a bunch of tools helping you find undefined behaviour (or left-and-right improvements of what the behaviour should be) you'd like to be able to make high level claims about your code and have the compiler validate those guarantees.
C++ having a huge C++ legacy, things of course are never easy. So for the time being this is just work-in-progress.
If WG21 is actually open to having them, ISO C++29 is probably when they might land, then given the compiler velocity with previous standards, expect at least 5 years to mature, on the top three, let alone everyone else.
If I am not dead by then, I will certainly be retired.
How long will the industry be willing to wait for profiles?
Herb's discussion of "unsafe" for Cpp2 is... misleading. Rust's unsafe does not turn off checking. If you take some safe Rust which compiles (even if it panics) and you just wrap that in a block with the unsafe keyword, all you get for your trouble is a new diagnostic (by default a warning) saying not to do that because it's futile to use an unsafe block here. No checks are switched off, no "performance" shortcuts are added, if it would panic before it still does now - it's just the same code with a frivolous "unsafe" sign on it.
Warning: <Certain undesirable behavior>
will be an error in Swift <Version
+ 1>.
I’m not sure if it’s an huge improvement, but it’s easy to block all forward warnings with `-Werror` to clean up right away.In general I agree with the sentiment, use AddressSanitizer in testing/debugging. However it's not meant to be a hardening option, AFAIK, so I advise against using it in production (along with other sanitizers), even if you can live with the performance hit.
Theoretically it is possible but libasan is not intended for linking or shipping in production. Also stuff like LeakSanitizer[1] actually cannot [1] be used with GDB.
While shipping debug symbols is something I recommend and has no side-effects aside from mere file-size (debug symbols are only loaded when used).
Usual exceptions apply as you encounter them.
I unfortunately don't write C++ anymore because the TC is too low. It's sad that Python and JS pay more.