

Getting Lazy with C++  - chokolad
http://bartoszmilewski.com/2014/04/21/getting-lazy-with-c/

======
NAFV_P
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.

~~~
dmytrish
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.

~~~
NAFV_P
> _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.

------
chipsy
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.

~~~
jzwinck
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](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.

------
oneofthose
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.

[0]
[https://www.youtube.com/watch?v=BFnhhPehpKw](https://www.youtube.com/watch?v=BFnhhPehpKw)

------
yati
Fascinating :) I am having a really great time reading this guy's blog.

------
throwaway7548
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.

~~~
throwaway7548
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."

~~~
rapala
I'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
Don'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.

------
louisdefunes
Is this a joke ?

~~~
adamnemecek
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++.

------
ryandrake
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).

[https://github.com/BartoszMilewski/Okasaki/blob/master/Tripl...](https://github.com/BartoszMilewski/Okasaki/blob/master/Triples/Triple.cpp)

~~~
GreaterFool
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!

~~~
jejones3141
I would have to disagree. C++ is the opposite of NIH; it's a kitchen sink
programming language.

