+1. I do have to say, though, I'll be far more likely to implement the 
refactor based on Rich's implementation. 
One might be able to refactor it even farther, simply to "easy is hard", 
but then it may lose some nuance and portability.



I really like the constructs Elixir uses to encourage code simplicity. 
Pattern matching and guard signatures allow functions to take on a level of 
granularity where you legitimately can write functions that perform 
*exactly* one action, *exactly* the same way with the same inputs. What 
emerges is a coding style where, as a general rule, you can say that if 
your Elixir function needs to set a variable, it can be refactored to a 
simpler function body.

My rationale for suggesting the pinpipe operator was because, within some 
function bodies, the only reason you might consider introducing a variable 
is so that your transformed data can be used in a specific position of your 
function result. The code example of def boundary at the start of this 
thread, for instance, is a self-contained, pure function as it is. The 
anonymous function called at the end does not need to exist, as the SHA 
sent in could just as easily be a variable:

def boundary do
  sha = :crypto.rand_bytes(8)
  |> Base.encode(16)
  "---------FormDataBoundary" <> sha 
end

DRY principles (at least, as far as The Rails Way was taught to me) would 
say that if there were no other way you would want a 
"---------FormDataBoundary" to be generated, then you would want to keep 
this method body self-contained, and with as few introduced variables as 
necessary. Pipe workflows keep that intent in focus by dissuading you from 
making functions that work on anything but their inputs. When I'm in that 
mindset, variables set within a function are an anti-pattern, but I would 
still sooner catch myself moving the pipes to the place where they were 
necessary:

def boundary do
  "--------FormDataBoundary" <> (:crypto.rand_bytes(8) 
    |> Base.encode(16))
end # sha, you know what? uh-uh.

Coming back to being able to overload signatures as you can in Elixir, 
after half a decade of not being able to in Ruby and Javascript, the above 
is still far more natural to me (even though I know inside how kludgey it 
feels) compared to something like:

def boundary, do: :crypto.rand_bytes(8) |> Base.encode(16) |> boundary
defp boundary(sha), do: "--------FormDataBoundary" <> sha

But almost all of my hesitation around a convention like this comes from 
not being used to it. Portable, reusable functions are very good things to 
have central to a language design, and if Elixir has A Right Way to 
implement those, it's within the maintainers' rights to foster that happy 
path and discourage what would be impure solutions according to the 
language philosophy. As the community grows and more code examples become 
available, fewer people will wonder about how they should do these things.

On Wednesday, May 10, 2017 at 5:39:53 AM UTC-7, Onorio Catenacci wrote:
>
> That's a great point Robert and Mr. Dijkstra certainly deserves credit.  
> Thanks for reminding me about that.
>
> On Tue, May 9, 2017 at 5:44 PM, Robert Virding <[email protected] 
> <javascript:>> wrote:
>
>> Actually this was said by Dijkstra long before Rich:
>>
>> “Simplicity is a great virtue but it requires hard work to achieve it and 
>> education to appreciate it. And to make matters worse: complexity sells 
>> better.”
>> Unfortunately all 3 points are true. He also said:
>>
>> “Simplicity is prerequisite for reliability.” 
>>
>> which is also true.
>>
>> On Tuesday, 9 May 2017 14:11:46 UTC+2, Onorio Catenacci wrote:
>>>
>>> To paraphrase Rich Hickey--"Simplicity isn't easy".  Figuring out those 
>>> simple function signatures is not the first thing that comes to mind for 
>>> most of us.  But it's worth the effort.
>>>
>>>
>>> On Saturday, May 6, 2017 at 7:14:45 PM UTC-4, Josh Bourgeois wrote:
>>>>
>>>> I thought of practicing, but then I just wound up doing a lot of 
>>>> thinking. Then it clicked 😬
>>>>
>>>> defmodule Words do
>>>>   def count("" <> string), do: parse(string) |> Enum.reduce(%{}, 
>>>> &count/2)
>>>>
>>>>   defp count("", map), do: map
>>>>   defp count("" <> word, map) do
>>>>     word |> String.replace("_", "-")
>>>>       |> increment(map)
>>>>   end
>>>>
>>>>   defp increment(word, map), do: put_in(map[word], (map[word] || 0) + 1)
>>>>   defp parse(string), do: string |> String.downcase |> 
>>>> String.replace("-", "&hyph;") |> String.replace("_", "-") |> 
>>>> String.replace("&hyph;", "_")  |> String.split(~r/\W/u)
>>>> end
>>>>
>>>> It's just a challenge to think of meaningful names sometimes. Breaking 
>>>> function/method bodies into smaller discrete blocks of work is obviously a 
>>>> fundament to making code more readable, but it takes discipline and, 
>>>> sometimes, a thesaurus
>>>>
>>>> Thank you for entertaining this zombie discussion once more 😶
>>>>>
>>>>> -- 
>> You received this message because you are subscribed to a topic in the 
>> Google Groups "elixir-lang-core" group.
>> To unsubscribe from this topic, visit 
>> https://groups.google.com/d/topic/elixir-lang-core/dwbNOh_yNd4/unsubscribe
>> .
>> To unsubscribe from this group and all its topics, send an email to 
>> [email protected] <javascript:>.
>> To view this discussion on the web visit 
>> https://groups.google.com/d/msgid/elixir-lang-core/59c6d90d-ded2-4794-8a73-920ab9350007%40googlegroups.com
>>  
>> <https://groups.google.com/d/msgid/elixir-lang-core/59c6d90d-ded2-4794-8a73-920ab9350007%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>
>
> -- 
> Onorio Catenacci
>  
> http://onor.io
> http://www.google.com/+OnorioCatenacci
>
>

-- 
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/2ea77bcc-a834-4108-902d-8722213fae3f%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to