When will Rust adopt the syntax of pipline operator "|>" in ocaml

When will Rust adopt the syntax of pipline operator "|>" in ocaml

1 Like

No one has, to my knowledge, ever created a proposal for this. Until that happens, there is zero chance of it becoming part of the language.

6 Likes

It would be a nice thing to have, though I think I rather see @ instead of |>.

There has been some discussion about it. Any specifics about what you think it brings to Rust?

It doesn't have to be a new operator. What some people consider syntactic noise could be avoided this way:

macro_rules! chain {
    (tuple($f:expr), $x:expr) => {$f($x)};
    (tuple($f:expr, $($tail:tt)*), $x:expr) => {
        chain!(tuple($($tail)*), $f($x))
    };
    ($x:expr, $($tail:tt)*) => {chain!(tuple($($tail)*), $x)}
}

fn into_iter<T: IntoIterator>(x: T) -> T::IntoIter {
    x.into_iter()
}

fn map<X, Y, I: Iterator<Item = X>, F: Copy + Fn(X) -> Y>(f: F) ->
    impl Fn(I) -> std::iter::Map<I, F>
{
    move |i| i.map(f)
}

fn main() {
    // let a: Vec<_> = (0..4).into_iter().map(|x| 2*x).collect();
    let a = chain!(0..4, into_iter, map(|x| 2*x), Vec::from_iter);
    println!("{:?}", a);
}

Which is just a different and not more succinct or readable way of writing the method chain. Problem with method chains is that non-method function calls are awkward, but that's easily alleviated with a .tap(impl Fn(Self) -> Self) style (extension) method that takes a function and "lifts it into the method context". Libraries that provide such a tap function can be found on crates.io.

1 Like

It doesn't seem that clear to me with certainty. From another point of view, chaining functions is normal, but using methods could be considered to be an obscure conflation of function calls, postfix syntax, and single-dispatch mechanisms. If you want to use an object with additional functionality, you would have to revert to ordinary functions, or you will be tempted to monkey patching. It seems, some things do not fit together very well. What should be the right view? Of course, the one that provides the most damage mitigation, or to put it more kindly, the one that seems the most constructive at the moment. At some point, however, one may reach a dead end, or a local optimum, whichever way you want to look at it.

Another simple construction which works today:

struct Node<T> {value: T}
fn arg<T>(x: T) -> Node<T> {Node {value: x}}

impl<X, Y, F> std::ops::BitOr<F> for Node<X>
where F: Fn(X) -> Y
{
    type Output = Node<Y>;
    fn bitor(self, rhs: F) -> Self::Output {
        Node {value: rhs(self.value)}
    }
}

impl<X> std::ops::BitOr<()> for Node<X> {
    type Output = X;
    fn bitor(self, _rhs: ()) -> Self::Output {self.value}
}

fn map<X, Y, I, F>(f: F) -> impl Fn(I) -> std::iter::Map<I, F>
where I: Iterator<Item = X>, F: Copy + Fn(X) -> Y
{
    move |i| i.map(f)
}

fn main() {
    let a = arg(0..4) | map(|x| 2*x) | Vec::from_iter | ();
    println!("{:?}", a);
}
1 Like

Please, do not use @... Start reading at Add operator @ for matrix multiplication - #20 by ckaran, and you'll get an idea of why.

tldr: Quick rule of thumb for creating new operator symbols: if it the symbol isn't printed on the keyboard[1], you shouldn't propose it for a new operator. Everyone reaches for the @ symbol because, thanks to email, we all have that symbol on our keyboards. However, there are a LOT more operators that we'd like to use out there than there are symbols available on our our keyboards. Function/method names, while verbose, are appropriate for those cases where we're not using the operation in at least 20% of our code.


  1. And not just your keyboard, everyone else's keyboard too. I have a '$' on my keyboard, but do Europeans? What about people around the world? β†©οΈŽ