5 ms·
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 operat
by gkmoyn 12y ago
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.
- pcmonk 12y agoJust because a language allows you to morph its syntax doesn't make it any more powerful. I'm not sure how this is considered an "advanced" thing. It's certainly a convoluted thing, but that's not at all the same.
- malisper 12y agoThere are three reasons why a program would look like this: 1. It is something simple implemented in a complicated way. 2. It is something complicated implemented in a simple way. 3. It is something complicated implemented in a complicated way. I believe this is an example of case 3, meaning even though it is something advanced, it should not take code that looks insane to express it.
- pfultz2 12y agoI disagree. It makes it very simple to make a pipable function, you just wrap the function object in pipable. There's nothing complicated about using it. Futhermore, doing it by hand is not as simple, but still not very complicated. This just helps alleviate the boilerplate in defining pipable functions.
- malisper 12y agoThere's nothing complicated about using it. I'm not talking about using the pipe operator, I'm talking about implementing it. The C++ version is ridiculously complicated. Let's compare your code with an analogous implementation in Common Lisp. (defun pipe (val &rest fns) (reduce (lambda (acc f) (funcall f acc)) fns :initial-value val)) Just this allows for some pretty similar code: (pipe 99 #'1+ #'sqrt #'1-) which evaluates to 9.0 It is possible to implement it in C++, but the implementation winds up being ridiculously complicated. I just implemented something very similar in Common Lisp and it wound up being incredibly simple. Why doesn't C++ allow for a definition nearly as nice as the Common Lisp one?
- pfultz2 12y ago> It is possible to implement it in C++, but the implementation winds up being ridiculously complicated. It may be more verbose in C++, but its not more complicated, and its definitely not "ridiculously" complicated. > I just implemented something very similar in Common Lisp and it wound up being incredibly simple. Maybe for you as a lisp programmer, but for me I find the lisp code incomprehensible.
- nawitus 12y ago>How would you implement pipe functions in Javascript? And I mean literally using the pipe operator, and not just chained. >But still, you can do very advanced things. Why do you think "advanced" means the ability to overload operators? I'd personally define "advanced" to mean something to do with semantics, not syntax.
- byuu 12y agoI'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++.
- mscdex 12y agoFor JavaScript there is this: https://github.com/hij1nx/pipe https://github.com/hij1nx/pipe
- Guthur 12y agoJust because you can use some ambiguous syntax construct does not make it good or even clever. This sort of thing can be done a lot clear with functional constructs like compose and curry. Common Lisp example (easily done with any language that supports higher order functions): (funcall (compose 'add-one 'add-one) 1) And you can roll that a number of ways; adding in a curry of the identity of 1 if you just want a nullary function. (funcall (compose 'add-one 'add-one (curry 'identity 1)) And if you are interested in typing less, maybe you are a dreadful typist...try Haskell.
- AndrewDucker 12y agoInterestingly, you can in Powershell, where piping objects works very naturally.