watt ([info]watt) rakstīja [info]koderi kopienā,
@ 2006-08-29 13:13:00

Previous Entry  Add to memories!  Tell a Friend!  Next Entry
I offer this critique of Erlang programming language tutorial:
http://pupeno.com/blog-en/erlang-the-language-for-network-programming-issue-1-pattern-matching/

While Erlang probably is a fine concept, and functional programming is popular among some, I have a problem with the way the concepts are taught.



Let's start with a classic of functional programming: factorial. This is factorial in Erlang:

fac(N) ->
   if N == 0 -> 1;
      true -> N * fac(N - 1)
   end.



Ok, now tell me, why did you name this function "fac" ? That is one nondescriptive 3 letter name. "fact" would be somewhat better, but would it kill you to spell the function name out completely? WOULD IT KILL YOU to type 5 letters more, type "orial" on the function definition, if you have already decided to spend a whole lot of time writing the damn tutorial?

I see "a = fac(5)" in some code - can I guess the fuck that means?
Opposed to "a = factorial(5)"... can you grasp the difference that spelling out the function name in full will have on actual readability of your code??

Second point - you name the function argument N. Why? To save yourself some precious time? How about save me some precious reading time? Yeah, you can get away with one-letter variables in mathematic formulas, but this is information technology here. No need to waste the reader's time: the argument to factorial is a natural number, and may be called factor. So I propose this signature:

factorial(factor) ->
   if factor == 0 -> 1;
      true -> factor * factorial(factor - 1)
   end.


Of course, some recursive-by-definition shit is always what you give when you start pimping functional programming. In imperative language I give you this:

def factorial(factor):
	""" computes a factorial of given number """
	result = 1
	while factor > 0:
		result *= factor
		factor -= 1

	return result


It's Python, but you probably can read this even if you have no idea. Just have to point out the indented block under "while" statement is it's body, and is executed in loop: identation makes it the body. And the """ block is built-in documentation string. I care about people who read my code - do you?

On to your next example function signature:


Let's see another case... one we all love, the raise salary example:

raise({Name, Salary}, N) ->
   {Name, Salary * N}.



Ah yes, When I see "raise" I immediately think about salary. NOT! Why can't you spell it out as "raise_salary" ?!?! Will your fingers fall off? Well, for one, I might gouge out my eyes when I read your code, that's for sure! Shit, some psycho might even BREAK your fingers after witnessing your code, so pay attention to what you type.

On to the lovely argument names.

raise_salary( {Name,Salary}, N ) -

So you explain that {Name, Salary} is actually a Person object that you chose to unwrap somehow. Whatever.

And what is N ? Maybe it's dollar amount you are going to raise salary by? When I see code "raise_salary( pupeno, 314 )", what does that spell? Give pupeno 314 dollars? SHIT! I look at the code, I see you are actually multiplying by the amount. That's times multiply! So, why don't you write it out as such? And why would you raise salary SEVERAL TIMES OVER?!

> raise([{"Mickaël", 3000}, {"Yariv", 3000}, {"Joe", 3000}], 2).


Yeah, it's only example, but who told you that you are allowed to make up nonsense examples? How often do you get your salary doubled, anyway? Fuck... would it kill you to spend a minute, and come up with a better idea?

I refuse to follow the craziness, and I am changing the function to add some dollar amount.
raise_salary( {Name,Salary}, add_dollar_amount ) ->
 {Name, Salary + add_dollar_amount}.


Now next is the example with processing a whole list, and with adding some dollars, instead of multiplying.
raise_salary( {Name, Salary}, add_dollar_amount ) ->
   { Name, Salary + add_dollar_amount };
raise_salary( [], add_dollar_amount ) ->
   [];
raise_salary( [Person|Persons], add_dollar_amount ) ->
   [ raise(Person, add_dollar_amount)|raise(Persons, add_dollar_amount) ].


Yeah, here you go, we now got a polymorphich function "raise_salary" where you may give it a list, and it will raise every person salary by the dollar amount given. Well, does it kill you much to type:

"for each Person in Employees: raise_salary( Person, 3.14 )" (in imperative language)?

Let's see - is this more readable than "raise_salary(Employees, 3.14)" ? Which example spells it's intent out better?

And what Erlang code actually does? It pops out first element in list (raises salary of first person in employees list), and then invokes "raise_salary" for the remaining list, and kind of rebuilds the list again later. Whatever.

Alright, the tutorial itself is brilliant, and gives you good insight in how Erlangs pattern matching works, and I hope to god it actually does the little tricks functional programming people say it does (optimizes the shit out of the whole list deconstruction/reconstruction code, etc).

But the attitude I am seeing towards documenting your code, naming your functions, naming your variables, structuring your code, that's what makes me wonder, what you functional programming people are thinking when you revisit your code 2 months later?


(Lasīt komentārus)

Nopūsties:

No:
Lietotājvārds:
Parole:
Ievadi te 'qws' (liidzeklis pret spambotiem):
Temats:
Tematā HTML ir aizliegts
  
Ziņa:

Gandrīz jau aizmirsu pateikt – šis lietotājs ir ieslēdzis IP adrešu noglabāšanu. Operatore Nr. 65.
Neesi iežurnalējies. Iežurnalēties?