
Pipable functions in C++14 - ingve
http://pfultz2.com/blog/2014/09/05/pipable-functions/
======
eps
I've been programming in C++ for close to 20 years now and the only
description for what I feel when looking at this sort of thing is "morbid
fascination". It's cool, but it's disappointing at the same time. The C++ I
started with looked and felt significantly more logical and easier to grasp
than what we have now and this is a very unfortunate way for a language to
evolve.

~~~
brooksbp
Taking a huge risk by saying this (I do not use C++ full-time), but every time
I look at C++11 and C++14 I get the feeling that I should just stick with
Haskell or <insert-popular-fp-lang-here>. It is insanely more natural to do
stuff like this in Haskell. Defer to those with more experience in 'modern
C++'.

~~~
MaulingMonkey
I use C++ more than full time (gamedev -_-;;) out of necessity (consoles,
existing codebase, C++ APIs...)

If I could swing it, I'd absolutely code everything in C#. Okay, maybe that
fails the "fp-lang" bit, but my reasons are basically the same ;). Unity's
finally getting around to covering the "consoles" bases, although I really
wish they weren't using old buggy compilers and writing similarly buggy APIs.
Maybe MonoGame will port to Xbox One eventually...

------
gkmoyn
Somehow I knew the top comment was gonna be "C++ is insane!!"

How would you implement pipe functions in Javascript? And I mean literally
using the pipe operator, and not just chained. You can't, so you don't.

In Java? You can't, do you don't.

In C++ you can. You probably won't. You probably shouldn't so others can
maintain your code in the future. But still, you can do very advanced things.

Thanks, pfultz2, for flexing C++'s muscles.

