(that is, without the boilerplate .begin and .end).
Even that is enough to make ranges useful in my mind, but in a codebase which has started to integrate some functional programming techniques, there are also applications for things like views and transforms.
This can make it easier to reason about iteration pipelines in ways you might already be familiar with from POSIX.
That all said, it's C++ so sometimes the error messages get a lot more 'interesting' than they would have with STL-style iterators, especially when mixed with constexpr expressions as you might do with std::format or fmt libs.
`std::accumulate` is defined to have sequential semantics, so the analysis required to make it parallel is probably not that different than starting from the loop version. I guess you could have an alternate `accumulate_associative` that uses the same interface but assumes the reduction is associative and has unspecified evaluation order?
2) the map part is included in the accumulate lambda, so the map part cannot be parallelized either -> you'd have to split it out into a transform step (iirc)
I really dislike the complexity of modern C++ language specs, but does it obscure much detail about FP ops?
TL;DR:
A vast majority of the programmers I've worked with don't understand the nuances of FP in general, nor the various extents of IEEE-754 support in different programming languages.
So for important numerical programming, I think clarity regarding the FP operations being performed can be crucial. I'm just unclear if modern C++ is a significant factor for that.
I’ve seen some terrible horrid nonsense from them and even the best compilers don’t use a third of the opcodes our modern CPUs boast of. Nobody understands the big compilers any more either, they’re all too huge. And soon AI will be “improving” hem too.
You want to see a beautiful compiler? Look at Plan 9’s compiler suite. A man could understand and even build on that.
> even the best compilers don’t use a third of the opcodes our modern CPUs boast of
That’s not necessarily an indication of the weakness of compilers. It also could be an indication that hardware designers could leave out instructions.
X86, in particular, will have lots of them for backwards compatibility reasons (extreme example: the old 80-bit x87 FP stack)
There also are instructions that are expected to never get used by ‘normal’ compilers but cannot be removed because they only make sense in lower-level code such as those for switching between protection levels, implementing compare-and-swap, etc.
How does the resulting code compared to what a modern compiler gives me. I don't maintain compilers for a living, I maintain other code, which is ultimately longer and more complex than a C++ compiler. And so if my compiler, by becoming a little bit more complex, can make my resulting code a lot simpler because I don't have to do inline optimizations of various sorts, that makes my life much easier and is a good trade-off since there's a lot more programs in the world than there are compilers.
Another name for compilers: invisible backdoor injectors. The more complex is the syntax the more it is likely to happen... I let you guess how the "sane" syntax from c++ and similar (LOL) does fit here...
Quit poking at the openbsd maintainers. Jokes aside (I mean maybe they are one I don't know), it is at least a coherent opinion that inherently complex but critical software infrastructure would ideally be kept as simple and understandable as possible with all the correctness and verification apparatus staying out of the way so you can see what is there to be backdoored. I use rust primarily and like using it, but there are well over a hundred crates just in the front end, and llvm isn't simple. I do miss the days when I could know what each line did.
Every time I see "use ranges and algorithms!" examples, I am baffled that apparently, I am supposed to find
more readable, concise, and easier on my eyes than Sure, there are some algorithms in <algorithms> that I'm rather not reimplement myself, but this one is not it.The first form is easier to send to 32 beefy cores or 1024 small CPUs or a Beowulf cluster or a GPU or people sitting in a room.
Both of them have to be completely rewritten to make use of multiprocessing, so what exactly is the advantage?
The original example isn't really using ranges except to emulate C++98 iterator work though.
The actual equivalent might be something closer to:
(that is, without the boilerplate .begin and .end).Even that is enough to make ranges useful in my mind, but in a codebase which has started to integrate some functional programming techniques, there are also applications for things like views and transforms.
This can make it easier to reason about iteration pipelines in ways you might already be familiar with from POSIX.
That all said, it's C++ so sometimes the error messages get a lot more 'interesting' than they would have with STL-style iterators, especially when mixed with constexpr expressions as you might do with std::format or fmt libs.
The first one too? Isn't that the map-reduce fork-join golden example of multiprocessing?
`std::accumulate` is defined to have sequential semantics, so the analysis required to make it parallel is probably not that different than starting from the loop version. I guess you could have an alternate `accumulate_associative` that uses the same interface but assumes the reduction is associative and has unspecified evaluation order?
C++ has std::reduce for that, which is std::accumulate except it's defined to operate without any specific ordering.
1) afaik accumulate cannot be parallelized
2) the map part is included in the accumulate lambda, so the map part cannot be parallelized either -> you'd have to split it out into a transform step (iirc)
std::accumulate is sequential and guarantes in order traversal. std::reduce is parallel version of it
Trust the compiler - sure - but we can't change the whole program by using -ffast-math, unfortunately, so that particular one is out.
I really dislike the complexity of modern C++ language specs, but does it obscure much detail about FP ops?
TL;DR:
A vast majority of the programmers I've worked with don't understand the nuances of FP in general, nor the various extents of IEEE-754 support in different programming languages.
So for important numerical programming, I think clarity regarding the FP operations being performed can be crucial. I'm just unclear if modern C++ is a significant factor for that.
> Virtual vs static polymorphism
> std::visit over std::variant<A, B, C> is lowered to a switch over the active alternative.
> In this case, layout is probably doing more work than the dispatch mechanism itself.
Very likely because last time I checked visit lowers to a virtual call.
> exceptions are slow
There are proposals to introduce better exceptions into C++. Like this: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p07....
But until it's not in the standard, people should use std::expceted instead.
I’ve seen some terrible horrid nonsense from them and even the best compilers don’t use a third of the opcodes our modern CPUs boast of. Nobody understands the big compilers any more either, they’re all too huge. And soon AI will be “improving” hem too.
You want to see a beautiful compiler? Look at Plan 9’s compiler suite. A man could understand and even build on that.
> even the best compilers don’t use a third of the opcodes our modern CPUs boast of
That’s not necessarily an indication of the weakness of compilers. It also could be an indication that hardware designers could leave out instructions.
X86, in particular, will have lots of them for backwards compatibility reasons (extreme example: the old 80-bit x87 FP stack)
There also are instructions that are expected to never get used by ‘normal’ compilers but cannot be removed because they only make sense in lower-level code such as those for switching between protection levels, implementing compare-and-swap, etc.
How does the resulting code compared to what a modern compiler gives me. I don't maintain compilers for a living, I maintain other code, which is ultimately longer and more complex than a C++ compiler. And so if my compiler, by becoming a little bit more complex, can make my resulting code a lot simpler because I don't have to do inline optimizations of various sorts, that makes my life much easier and is a good trade-off since there's a lot more programs in the world than there are compilers.
Are you a fool?
Another name for compilers: invisible backdoor injectors. The more complex is the syntax the more it is likely to happen... I let you guess how the "sane" syntax from c++ and similar (LOL) does fit here...
What has complex code got to do with it?
Trusting trust was based on old C. You don't get much more minimal than that.
Quite funny comment on the vibe coding age.
Quit poking at the openbsd maintainers. Jokes aside (I mean maybe they are one I don't know), it is at least a coherent opinion that inherently complex but critical software infrastructure would ideally be kept as simple and understandable as possible with all the correctness and verification apparatus staying out of the way so you can see what is there to be backdoored. I use rust primarily and like using it, but there are well over a hundred crates just in the front end, and llvm isn't simple. I do miss the days when I could know what each line did.
And yours is in no way related to mine...
Complaining about C++ compilers given the amount of increasing vibe code garbage and related hallucinations, certainly is.
Oh!
You meant it is even worse nowadays with vibe coding! My bad.