Autor Téma: Zajímavé chování funkce  (Přečteno 5296 krát)

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2711
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Zajímavé chování funkce
« kdy: 22-03-2013, 00:11:51 »
Dneska jsem v cizim kodu narazil na zajimave chovani.

Zjednoduseny kod (TestB byl ve skutecnosti scitany string v cyklu pres nejake podminky, ale to je nepodstatne), jde mi o to, zda je definovane chovani,
ja chapu, jak k tomu dojde, ale nikdy by mne to drive nenapadlo.
Kód: Delphi [Vybrat]
  1. program Project3;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. function TestA:string;
  6. begin
  7.   Result := 'A';
  8. end;
  9.  
  10. function TestB:string;
  11. begin
  12.   // simplified
  13.   Result := Result + ';B';
  14. end;
  15.                                
  16. procedure Test;
  17. var
  18.   s: string;
  19. begin
  20.   s := TestA;
  21.   s := testB;
  22.   writeln(s);
  23. end;
  24.  
  25. begin
  26.   Test;
  27. end.
  28.  
  29.  

Vypíše A;B. Jak v D2007, tak v XE3. Je to asi vlastnost, ze?
Embarcadero MVP - Czech republic

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1524
  • Karma: 37
    • Pepak.net
Re:Zajímavé chování funkce
« Odpověď #1 kdy: 22-03-2013, 07:01:21 »
Vypíše A;B. Jak v D2007, tak v XE3. Je to asi vlastnost, ze?
Já bych to spíš označil jako náhodu vzhledem ke kontextu. To nevylučuje, že ta "náhoda" vzniká v podobné situaci pravidelně, ale nelze se na to spoléhat. Respektive, můžeš se vsadit, že když se na ni spolehneš, tak se ti za půl roku, až na ni zapomeneš, vrátí.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3004
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Zajímavé chování funkce
« Odpověď #2 kdy: 22-03-2013, 07:03:38 »
Excellent
Rated 1 time
Dneska jsem v cizim kodu narazil na zajimave chovani.
...
  s := TestA;
  s := testB;
[/code]

Vypíše A;B. Jak v D2007, tak v XE3. Je to asi vlastnost, ze?
Osobne mi to prijde jako desna (nesrozumitelna, strojove zavisla) prasarna, spolehajici na konkretni zpusob, jakym se predavaji parametry do subroutiny.

Ale je to vlastnost, protoze Result je promenna predavana odkazem jako skryty var parametr, takze preklad je ekvivalentni zapisu
Kód: Delphi [Vybrat]
  1. procedure B(var Res:string);
  2. begin
  3.   Res = Res + ';B';
  4. end;
  5.  
coz je strojove totez a kazdemu je na prvni pohled jasne, co to dela a je to strojove nezavisle.

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Zajímavé chování funkce
« Odpověď #3 kdy: 22-03-2013, 08:33:39 »
Mě spíš zaráží, že Delphi při tom kódu nevyhazuje warning.

FPC vypíše:
Kód: Delphi [Vybrat]
  1. Unit1.pas(161,20) Warning: Function result variable does not seem to initialized
  2.  

Delphi nevypíše nic. Nebo se musí zapnout nějaké nastavení?

Jednou se mi podařilo přesně tohle omylem udělat, v Delphi vše fungovalo bez problémů (taky jsem nedostal žádný warning), při portaci do FPC se to chovalo jinak a nemohl jsem na to asi 2 hodiny kápnout, než jsem to v té spoustě warningů, které se při portaci objevily, našel...
Zajímavé ovšem je, že tento konkrétní případ v FPC funguje.
Embarcadero Technology Partner

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2711
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Re:Zajímavé chování funkce
« Odpověď #4 kdy: 22-03-2013, 08:40:36 »
Díky za názory.
No právě, já bych také očekával warning. Jak říkám, byl to cizí kód a čuměl jsem na to jak vyoraný krtek.
Embarcadero MVP - Czech republic

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Zajímavé chování funkce
« Odpověď #5 kdy: 22-03-2013, 09:01:07 »
Já si spíš myslím, že to autor udělal neúmyslně. Takže bych mu to oznámil jako bug.

Přeci jenom takový kód se asi nedá označit jako za okamžitě pochopitelný:

