Thank you for the reply! We use Rails exclusively on my team, so all of my 
exposure to Elixir so far has come through HackerRank, Exercism, and poring 
over the online guide and core documentation.

May I ask for clarification around what you mean when you say "create small 
named functions [when you can't pipe]"?  From everything I've read and seen,

thing |> a_function

is simply converted to

a_function(thing)

at compile time, so... "when you can't pipe", literally translates to "when 
you would be unable to call a function"... Unless I've missed something? 
How would one apply the advice of creating a small named function to a 
practical example to a workflow point where you would be unable to call a 
function?

Since my password function was the only semi-noncontrived example, I guess 
you're saying it would be best practice to rewrite it from 

def encrypt_password(user, password) do
  encrypted = password
    |> Salt.add
    |> BCrypt.hash
  put_in(user[:hashed_password], encrypted)
    |> EctoLike.update
end

to something like 

def encrypt_password(user, password) do
  put_in(user[:hashed_password], encrypt(password))
    |> EctoLike.update
end

defp encrypt(password) do
  password
    |> Salt.add 
    |> BCrypt.hash 
end

or something similar, right? I've learned to try to keep code as close to 
where it winds up getting run as I can (jumps are bad, m'kay? 
<https://www.joelonsoftware.com/2003/10/13/13/>), so my instinct is to keep 
processes inlined in their methods until I use the process in more than one 
place, or (in this new Elixir land) until I have a second clause I need to 
define.



On Tuesday, May 2, 2017 at 10:12:59 PM UTC-7, José Valim wrote:
>
> As explained in the many others pipe proposals sent to this mailing list, 
> we don't plan to add more complexity to the pipe operator.
>
> Despite the suggestions of many, anonymous functions are not the solution 
> when you can't pipe. Well named and defined private functions are. Elixir 
> is a functional language. So create small named functions to improve code 
> readability.
>
> On Wed, May 3, 2017 at 01:48 OvermindDL1 <[email protected] <javascript:>> 
> wrote:
>
>> Hmm, I rather like it, `|>` is pipe-start (still think it should be pipe 
>> into the end of the argument list) and `|^` could be pipe-pin, interesting 
>> approach, I like it.
>>
>>
>> On Tuesday, May 2, 2017 at 5:09:57 PM UTC-6, Josh Bourgeois wrote:
>>>
>>> Many significant apologies for reopening this very-very-well-treaded 
>>> topic, but I do want to advocate this *one* more time.
>>>
>>> The pipe operator is used to illustrate the flow of data transformation, 
>>> but while functional programming is very expressive, there are times when a 
>>> signature requires the data in question to be used as a different argument. 
>>> In those cases, you must either break the pipe chain (and thus the flow of 
>>> data transformation) to assign the transformed data to a variable, or send 
>>> the data through an anonymous function to continue the program flow.
>>>
>>> Take a process where data should be transformed before being saved to a 
>>> database:
>>>
>>> # intermediary value
>>> def encrypt_password(user, password) do
>>>   encrypted = password
>>>     |> Salt.add
>>>     |> BCrypt.hash
>>>   put_in(user[:hashed_password], encrypted)
>>>     |> EctoOrSomething.UpdateIGuess.ImStillNewHere
>>> end
>>>
>>> # anonymous function wrap
>>>
>>> def encrypt_password(user, password) do
>>>   password
>>>     |> Salt.add
>>>     |> BCrypt.hash
>>>     |> (fn(encrypted) -> put_in(user[:hashed_password], encrypted) end
>>> ).()
>>>     # or |> (&(put_in(user[:hashed_password], &1)).()
>>>     # but considerably messy either way
>>>     |> ...
>>> end
>>>
>>> The main issue in conceptualizing a more elegant workflow to represent 
>>> these transformations is that any construct implemented will make an 
>>> affordance in one direction or the other. A pipe-to-argument operator would 
>>> offer strong reusability, but proposals in this group suggested a token 
>>> that poorly expresses its usage (I'm thinking of a thread where ~| had 
>>> been proposed as an anonymous variable binding with |>) . The other 
>>> proposals are for inflexible cases that would necessitate more extensions 
>>> for further implementations, and/or borrow symbols from other languages 
>>> that are ambiguous in their usage (such as proposals for <|, |<, and |>> as 
>>> tokens for pipe-to-last).
>>>
>>> I think Elixir is in a unique position to solve this problem, though. If 
>>> I could draw a correlation, the pin macro, Kernel.^/1 is used to bind a 
>>> variable in at a location for pattern-matching...
>>>
>>> good_status = "200"
>>> {^good_status, response} = fetch("www.example.com")
>>> # expands to {"200", response} = fetch("www.example.com")
>>>
>>> I believe there's syntactic justification for a new pipe macro, 
>>> Kernel.|^/2, that would interact with a Kernel.^/0 macro, to combine 
>>> the concepts of the pipe and the pin. Assuming the current pipe 
>>> operator symbolically translates | to "pipe to" and > to "the left", |^ 
>>> would 
>>> represent "pipe to the pin". The pin would appear at least once in the 
>>> expression on the right in order to represent where the expression on the 
>>> left will appear, expanded, like such:
>>>
>>> def encrypt_password(user, password) do
>>>   password
>>>     |> Salt.add
>>>     |> BCrypt.hash
>>>     |^ put_in(user[:hashed_password], ^)
>>>     |> ...
>>> # expands to ...(put_in(user[:hashed_password], 
>>> BCrypt.hash(Salt.add(password)))
>>> end
>>>
>>> Benefits to this approach:
>>>
>>>    - The current pipe operator behavior remains pristine
>>>    - ^/0 continues to act as a reference to expanding a variable
>>>    - No introduction of new symbolic concepts
>>>    - Syntax is flexible enough to expand to any (or multiple) argument 
>>>    position
>>>
>>> # more contrived examples!!
>>> > map = %{little_bunny: %{}}
>>> > :foo
>>>     |^ put_in(map[:little_bunny][^], ^)
>>> %{little_bunny: %{foo: :foo}}
>>>
>>> > "Ton" |^ (^<>"y! " <> ^<>"i! " <> ^<>"é!")
>>> "Tony! Toni! Toné!"
>>>
>>> Again, I know there've been many discussions about the drawbacks to 
>>> implementing a new pipe mechanism, and the Elixir community may have 
>>> already come to a consensus around how to handle transformations like this, 
>>> but I think the longevity of this topic points to a desire for some kind of 
>>> better solution.
>>>
>>> If everyone is tired of talking about this, I'll happily let it end 
>>> here, but I thought one more perspective couldn't hurt.
>>>
>>> Thanks for reading! ^_^
>>>
>>> On Wednesday, July 9, 2014 at 5:10:19 AM UTC-7, José Valim wrote:
>>>>
>>>> at the risk of being painfully obvious, this works:
>>>>>
>>>>> :crypto.rand_bytes(8)
>>>>> |> Base.encode16
>>>>> |> (&("--------FormDataBoundary" <> &1)).()
>>>>>
>>>>
>>>> Yup, this form works and is usually the solution proposed for such 
>>>> cases.
>>>>
>>>> I concur that allowing such forms would be a special case for pipe and 
>>>> possibly confusing in the long term. However, given that many were 
>>>> expecting it to work, I decided to gather everyone's feedback. And based 
>>>> on 
>>>> this thread, it doesn't seem we should change the pipe operator.
>>>>
>>>>
>>>> *José Valim*
>>>> www.plataformatec.com.br
>>>> Skype: jv.ptec
>>>> Founder and Lead Developer
>>>>
>>>>
>>>> -- 
>
>
> *José Valim*
> www.plataformatec.com.br
> Skype: jv.ptec
> Founder and Director of R&D
>

-- 
You received this message because you are subscribed to the Google Groups 
"elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/elixir-lang-core/d5387c0c-afe9-470a-8443-8a06eeaa61a7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to