Opinions on piping into variable?

We use the Julia REPL quite a bit with custom data flows. When interactively toying around with them, we find the pipe operator extremely handy; especially combined with expressive Base.show() output, the sense of progression aids the learning, with minimal cursoring-and-bracketing-around.

I was wondering about the possibility of a new operator for assignment at the end of a pipe chain, and wanted to gather some feedback. (I did not find a Julia discussion, only an R one at r - How do you end a pipe with an assignment operator? - Stack Overflow)

So instead of:

result = load("foobar") |> transmogrify

one could write:

load("foobar") |> transmogrify |>= result

Leaner/shorter variants than |>= might even be better, but |= and | are already taken. (Maybe this could even be tackled on a higher, not-just-pipe level, via some “rightward” assignment operator that would not have to adhere to some pipe nomenclature.)

Any thaughts appreciated!

3 Likes

I agree this would be nice (I really with R had this too). fwiw, Chain.jl has something kind of similar in the latest version (which doesn’t wrap in a let block)

julia> using Chain

julia> x = rand(10);

julia> @chain x begin
           first
           y = _
       end
0.5028500583195015

julia> y
0.5028500583195015

I’ve never understood RHS assignment. I use Chain all the time (and simple pipes for simple tasks), but I still always use LHS assignment.

1 Like

You could easily make a macro that takes an expression like @rhassign x |> f |> g = y and flips the expression so that it runs like y = x |> f |> g.

This doesn’t solve the problem, though, since if you knew you wanted to assign a variable, you would have written it at the top.

Same response to @tbeason, sometimes you write an expression and then realize only later you want to assign it to a variable. Its a nice feature wither REPL

I also just figured out how to do it in R

x %>% f() -> y
2 Likes

I don’t think that really makes much of a difference, you can return to the beginning of a long expression with 1 or 2 keystrokes (home key) and add the assignment if you want. It is more about a conceptual difference.

1 Like

TIL about the home key. Still, I think it would be useful.

2 Likes

Hi,
first, thanks for the feedback!

I concur with @pdeffebach that macros are not ideal here – when I started piping around, I of course forgot to start the line with the initial macro; I’d need the same procedure (up → home → write something).

(Of course the number of keystrokes is absurdly modest. But maybe it’s also psychological – at least my head does not want to go back to the beginning of the nice pipeline; it is now snugly entrenched at the end of it…)

1 Like

I’m not sure about this. I only pipe across many lines, and left handed assignment is a lot clearer in that case. There’s no way I would confuse = and |>, but I might confuse |>= and |> at a glance and think result is the last called function. I get the use in the REPL, but we already can 1) click the home key to move to the start of the line, or 2) retrieve the value from global ans immediately after execution:

julia> 1:9 |> sum
45
julia> ans
45
julia> result = ans
45
julia> 1+1
2
julia> ans
2
julia> result
45
julia> ans
45
3 Likes

Actually it does, the <- assignement in R is also available as ->, which is IMHO clever.

Hi,

I wanted to add a possible idea to this thread.

The following, at first sight, seems to achieve the desired “assignment-at-end-of-pipe.” I am very unsure if this does not break something else; any feedback really very welcome!

(The primary goal would be for this to work in the REPL; it would not necessarily need to have to work otherwise…)

The idea is to overwrite the function call operator for Symbol:

julia> x
ERROR: UndefVarError: x not defined

julia> function (newvarname::Symbol)(varvalue)  eval(:($newvarname = $varvalue))  end

julia> 1 |> sin |> cos |> sin |> cos |> sin |> cos |> :x
0.7467069000243155

julia> x
0.7467069000243155

(I would activate it in my REPL modes for interactive usage only…)

Could there be some dangerous side-effect here in your opinion? Maybe I need to do better escaping/quoting…?

Interesting, though the use of eval feels like a code smell to me.
Alternatively, you could have a macro creating a function suitable for piping, i.e.,

macro rassign(symb)
    :(x -> global $(esc(symb)) = x)
end
julia> 1 |> sin |> cos |> sin |> cos |> sin |> cos |> @rassign x
0.7467069000243155

julia> x
0.7467069000243155
3 Likes