Kód: Delphi [Vybrat]
  1. procedure Test;
  2. var
  3.   s: string;
  4. begin
  5.   s := TestB;
  6.   ShowMessage(s);
  7.   s := TestA;
  8.   s := TestB;
  9.   ShowMessage(s);
  10. end;
  11.  

Jinak teď se mi podařilo vyvolat odlišné chování FPC-Delphi. Zkuste tento kód:
Kód: Delphi [Vybrat]
  1. function TestA:string;
  2. begin
  3.   Result := 'A';
  4. end;
  5.  
  6. function TestB:string;
  7. begin
  8.   // simplified
  9.   Result := Result + ';B';
  10. end;
  11.  
  12. procedure Test;
  13. var
  14.   s: string;
  15. begin
  16.   s := TestA+TestB+TestA+TestB;
  17.   s := TestA;
  18.   s := TestB;
  19.   ShowMessage(s);
  20. end;
  21.  
Lazarus vypíše ";B", Delphi vypíše "A;B". Takže já bych na to dával pozor, fakt se ta chyba špatně hledá (hlavně když je ta funkce dlouhá) :)
Embarcadero Technology Partner

Offline pepak

  • Padawan
  • ******
  • Příspěvků: 1524
  • Karma: 37
    • Pepak.net
Re:Zajímavé chování funkce
« Odpověď #6 kdy: 22-03-2013, 09:07:24 »
Ale je to vlastnost, protoze Result je promenna predavana odkazem jako skryty var parametr, takze preklad je ekvivalentni
Tohle určitě neplatí obecně. Počítám, že by to mohlo platit pro stringy (a možná taky interfacy), ale zcela jistě to neplatí třeba pro třídy nebo čísla v defaultní konvenci register.

A zdráhal bych se jakékoliv chování označit za "vlastnost", pokud není zdokumentované.

Mě spíš zaráží, že Delphi při tom kódu nevyhazuje warning.

FPC vypíše:
Kód: Delphi [Vybrat]
  1. Unit1.pas(161,20) Warning: Function result variable does not seem to initialized
  2.  
FPC obecně má mnohem důkladnější systém warningů než Delphi. Někdy až přehnaně důkladný, ale narazil jsem už na dost konstrukcí, které Delphi tiše přešly, zatímco FPC na nich oprávněně zařval. Tohle bude další podobný případ.

Offline Radek Červinka

  • Administrátoři
  • Padawan
  • *****
  • Příspěvků: 2711
  • Karma: 104
    • Verze Delphi: D2007, DXE + 2 poslední
    • O Delphi v češtině
Re:Zajímavé chování funkce
« Odpověď #7 kdy: 22-03-2013, 09:08:09 »
Konkrétně tento kód z RTL:

Kód: Delphi [Vybrat]
  1. function TDataSet.PSGetKeyFields: string;
  2. var
  3.   i: integer;
  4. begin
  5.   for i := 0 to Fields.Count - 1 do
  6.     if pfInKey in Fields[i].ProviderFlags then
  7.     begin
  8.       if Result <> '' then
  9.         Result := Result + ';';
  10.       Result := Result + Fields[i].FieldName;
  11.     end;
  12. end;
  13.  
Embarcadero MVP - Czech republic

Offline Ondřej Pokorný

  • Guru
  • *****
  • Příspěvků: 815
  • Karma: 59
    • Verze Delphi: Primárně Lazarus, jinak D7 až aktuální
    • Kluug.net
Re:Zajímavé chování funkce
« Odpověď #8 kdy: 22-03-2013, 09:17:25 »
Přesně můj případ - zapomněl jsem vyprázdnit Result na začátku (Result := ''; ).

Ono v Delphi to moc nevadí, protože:
Kód: Delphi [Vybrat]
  1. function TestA:string;
  2. begin
  3.   Result := 'A';
  4. end;
  5.  
  6. function TestB:string;
  7. begin
  8.   // simplified
  9.   Result := Result + ';B';
  10. end;
  11.  
  12. function TestC:string;
  13. begin
  14.   // corrected
  15.   Result := '';
  16.   Result := Result + ';B';
  17. end;
  18.  
  19. procedure Test;
  20. var
  21.   s: string;
  22. begin
  23.   s := '';
  24.   s := TestA;
  25.   s := s+TestB;
  26.   ShowMessage(s);
  27.   s := '';
  28.   s := TestA;
  29.   s := s+TestC;
  30.   ShowMessage(s);
  31. end;
  32.  

