Beginner question - should I use ifs or short functions when programming erlang?

Recently, I began to study the book "Programming Erlang", and I have a question. Is the approach lower to Erlang? This (changed for brevity (no exit message), with deleting the log after a basic check) is a solution to the ring problem from ch4. The outputs of the processes after they transmitted the message the estimated number of times; the first process waits until the last message reaches it and exits.

Besides the general criticism of the style and the being, could you please tell me if there are special 1-2 line functions written like this, the correct style, or if you need to use if-s, case-s, etc.

start_ring( 0, _, _ ) -> {error, badarg}; start_ring( _, 0, _ ) -> {error, badarg}; start_ring( M, N, Message ) -> spawn( ring, run_ring, [M, N, Message, 0] ). % last process that connects the ring run_ring( M, 1, Message, Pid ) when is_pid(Pid) -> loop_ring( M, Message, Pid, false ); % process in the middle run_ring( M, N, Message, Pid ) when is_pid(Pid) -> loop_ring( M, Message, spawn( ring, run_ring, [M, N-1, Message, Pid] ), false ); % first process - special case for one process run_ring( M, 1, Message, _ ) -> loop_ring( M, self() ! Message, self(), true ); % first process run_ring( M, N, Message, _ ) -> NextPid = spawn( ring, run_ring, [M, N-1, Message, self()] ), loop_ring( M, NextPid ! Message, NextPid, true ). loop_ring( 0, _, _, _ ) -> ok; loop_ring( 1, Message, Next, true ) -> ok; loop_ring( M, Message, Next, IsMaster ) -> receive Message -> loop_ring( M - 1, Next ! Message, Next, IsMaster ) end. 
+4
source share
2 answers

I think your style is very good and concise! Good job!

A few comments (a matter of personal taste):

  • The starting ring can be rewritten as:

     start_ring( M, N, Message ) when M < N, N > 0, M > 0 -> spawn( ring, run_ring, [M, N, Message, 0] ). 

    If used incorrectly, a crash will occur with a function_clause error. There, a good habit of working with errors returns that if the user can do something reasonable with an error, return, for example, {error, Reason} , otherwise it just fails. I think that in this case it is safe to simply crash, because any other input will be a program error.

  • run_ring/4 + loop_ring/4 : I do not like to use line breaks between functions with several sentences. This makes it difficult to work where the function begins and ends. Comments can then be placed inside the body of the sentence instead of the outer one. Now it becomes much easier to identify the function headers (and see the function as a whole):

     run_ring(M, 1, Message, Pid) when is_pid(Pid) -> % last process that connects the ring loop_ring(M, Message, Pid, false); run_ring(M, N, Message, Pid) when is_pid(Pid) -> % process in the middle loop_ring(M, Message, spawn(ring, run_ring, [M, N-1, Message, Pid]), false); run_ring(M, 1, Message, _) -> % first process - special case for one process loop_ring(M, self() ! Message, self(), true); run_ring(M, N, Message, _) -> % first process NextPid = spawn(ring, run_ring, [M, N-1, Message, self()]), loop_ring(M, NextPid ! Message, NextPid, true). 
  • I personally don't like spaces in parentheses (as I said, personal taste). :-) Makes the code more fluffy.

  • Use spawn_link/3 instead of spawn/3 if you do not know that you do not want it. This greatly facilitates the detection of errors, etc., when you are developing your program.

  • The second loop_ring/4 emits compiler warnings. Use _Message and _Next instead (use them also for the first sentence, this is bonus documentation!)

+7
source

According to Erlang's best practices , if and case should be nested more than two times:

Nested code is code containing case / if / receive within other cases / if / accept applications. This is a bad programming style for writing deeply nested code - code tends to drift down the page to the right and soon becomes unreadable. Try to limit most of your code to a maximum of two indentation levels. This can be achieved by dividing the code into shorter functions.

Also, I think it is a matter of taste to use if/case or a simple pattern matching. Personally, I prefer to use pattern matching rather than if or cases. So you are doing it right if you ask me.

Regarding if and case , you can usually rewrite the first to the last. Someone says:

"always uses case, the if construct is kind of broken."

Well, the two designs work differently. The expression evaluated in the if construct is a defense and has many limitations - due to the fact that you cannot have side effects in guards, evaluating them regardless of the accepted branch. The design of the case does not have this “limitation”. You can use any expression there, the result of which will be matched with the patterns that make up this case.

Possible duplicate:

Erlang style - case vs function pattern matching

+3
source

Source: https://habr.com/ru/post/1342772/


All Articles