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?


(Ierakstīt jaunu komentāru)


[info]smejmoon
2006-08-29 15:34 (saite)
1) matemātiskajās funkcijās tiešām ir normāli saukt mainīgos par N; N probably stands for a 'number'. Mani reāli kaitina matemātiķu impotence šajā jautājumā, bet tāda ir šī kultūra un autors neiebrauc tajā, ka vārdiem kodā vajadzētu atbilst apzīmējumiem jomā, kurai šis kods kalpo.
2) autors nedaveda savu domu līdz rezultātam, piemēram:

class Person(object):
  def raise_salary(person, add=0, multiply=1):
    """Raise salary of person. 
       Optional arguments: add - ammount in USD that will be added to salary; 
                           multiply - ammount by which salary will be multiplied.
       If no arguments will be passed, salary will remain the same.

    """
    person.salary += add
    person.salary *= multiply



Pārāk samocīti izskatās tie rezultējošie piemēri. Manā piemērā lietojums būtu:

phb.raise_salary(multiply=5)
wally.raise_salary(add=5)

3) Ok, šeit sāku domāt par naudas vienībām, kas pieskaitīšanas gadījumā ir svarīgas, bet tas jau priekš tutoriāļa būtu par daudz... :)

(Atbildēt uz šo) (Diskusija)


[info]watt
2006-08-29 16:03 (saite)
ir viedoklis, ka amount rakstās ar vienu m

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]smejmoon
2006-08-29 16:46 (saite)
piekrītu

(Atbildēt uz šo) (Iepriekšējais)


[info]barvins
2006-08-29 17:09 (saite)
Cilvēki samācās nelāgus paradumus jau skolā risinot vienādojumus ar x, y un z - gan tāpēc, ka skolās pārsvarā risina abstraktas problēmas, līdz ar to mainīgajiem nemaz nevar būt aprakstoši nosaukumi (varbūt, vienīgi, fizikā), gan tādēļ, ka uz papīra vai tāfeles taču intellisense nepalīdz uzrakstīt garus vārdus.

(Atbildēt uz šo)


Neesi iežurnalējies. Iežurnalēties?