And as a trade off you get a much cleaner and more performant solution to the same contrived problem. This is where Haskell and functional coders tend to break down. Yes its mutable, but by violating that one rule you gain so much in terms of readability and performance.
That's one thing I've noticed with my C++ code lately is that I'm writing const absolutely everywhere. Having mutability where you need it is awesome but it is interesting to see languages like Rust where immutability is the default.
I have done a bit of this too. The main downside in C++ is that you end up writing a few more ternary operators than you otherwise may have. But it is nice to be able to look at the first assignment of a variable and know it is the only one.
Yeah it kind of feels dirty having all these mutable variables around after doing any functional programming at all.
I've found using const a lot also goes hand-in-hand with raii. If a member of a class is const it must be initialized in the constructor, and it just seems to make me code a bit more "hygienically".
Indeed. This is part of why I included "idiomatic" in the title here. Someone smarter than me already wrote a bit prettier iterator increment function, and using that is easy once you have the interface decided. And in C++, iterators abound, and can be used as infinite sequence generators with no difference to how they are normally used and understood.
The code may be spaghetti, but I mostly just lifted it from the referenced article and solved the problems the original author brought up, namely the separation of concerns. The C++ solution to this problem will never be as beautiful as the Haskell one, but I wanted to show it doesn't have to be alienating for people who program C++ daily.
C++ iterators are powerful, and can be used for a lot more than stepping through a container. We write too few of them.
I totally agree--thank you for bringing this up. I'm not sure it would be faster, but it is an interesting case for goto.
I saw another proposal referencing the original article which used a trio of functions in a nice way to achieve something similar without the goto (and without the ifs). My main point was to illustrate the use of custom iterators.
Consider me nerd-sniped. I typed the last post on my phone, but just had to bust out the laptop to check. Noticed a couple bugs I had: the for-loop initializers need to be set, and there needs to be an empty statement after the cont: label.
The goto version only has one unconditional branch outside of a loop, rather than three conditional branches inside loops. Anyways, the speed difference shouldn't be too big, as the branches are pretty predictable (pretty much always not taken).
Quick benchmark of the original and mine, up to the first 3000 triples:
$ c++ -O3 pyth1.cpp && time ./a.out | md5
33aa33d6cad59951489757e06aeb5a15
real 0m5.492s
user 0m5.484s
sys 0m0.007s
$ c++ -O3 pyth2.cpp && time ./a.out | md5
33aa33d6cad59951489757e06aeb5a15
real 0m4.248s
user 0m4.238s
sys 0m0.011s
I'm always looking for a legitimate excuse to use a goto in my C++ code because I'm perverse. It's very rare to find one but this looks like it might be okay.
Hopefully, once we get ranges in the C++ standard library, we can add list comprehension to the language, perhaps something like this:
auto q = [
for (z, std::irange(1, std::numerical_limits<int>::max()))
for (x, std::irange(1, z))
for (y, std::irange(1, x))
if (x*x + y*y == z*z)
boost::fusion::make_vector(x, y, z)
];
for(auto&& x:q | std::take(10)) std::cout << x << std::endl;
I'm learning C/C++, tried to compile (http://ideone.com/T1xVLz) your code in ubuntu, with gcc-4.8, and an error about copy_n is not declared in this scope was raised.
error: ‘copy_n’ was not declared in this scope
what is the problem? Is it something to do with gcc-4.8 and shared libs?
19 comments
[ 4.5 ms ] story [ 47.2 ms ] threadYour code is
I've found using const a lot also goes hand-in-hand with raii. If a member of a class is const it must be initialized in the constructor, and it just seems to make me code a bit more "hygienically".
The code may be spaghetti, but I mostly just lifted it from the referenced article and solved the problems the original author brought up, namely the separation of concerns. The C++ solution to this problem will never be as beautiful as the Haskell one, but I wanted to show it doesn't have to be alienating for people who program C++ daily.
C++ iterators are powerful, and can be used for a lot more than stepping through a container. We write too few of them.
I saw another proposal referencing the original article which used a trio of functions in a nice way to achieve something similar without the goto (and without the ifs). My main point was to illustrate the use of custom iterators.
The goto version only has one unconditional branch outside of a loop, rather than three conditional branches inside loops. Anyways, the speed difference shouldn't be too big, as the branches are pretty predictable (pretty much always not taken).
Quick benchmark of the original and mine, up to the first 3000 triples:
And the only point of having named break/continue would be to not use goto. I don't see the point in that, since to me, this:
is as readable as this:Edit: A better way to write the inner loop: http://ideone.com/wEfNyh
Edit: When the values are initialized to 3, 4, 5 instead of 0, 0, 0, the program can be simplified to: http://ideone.com/oyNk1O
error: ‘copy_n’ was not declared in this scope
what is the problem? Is it something to do with gcc-4.8 and shared libs?
Thanks