momente şi schiţe de informatică şi matematică
To attain knowledge, write. To attain wisdom, rewrite.

Şablonul "return 0; ELSE return 1" (mot-à-mot din Pascal în C)

Pascal | Pascal versus C
2008 dec

Am evocat în Informatica evoluează, învăţământul nu! o discuţie de genul Aşa ne-a zis Domnu' profesor, în legătură cu care m-am simţit… vinovat de exagerare - în fond ar fi doar un caz izolat, ceva neatenţie şi-atât. Dar iată că avem un întreg manual oficial, "Informatică - Manual pentru clasa a XI-a", Ed. CORINT 2006, autori: Mioara Gheorghe, Monica Tătărâm, Corina Achinca, Constanţa Năstase - în care apare peste tot (şi fără nici o discuţie) sintagma if (...) return (...); else return (...);.

În acest manual există un capitol SUBPROGRAME (de 80 de pagini) care tratează "Modularizarea programelor", "IMPLEMENTAREA MODULARIZĂRII. STIVA SISTEM", "Comunicarea între module", "Apelarea subprogramelor", "Fluxul de execuţie", etc. cu exemple şi ilustraţii potrivite - în pseudocod, în Pascal şi în C - şi cu fel de fel de Definiţii, Atenţionări şi Reguli (am păstrat denumirile şi scrierea cu majuscule… specifică manualului respectiv).

În treacăt, zicem şi aici că n-ar trebui să mai fie astăzi nici o îndoială: despre "subprograme" trebuie să se înveţe de la bun început, dintr-a IX-a deci (şi nicidecum, într-a XI-a!).

Cu "Definiţiile" şi cu "regulile" nu putem fi de acord: ele pot fi valabile pentru pseudocod şi pentru Pascal (şi… pentru BAC desigur), dar sunt destule alte limbaje în care nu sunt valabile! Şi odată impuse asemenea definiţii şi reguli nenuanţate, va fi greu de acceptat mai departe că o funcţie Javascript (sau o subrutină Perl, etc.) poate "conţine" o altă funcţie (mai nou, nici C++ nu-i străin de această idee).

După ce se discută aşa de amănunţit şi temeinic (se şi cuvine! Numai că… nu la clasa a XI-a, ci de la bun început - fiindcă "funcţie" este conceptul esenţial şi la Matematică şi la Informatică şi trebuie să stea la baza formării unui programator), despre subprograme, despre "fluxul execuţiei" şi desigur despre return - la pagina 123 este formulată această funcţie C:

     long fact(int n)
     { int i;
       if(!n) return 1;
       else
          return n*fact(n-1);
     }

Să ignorăm faptul că declaraţia "int i;" nu are sens în cadrul acestei funcţii (totuşi, ar trebui să fie clar că programele redate într-un manual trebuie să constituie modele, inclusiv în privinţa stilului de scriere). Însă formularea if(!n) return 1; else return n*fact(n-1); trădează neînţelegerea "fluxului execuţiei" (în pofida clamării pe parcursul capitolului).

Chiar şi formulările din manual care însoţesc explicativ funcţia redată mai sus, ar fi în măsură să lămurească lucrurile: "În corpul subprogramului recursiv există unul sau mai multe teste prin care se verifică condiţiile de ieşire din autoapelul recursiv. Aceste teste de ieşire formează condiţia de oprire." (am încheiat citatul; sublinierile îmi aparţin). Cu alte cuvinte, în momentul îndeplinirii condiţiei de oprire n = 0 se va executa return 1; - determinând "ieşirea din autoapelul recursiv"; ieşire înseamnă implicit şi că se vor ignora toate instrucţiunile scrise după if(!n) return 1; - acestea vor fi executate numai dacă nu s-a atins situaţia de oprire. Formularea corectă ar fi aceasta:

     long fact (int n) {
          if(!n) return 1;
          return n * fact(n-1);
     }

sau mai scurt (s-o fi întâlnit şi "operatorul condiţional" pe la clasa a IX-a…):

     long fact (int n) {
          return n ? n * fact(n-1) : 1;
     }

iar aceste ultime formulări sunt valabile (cu nuanţe sintactice nesemnificative) în javascript, în PHP, în Perl şi în multe alte limbaje (a… da - şi manualul respectiv se referă la alte limbaje, anume la "limbajele inteligenţei artificiale").

De ce greşeşte…?

Întrebarea ţine desigur de o "deformaţie profesională": de ce greşeşte cutare (elevul)?

În cazul de faţă ar fi chiar interesant de stabilit "de ce", fiindcă sintagma greşită if(...) return 1; else return 0; este întâlnită în toate formulările de funcţii recursive existente în manual. Şi intuim răspunsul, prin comparaţie:

     LIMBAJUL PASCAL:
          function fibo(n: integer): integer;
          begin
          if n > 1 then fibo := fibo(n-1) + fibo(n-2)
                   else fibo := 1;
          end;

     LIMBAJUL C/C++:
          int fibo(int n)
          {
          if(n > 1)
             return (fibo(n-1) + fibo(n-2));
          else
             return 1;
          }

Manualul respectiv vizează în paralel limbajul Pascal şi limbajul C/C++ (şi pseudocodul… excesiv). Ideea de a viza împreună mai multe limbaje de programare este excelentă, dar "realizarea" ei în acest manual este… "în paralel": programele redate în C/C++ nu sunt altceva decât traduceri mot-à-mot ale programelor Pascal respective.

Şi cum în Pascal nu avem o instrucţiune return, devine obligatorie formula if n > 1 then fibo := ... else fibo := ..., care prin traducere mot-à-mot conduce desigur la formularea principial greşită if(n > 1) return ...; else return ....

Dacă mai observăm şi greşeli de genul fibo := fibo(n-1) + fibo(n-2) (formulă în care nu se are în vedere ce înseamnă "integer" - vezi Rangul elementului din mijloc)
Manualul acesta o fi bun ca "pregătire pentru bacalaureat" - sau mă rog, "pentru BAC" (care mizează în continuare pe pseudocod, Pascal sau C/C++ la fel de izolate între ele ca şi în manual, la fel de lipsite de legătură cu calculatorul sau cu sistemul de operare ca şi în manual); dar în nici un caz nu poate servi ca manual de Informatică pentru profilul Matematică-Informatică (decât doar de formă, nicidecum ca vreo bază de studii ulterioare BAC-ului; sau cumva… BAC-ul o fi scopul final pentru învăţământul nostru liceal?! - după care fiecare o ia de la capăt, încercând să scape de tâmpeniile şi de obiceiurile proaste care l-or fi pregătit pentru BAC şi încercând să înceapă să priceapă despre ce este vorba).

vezi Cărţile mele (de programare)

docerpro | Prev | Next