6 ms·
Getting Lazy with C++
- throwaway7548 12y agoHey! This is great! I can fill my C++ code with statefull functors and lazy evaluation. The enemy shall not pass. No one will ever be able to debug it. Instant job security. Seriously. I like experiments, but just keep this away from production code.
- throwaway7548 12y agoSorry about being an asshole here, but really. The problem with articles like that, is that a novice developer, with some 5-10 years of experience can pick up an article similar to that one and use such techniques without any need. With disastrous consequences. How do I know it? I've seen it happen. Again and again. Hell, it had happened to myself, years back. An article like that should start with: "unless you really really know what you are doing and are an adult (20+ years of coding) you should probably avoid using techniques like that in the production code."
- reality_czech 12y agoHey, that's not fair. Experts can use them for disastrous consequences as well. This is C++ we're talking about here!
- chetanahuja 12y agoHah... "novice... with some 5-10 years of experience". Actually you're not too off the mark. And in any case, with c++11, pretty much everyone who's not been following the c++0x/c++1x process assiduously, counts as a novice.
- enjoy-your-stay 12y agoI would have to agree with your comment there. Although having over 7 years experience as a c++ programmer, since I'm not using it so much now I haven't managed to keep up so much with the changes in c++11 and feel a bit noviced overnight. Still, move constructors are pretty handy so that's one change I use whenever I can.
- rapala 12y agoI'm pretty sure C++ (and any language for that matter) has more than enough quirky features to obfuscate any piece of code. No need to read this article for that. But if 20 years of experience makes lazy streams seem unfit for production, then someone has spent 10 years burying their head so deep in the sand that their feet are barely showing. Java's iterators, Python's generators, you work with them even in C. And is it not obvious that one needs to really know what they are doing if they are working as a professional developer? The example of the article was simple of course. But solving the problem of printing Pythagorean triples was not the aim of the article. The aim was to show what makes lazy streams tick, to show that they can be implemented in C++ and that an uniform interface can be provided with functor, monoid and monad. Finally, the simple problem was solved with the new tool to show the inversion of control. PS. std::vector is a stateful functor.
- throwaway7548 12y agoDon't get me wrong. I like functional approach. I am developing in functional languages as well as in C/C++. I think these techniques actually do have a place in the production level code. But, the mail point of the post was, that if you write an article like that, it should start from a warning to novices. This point of view is based on the experience of having to deal with fuckups from novice developers, who were trying to use and abuse the language to the full extends of their abilities. Including fuckups of my own. PS. std::vector is a container.
- fauigerzigerk 12y agoIn this case I think 20 years of C++ experience doesn't help much. At least it doesn't help me. This is a challenge for procedural programmers to really think through what functional primitives are all about by implementing them in a procedural language. It's not the usual template metaprogramming brain teaser.
- throwaway7548 12y agoI very much agree. I should have stated more clearly that "20 years of coding" requirement in my post should include software (and hardware development) in a variety of languages, including functional languages. Or even domain specific languages like SQL, Matlab or VHDL/Verilog.
- jeremiep 12y agoYears of experience is also hard to define. It's as precise a metric as lines of code are. I've seen people saying 10 years of experience when they're closer to have 10 times one year of experience since they continuously do the same thing over and over. I've also seen people with barely a year or two of experience already coding circles around people with 10+ years.
- deleted 12y ago[deleted]
- thinkpad20 12y ago> The enemy shall not pass. No one will ever be able to debug it. Instant job security. Isn't that just C++ in general?
- ryandrake 12y agoIt's either an exaggerated academic demonstration or a joke, but it's convincingly presented in a serious tone. Nobody genuinely thinks it's a good idea to replace a 9 line C function with 156 lines of templated C++ code (not counting the header full of templates classes it includes). https://github.com/BartoszMilewski/Okasaki/blob/master/Triples/Triple.cpp https://github.com/BartoszMilewski/Okasaki/blob/master/Tripl...
- spc476 12y agoHow about if it's framed differently: he created coroutines in 156 lines of C++.
- zvrba 12y agoWell, almost. A coroutine is created once and it yields control to its "caller" each time it produces an item. To implement a coroutine, you only need to save its stack (local variables, instruction pointer). He created a lazy stream: instead of yielding control for each item produced, it makes a linked list of items where each node is created on demand. Thus, coroutines only return the "next" item, while streams compute and store the history of the whole computation.
- adamnemecek 12y agoNot to nitpick but you are talking about generators which IIRC are also incorrectly called coroutines in the Python community. A proper coroutines are not limited to yielding control to the caller, but anywhere.
- zvrba 12y agoI've described what's usually known as asymmetric coroutines or semicoroutines. "Asymmetric" because [as claimed by Lua manual at least] there are two separate calls for control transfer (yield and resume). Generators are less powerful. See http://www.lua.org/pil/9.1.html http://www.lua.org/pil/9.1.html
- 12y ago
- louisdefunes 12y agoIs this a joke ?
- adamnemecek 12y agoYou do realize that this is a pretty common pattern in asynchronous programming, right? E.g. in the browser networking stack. Like the one that you used to post your comment. Which was most likely implemented in C++.
- yati 12y agoFascinating :) I am having a really great time reading this guy's blog.
- chipsy 12y agoI'm not sure why this comment thread is so awful. It's as if veteran C++ devs are scared of Haskell or something. Lazy evaluation is a great boon for achieving a mix of performance and flexible coupling. In a lot of simpler, lower-performance cases you _can_ get away with just evaluating the same function with the same inputs repetitively, which doesn't require these tools, but having the "next step" available makes it possible to apply that strategy in more places.
- jzwinck 12y agoNot scared of Haskell, just we have other ways to do stuff like this in C++, namely iterators. I posted a solution using iterators here: https://news.ycombinator.com/item?id=7626984 https://news.ycombinator.com/item?id=7626984 My solution completely avoids dynamic memory allocation--even the stack allocation is just a handful of bytes per generated triple. You're right that lazy evaluation is useful for performance, but TFA acknowledges that its own implementation is not efficient because it dynamically allocates memory repeatedly. This is not something we can hand-wave away: it's at the core (no pun intended) of high performance in C++ and many other languages.
- mmaldacker 12y agoYou are right, but computing the first n Pythagorean triples is a terrible example to show lazy evaluation.
- NAFV_P 12y agoBeing a 100000 year old lycanthropic C coder things like lazy evaluation, garbage collection etcetera make my head spin (a full 1440 degrees) .. But I have come across Milewski before since I started on C++, he has a clever way of explaining programming concepts while tending to avoid the usual "is a, has a". A couple of months ago I gave Haskell a decent go, and I sort of got my head round the basics of being a lazy coder. Take a never ending list: let t=[1..] Okay, fairly compact notation. I think of this code as declaring blueprints of the list in order to create it when someone demands it. That's alright, as long as those blueprints take up substantially less space in memory than the list itself. In the example above, the entire list can be generated by a starting value and a function to append the previous value incremented by unity to the end of the list; the data exhibits the ability to be compressed infinitely. The same can be applied to many other simple lists, like the set of all square numbers. This is an efficient use of memory. When the function required to create a certain list becomes comparable in size to the resultant list, this advantage is lost. Luckily, those lists are fairly rare - white noise would be a pathological example.
- dmytrish 12y agoWell, Haskell has rather helpful strictness analyzer in its compiler that tries to determine automatically where strictness has to be enforced. C++ implementation does not have this advantage, but a limited form of laziness still seems to be a good tool for code expressiveness.
- NAFV_P 12y ago> Well, Haskell has rather helpful strictness analyzer in its compiler that tries to determine automatically where strictness has to be enforced. I wasn't aware of that, cheers for the heads up.
- oneofthose 12y agoSome commenters seem to be offended by the way Bartosz presents his insights. Maybe some background is necessary. Bartosz has been pushing the C++ community for some time now to think more functional and consider the excellent properties of functional languages. His posts are great and his talks are very enlightening. I recommend his recent talk "I see a Monad in Your Future" [0] and I'm looking forward to his talk at C++Now. Many of Bartosz' discussions focus on concurrency. It is one of the big and interesting problems we have at the moment. The criticism repeated here that "No one will ever be able to debug it" and the like is exactly what Bartosz sees in our future if we continue to program concurrent systems the way we do. He favours adoption of functional programming concepts to manage the complexity of concurrent systems. And I agree. If code similar to the code in his blog is not acceptable in production code, a code review should make sure it never reaches production. An informed discussion about the pros and cons of such code could ensue during the code review, new insights are gained and everyone walks away a better, more knowledgeable programmer. I suspect this is one of Bartosz main goals. [0] https://www.youtube.com/watch?v=BFnhhPehpKw https://www.youtube.com/watch?v=BFnhhPehpKw