~~~
byuu
I've been quite disillusioned with C++ myself as of late. I am currently
writing a wrapper class around shared pointers to objects with inheritance
(which embed their own private implementations, which also utilize
inheritance) so that I can pass them by value and use operator. for method
chaining. The SFINAE used for construction from base objects to these shared
pointer wrappers is something out of the ninth circle of hell.

    
    
        template<typename T> struct Shared : std::shared_ptr<T> {
          template<typename U> struct is_compatible {
            typedef char yes[1], no[0];
    
            template<typename V> static yes& test1(typename std::enable_if<std::is_base_of<std::shared_ptr<T>, V>::value>::type*);
            template<typename V> static no& test1(...);
    
            template<typename V> static yes& test2(typename std::enable_if<std::is_base_of<element_type, typename V::element_type>::value>::type*);
            template<typename V> static no& test2(...);
    
            static constexpr bool value = sizeof(test1<U>(0)) == sizeof(yes) || sizeof(test2<U>(0)) == sizeof(yes);
          };
    

And from the function binder:

    
    
          //value = true if R L::operator()(P...) exists
          template<typename L> struct compatible {
            template<typename T> static constexpr typename std::is_same<R, decltype(std::declval<T>().operator()(std::declval<P>()...))>::type exists(T*);
            template<typename T> static constexpr std::false_type exists(...);
            static constexpr bool value = decltype(exists<L>(0))::value;
          };
          template<typename L> function(const L& object, typename std::enable_if<compatible<L>::value>::type* = nullptr) { callback = new lambda<L>(object); }
    

And yet ... when actually _using_ the library, it is a thing of beauty.

    
    
        struct TextEditor : Window {
          MenuBar menuBar = {this};
            Menu menuFile = {&menuBar, "File"};
              MenuItem menuQuit = {&menuFile, "Quit"};
        
          VerticalLayout layout = {this};
            TextEdit editor = {&layout, Size{~0, ~0}};
        
          TextEditor() {
            StatusBar statusBar{this};
            statusBar.setFont(Font::sans(8, "Bold")).setText("Line 1, Column 1");
    
            HorizontalLayout findBar(&layout);
            findBar.append(Label(&findBar, "Find:"));
            findBar.append(LineEdit(&findBar).setBackgroundColor(Color::Yellow)
            .onChange([&] { searchFor(text()); }));
            findBar.append(Button(&findBar, "Clear")
            .onActivate([&] { findBar.widget(1).setText(""); }));
        
            menuQuit.onActivate(&Application::quit);
            edit.onChange([&] { updateStatusBar(); });
          }
        };
    

There is no need for any memory management, or any usage of pointers. We build
UIs, and everything gets automatically released safely when nothing is
referring to it anymore. We can declare named objects that we can use later,
or we can create dynamic objects and pop them right inside of other objects.
We can destroy and unparent things whenever we want. And it's deterministic,
reference-counted GC. No pauses for a tracer. No dynamic typing anywhere, all
errors are at compile-time.

I highly suspect that C++ is unreasonably complicated and that all of this
rvalue-reference, variadic template, meta-programming, dynamic-casting
polymorphism, is all just voodoo that isn't applicable to general programming.
And yet, being able to do it gives me amazing expressive power to write
awesome libraries that I could never hope to accomplish in another language.

Until I find a language that's even in the same ballpark as C++ in terms of
performance, and offers similar expressiveness, it really doesn't even matter
how bad C++ can be for library authors. There's no other viable option right
now. D is the closest we have, but its complexity already rivals, if not
exceeds, that of C++.

~~~
matt_d
A side note: I think you may be able to simplify `is_compatible` by getting
rid of hand-rolled `yes` and `no` constants (and subsequent manual size-
testing for `value` computation) and using `std::true_type` and
`std::false_type`, respectively:
[http://en.cppreference.com/w/cpp/types/integral_constant](http://en.cppreference.com/w/cpp/types/integral_constant)

Edit: noticed you're using these in another place (`compatible`
implementation), so perhaps there's a reason for a different approach?

~~~
byuu
Thanks, the is_compatible test certainly gave me a good bit of trouble.

Ideally you'd want to do enable_if< conditionA || conditionB >, but of course
if one of the conditions fails to evaluate, the overload is ignored. So you
have to split out the conditions and them merge them back together later on.

We could use true_type / false_type, but they have equivalent sizes. So unlike
the function version that only needs one test and can just take the return
type directly, the test at the end would then have to become
std::is_same<decltype(test1<U>(0)), std::true_type>::value |
std::is_same<decltype(test2<U>(0)), std::true_type>::value.

I still think we can do better than even this, so I'll have to keep working at
it.

------
byuu
I'd really like it if they added D's uniform function call syntax to C++
([http://www.drdobbs.com/cpp/uniform-function-call-
syntax/2327...](http://www.drdobbs.com/cpp/uniform-function-call-
syntax/232700394)). Then this code could be:

    
    
        auto r = numbers().where([](int x) { return x > 2; }).select([](int x) { return x * x; });
    

Without the need and potential ambiguity that arises from overloading the pipe
operator, you'd just use simple free functions instead and it'd just work.

~~~
paxcoder
Potentially ambiguous, but I assume worth it?

~~~
byuu
By ambiguous, I mean that operator|'s precedence is very different than
operator.'s (std::operator<< has similar issues); which could lead to
surprises if you don't have the precedence tables memorized.

operator. is at the optimal precedence for method chaining, and has well
understood behavior, so I think it'd be preferred over hijacking things like
the bitwise-or operator.

~~~
paxcoder
Heh, didn't even notice that you mentioned ambiguity too. I was refering to
the D's version with the dot operator: A programmer needs to differentiate
between function calls and method calls. I wonder which ambiguity @pfultz2 was
referring to.

But now that you mention it, an operator (such as pipe) with a lower
precedence could actually be useful and spare having to jump back in code to
open brackets.

------
pestaa
Wow. I think I'm a decent programmer, but that is some hardcore shit right
there.

Some of those syntax constructs are really hard to wrap my head around. In a
lot of cases `x | f` is more readable than `f(x)` (especially when you want to
chain several functions), but there's no way I can remember how to extend the
language this way unless I'm a full-time C++ programmer. I don't feel the same
in Haskell, for example.

Also, function composition should be similar to this, anyone can shed some
light how it would be implemented? (I mean `x | f . g` would look awesome.)

~~~
pbsd
You can't overload the `.` operator. However, something like this would work:
`x | (f , g)`.

------
C--
I feel they could have stopped with C++03. C++11 certainly introduced very few
necessary features but this is just going too far. This is not solving any
problems but in reality is causing new ones as introducing syntactical
redundancies ultimately leads to everyone having their own preference, which
in turn is a source for inconsistent and dirty code bases and bugs.

They should have taken a hint from all of those coding standards coming from
companies such as Google, which basically constrain the programmer to a small
subset of the language features.

~~~
agwa
> C++11 certainly introduced very few necessary features

I have to ask whether you've actually done any significant amount of
programming in C++, both C++11 and pre-C++11.

~~~
TillE
Honestly, it seems like the people who complain loudest about C++ have barely
used it. C++11 is fantastic. C++14 and beyond are quite exciting as well.

I'd avoid Alexandrescu-style template trickery unless you really truly need
it, though. You can write good C++ that more or less resembles Java, and
that's fine.

~~~
pfultz2
> You can write good C++ that more or less resembles Java

That doesn't sound like good C++. Making everything a pointer or implementing
polymorphism through pointers makes the code harder to reason about, and makes
tighter coupling between interfaces and implementations.

------
cschwan
The techniques he used are very similar to "Expression templates". If you are
a C++ programmer and haven't heard of it, look it up. There are not many
libraries actually making use of it, but Boost uBLAS is an example. I think
expression templates give you a good idea what one can achieve with C++
(whether this is a good idea is another question).

OT: That's also why I love the language - there are plenty of ways to solve a
problem and C++, unlike other languages, does not force me to solve a problem
"the right way".

------
IsTom
This is a standard construct in functional languages, probably why it's
getting into C++14. This "|" is $ in Haskell with its arguments reversed. F#
even has it in this particular order of arguments "|>" IIRC.

------
kolev
This is beautiful! Should be part of all languages. I love this in Jinja, but
never thought that this should be native... until today!

------
smallduck
Look at the 3rd to last code block, especially; I claim it self-evident that
C++ is irrevocably broken.

~~~
nhaehnle
Except that nobody in their right mind would actually write code like this on
a day-to-day basis. All languages allow the writing of insane nonsense. The
question is how much nonsense is actually required in everyday work, and on
that point I would argue that C++ is moving in the right direction since
C++11.

------
pcmonk
How can any sane person think this is a reasonable way to program?

While perhaps stated with slight hyperbole, this is actually a serious
question. I don't see how, for example, these pipable functions give any
additional real expressive power, and they seem incredibly hacky in how you
have to build them. I simply don't understand why anyone would use this kind
of thing. C makes sense; I can see an argument for C++03; this is madness.

~~~
pfultz2
Well this can help when you have many nested functions that are chained
together, for example, like this:

    
    
        auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });
    