vypíše to samé, ale určitě to není to, co autor zamýšlel.
Embarcadero Technology Partner

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3004
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Zajímavé chování funkce
« Odpověď #9 kdy: 22-03-2013, 09:49:08 »
No právě, já bych také očekával warning. Jak říkám, byl to cizí kód a čuměl jsem na to jak vyoraný krtek.
No ty warningy mi pijou krev uz peknou radku let - de facto od D2, kdyz se poprve objevily reference counted typy. A taky jsme to uz nekolikrat na ruznych forech probirali. Warning funguje jen na prostych typech (vcetne normalnich pointeru). Tam prekladac oznami W1035 return value of XXX may be undefined.

Jenomze Bordalandi po pridani reference countent typu pojali kontrolu alibisticky na low level urovni: protoze nemohou nechat promenou odkazujici se na reference counted jen tak, tak ji inicializuji na nil a pak ji z nejakeho nepochopitelneho duvodu berou jako prirazenou a nevaruji  >:(




Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3004
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Zajímavé chování funkce
« Odpověď #10 kdy: 22-03-2013, 10:08:29 »
Tohle určitě neplatí obecně.

A zdráhal bych se jakékoliv chování označit za "vlastnost", pokud není zdokumentované.
atímco FPC na nich oprávněně zařval. Tohle bude další podobný případ.
Samozrejme, ze se to tyka jen reference counted typu viz jiny prispevek o warningach.
A zdokumentovane to samozrejme je v reference guide u Program control:

or a string, dynamic array, method pointer, variant, or Int64 result, the effects are the same as if the function result were declared as an additional var parameter following the declared parameters. In other words, the caller passes an additional 32-bit pointer that points to a variable in which to return the function result.

Samozrejme se to vztahuje k Delphi a ne k Lazaru - o nem nic nevim, ale z podstaty veci bych nepredpokladal, ze by se to tam melo chovat stejne.

Offline Mi.Chal.

  • Guru
  • *****
  • Příspěvků: 576
  • Karma: 25
Re:Zajímavé chování funkce
« Odpověď #11 kdy: 22-03-2013, 11:16:33 »
Díky za názory.
No právě, já bych také očekával warning. Jak říkám, byl to cizí kód a čuměl jsem na to jak vyoraný krtek.

Tohle je spíš error.  Takový kód nemůže dávat jednoznačné výsledky, takže mě nenapadá žádný případ, kdy by téhle featury šlo rozumně využít.

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3004
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Zajímavé chování funkce
« Odpověď #12 kdy: 22-03-2013, 11:33:08 »
Tohle je spíš error.  Takový kód nemůže dávat jednoznačné výsledky, takže mě nenapadá žádný případ, kdy by téhle featury šlo rozumně využít.
To by me zajimalo, z cehoz usuzujes, ze to nemuze davat jednoznacne vysledky  :o (ne ze bych takovou prasarnu obhajobval, ale vzhledem k tomu, ze ten konkretni kod byl v TDatasetu, tak by to klidne mohlo byt z duvodu optimalizace).

Offline vladyk

  • Příspěvků: 32
  • Karma: 0
Re:Zajímavé chování funkce
« Odpověď #13 kdy: 22-03-2013, 11:58:32 »
No, mně přijde, že použití výrazu x:=x+ něco bez předchozí inicializace x bude čuňačina kdekoliv  :) (bez ohledu na to, jak je definováno, ukládáno a předáváno to x)

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3004
  • Karma: 135
    • Verze Delphi: D2007, XE3, DX10
Re:Zajímavé chování funkce
« Odpověď #14 kdy: 22-03-2013, 12:02:10 »
No, mně přijde, že použití výrazu x:=x+ něco bez předchozí inicializace x bude čuňačina kdekoliv  :) (bez ohledu na to, jak je definováno, ukládáno a předáváno to x)
Obecne ano, ale v tomle pripade je x inicializovano prekladacem na nil a stringove knihovny se k tomu chovaji jako k prazdnemu stringu.