Being 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.
Well, 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.
I'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.
Not 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
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.
Some 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.
Hey! 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.
Sorry 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."
You 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++.
It'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).
Well, are you suggesting that a real C++ developer wouldn't think it is a good idea to include a library or framework in his program? (because 156 lines of extra code is too much?)
Have you ever used STL? It is full of template classes! It is a LOT of code in there.
The author implemented a stream processing framework based on lazy evaluation and an interface taken straight out of functional programming (Haskell) approach.
Tidy it up, make it more robust and why wouldn't it be industry strength and ready for production code?
#include <lazy_streams>
//3 lines of code to implement the original problem
What would be wrong with that?
I think C++ more than (m)any other language(s) sufferes from not-invented-here syndrome. If something is not in core language or STL then it might as well not exist -- people will always do their own thing from scratch. Or you grab some behemoth library like Boost which should cater to all your needs.
In contrast in Haskell/OCaml/Clojure (probably others too but those I'm most familiar with) one can download a tiny library that allows to radically change the control flow of the program.
What's demonstrated here is one such thing. It is based on sound principles (monads, functors...) and lazy streams which is a very well researched topic.
Sure, this is C++ we are talking about and there sure will be dragons somewhere. But if Bartosz ever dedicates his time to make a full fledged and tested library I will be damn sure to use it!
Well, before it was "any complex program contains bug-ridden implementation of Lisp", and now it's "any C++ program invents verbose Haskel".
But seriously, while this is toy example, it demonstrates what perhaps will be viable for standard library or for the future language features. Have you tried to read STL implementation code? - it's pretty incomprehensible, but it's still extremely useful library.
I....do not grok article. I don't use function pointers and jump tables all that much, but I'm pretty sure you could add a function pointer argument to printNTriples and replace the printf() with it and get somewhere if you really needed to get there. Starting to feel like I might be getting to the "Get off my damn lawn, kid!" part of my life.
It’s both a demonstration of the expressive power of C++—“In C++, you can say anything!”—and a joke—“…but it takes a very long time to say.” Several of my coworkers experienced with C++ are jumping ship to Haskell for new code, because C++ is becoming simply untenable.
[+] [-] NAFV_P|12 years ago|reply
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:
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|12 years ago|reply
[+] [-] chipsy|12 years ago|reply
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|12 years ago|reply
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|12 years ago|reply
[+] [-] oneofthose|12 years ago|reply
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
[+] [-] yati|12 years ago|reply
[+] [-] throwaway7548|12 years ago|reply
Seriously. I like experiments, but just keep this away from production code.
[+] [-] thinkpad20|12 years ago|reply
Isn't that just C++ in general?
[+] [-] unknown|12 years ago|reply
[deleted]
[+] [-] throwaway7548|12 years ago|reply
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."
[+] [-] louisdefunes|12 years ago|reply
[+] [-] adamnemecek|12 years ago|reply
[+] [-] ryandrake|12 years ago|reply
https://github.com/BartoszMilewski/Okasaki/blob/master/Tripl...
[+] [-] GreaterFool|12 years ago|reply
Have you ever used STL? It is full of template classes! It is a LOT of code in there.
The author implemented a stream processing framework based on lazy evaluation and an interface taken straight out of functional programming (Haskell) approach.
Tidy it up, make it more robust and why wouldn't it be industry strength and ready for production code?
What would be wrong with that?I think C++ more than (m)any other language(s) sufferes from not-invented-here syndrome. If something is not in core language or STL then it might as well not exist -- people will always do their own thing from scratch. Or you grab some behemoth library like Boost which should cater to all your needs.
In contrast in Haskell/OCaml/Clojure (probably others too but those I'm most familiar with) one can download a tiny library that allows to radically change the control flow of the program.
What's demonstrated here is one such thing. It is based on sound principles (monads, functors...) and lazy streams which is a very well researched topic.
Sure, this is C++ we are talking about and there sure will be dragons somewhere. But if Bartosz ever dedicates his time to make a full fledged and tested library I will be damn sure to use it!
[+] [-] vl|12 years ago|reply
But seriously, while this is toy example, it demonstrates what perhaps will be viable for standard library or for the future language features. Have you tried to read STL implementation code? - it's pretty incomprehensible, but it's still extremely useful library.
[+] [-] spc476|12 years ago|reply
[+] [-] qdog|12 years ago|reply
[+] [-] evincarofautumn|12 years ago|reply