Because of nesting this can be hard to read(and even write). If we can make
the function pipable, the above can be written like this:

    
    
        auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });
    

Which it is easier to see what this does. So this blogpost goes over how to
implement an utility that will take care of the boilerplate involved in
writing a function that can be pipable.

It does take advantage of a lot of C++14 features to implement this such as
such as vardiac templates, rvalue reference, generic lambdas, and auto type
deduction, but those feature actually make it simpler. I have in the past
implemented something similar for C++03 and the code looks awful with way too
much noise.

> this is madness.

Why do you consider this madness?

Maybe my mind has already been warped by C++.

~~~
jschwartzi
The first one looks like you're chaining functions together, while the second
one looks like you're taking multiple bitwise or operations over the result of
each function.

I think it's fascinating to see how the language can be extended. On the other
hand I would not want to be the poor bastard stuck maintaining either
construct after discovering some compiler edge case. If I've learned anything
it's that just because you can do something doesn't mean you should.

The issue with extending operators in this fashion is that you're violating
the principle of least surprise. | is an operator that should only really do
exactly what it always does--bitwise or. If composition of functions is
fundamentally analogous to taking the bitwise or of two values then I would
concede that your second syntax is a bit clearer.

Personally I feel that this is not the case.

~~~
pfultz2
> The issue with extending operators in this fashion is that you're violating
> the principle of least surprise.

It is really common for the `|` operator to be used for piping functions
together. There are several libraries that support it:
[Boost.Range]([http://www.boost.org/doc/libs/1_56_0/libs/range/doc/html/ind...](http://www.boost.org/doc/libs/1_56_0/libs/range/doc/html/index.html)),
[PStade
Oven]([http://p-stade.sourceforge.net/oven/doc/html/index.html](http://p-stade.sourceforge.net/oven/doc/html/index.html)),
[Linq]([http://pfultz2.github.io/Linq/](http://pfultz2.github.io/Linq/)), and
[Streams]([http://jscheiny.github.io/Streams/](http://jscheiny.github.io/Streams/)).
Plus, its even being proposed as part of the ranges library in future C++:
[https://github.com/ericniebler/range-v3/blob/master/doc/D412...](https://github.com/ericniebler/range-v3/blob/master/doc/D4128.md)

So just as the bit shift operators in C++ also have the meaning of streaming
in and out, the bitwise or also has the meaning of pipe, so this is should not
at all be a suprise.

~~~
jschwartzi
Interesting. I was not aware of this, so thank you.

