Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Optimierung oder Compilerfehler oder was? (https://www.delphipraxis.net/197073-optimierung-oder-compilerfehler-oder.html)

Rainer Wolff 16. Jul 2018 12:51

Delphi-Version: 10.2 Tokyo

Optimierung oder Compilerfehler oder was?
 
Hallo,

ich habe in einem Unit-Test folgenden Code (auskommentierte Zeilen wurden für Debugging eingefügt):

Code:
procedure TestTTyp.TestProgrammZurrschiene;
var
  Stanzprogramm240, Stanzprogramm840:TEinzelSchrittlist;
  count: Integer;
  z240,z840: Integer;
begin
  SetupStandardBlech;

//  z240:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']].Count;
//  z840:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']].Count;

  count:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']].Count+
         FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']].Count;

//  count:=z240+z840;
  assert.areEqual(FTypList[0].ZurrschienenList.Count, Count);
FilteredEinzelschritte ist eine indexed property, die folgende Funktion aufruft:

Code:
function TTyp.GetFilteredEinzelschrittlist(Filter: TWerkzeug): TEinzelSchrittlist;
var
  I, j: Integer;
begin
  FFilteredStanzprogramm.Clear;
  for I := 0 to GesamtSchrittlist.Count - 1 do
  begin
    for j := 0 to GesamtSchrittlist[i].EinzelschrittList.Count - 1 do
    begin
      if FGesamtSchrittlist[i].EinzelschrittList[j].Werkzeugname=Filter.Name then
        FFilteredStanzprogramm.Add(FGesamtSchrittlist[i].EinzelschrittList[j])
    end;
  end;

  result:=FFilteredStanzprogramm;
end;
Es gibt also eine Liste von Bearbeitungsschritten in einem Ablauf, die einzelnen Schritte verwenden unterschiedliche Werkzeuge (Werkzeuge=Objekte mit Namen und weiteren Eigenschaften).
Die Funktion soll mir aus der Gesamtliste die Schritte heraussuchen, die ein Werkzeug mit einem bestimmten Namen verwenden. Diese werden dann in eine zweite Liste eingefügt.
Meine Test-Liste enthält 3 x das Werkzeug Zurr_240 und 2 x das Werkzeug Zurr_840.
count sollte also im Test die Summe 5 ergeben, tatsächlich kommt aber jetzt 4 zurück.

Wenn ich im Debugger nachschaue, bzw. im Programm die Befehle aufsplitte, wie im auskommentierten Quelltext zu sehen, erhalte ich wieder das richtige Ergebnis.

Lief unter älteren Delphi-Versionen bisher auch. Nun habe ich das Projekt auf Tokyo 10.2.3 aktualisiert und bekomme das Problem.

Uwe Raabe 16. Jul 2018 13:09

AW: Optimierung oder Compilerfehler oder was?
 
Ich kann es nicht wirklich erklären, aber ich habe eine Vermutung.

Innerhalb GetFilteredEinzelschrittlist ändert sich die (vermutlich klassen-lokale) Instanz FFilteredStanzprogramm. Eventuell wird da schon der zweite Aufruf getätigt, bevor der erste seinen Count abgeholt hat? Wie gesagt, ich kann es nicht wirklich erklären, aber das kommt mir halt verdächtig vor.

Das entspräche dann in etwa diesem Code:
Delphi-Quellcode:
  Stanzprogramm240:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']];
  Stanzprogramm840:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']];
  count := Stanzprogramm240.Count + Stanzprogramm840.Count;

Fritzew 16. Jul 2018 14:04

AW: Optimierung oder Compilerfehler oder was?
 
Ich denke da hat Uwe recht, so wie es aussieht wird der Aufruf der
FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['xxx']].Count erst nach dem 2. Aufruf der function ausgewertet und nicht
temporär zwischengespeichert. Eventuell eine "Optimierung" im Compiler.
Was aber wieder mal zeigt das man nicht auf Unit-Test verzichten kann.

MichaelT 16. Jul 2018 14:09

AW: Optimierung oder Compilerfehler oder was?
 
Müsste man die Aufrufe mal vertauschen zuerst 840 hernach 240 und schauen ob die Einzelaufrufe auch in dem Fall dasselbe Ergebnis liefern.

Zitat:

Zitat von Rainer Wolff (Beitrag 1407404)
Lief unter älteren Delphi-Versionen bisher auch. Nun habe ich das Projekt auf Tokyo 10.2.3 aktualisiert und bekomme das Problem.


himitsu 16. Jul 2018 14:16

AW: Optimierung oder Compilerfehler oder was?
 
Wenn es wirklich an der Optimierung liegt, dann den Code anpassen
oder notfalls ein http://docwiki.embarcadero.com/RADSt...erung_(Delphi) drumrum, bzw. an den Anfang der Unit.

MichaelT 16. Jul 2018 14:32

AW: Optimierung oder Compilerfehler oder was?
 
Mir kommt das
Delphi-Quellcode:
result:=FFilteredStanzprogramm;
ein wenig seltsam vor.

Vor dem Addieren wird die Value vom FFilteredStandprogramm gezogen und zumal ein Clear im Code steht liegt die Vermutung nahe, dass die Liste dieselbe ist.

Aus der Sicht des Compilers ist .Value call an sich identisch.

D.h. würde man die beiden Aufrufe vertauschen müsste 6 rauskommen.


Zitat:

Zitat von himitsu (Beitrag 1407412)
Wenn es wirklich an der Optimierung liegt, dann den Code anpassen
oder notfalls ein http://docwiki.embarcadero.com/RADSt...erung_(Delphi) drumrum, bzw. an den Anfang der Unit.


Rainer Wolff 16. Jul 2018 14:44

AW: Optimierung oder Compilerfehler oder was?
 
Zitat:

Zitat von MichaelT (Beitrag 1407413)
Mir kommt das
Delphi-Quellcode:
result:=FFilteredStanzprogramm;
ein wenig seltsam vor.

Vor dem Addieren wird die Value vom FFilteredStandprogramm gezogen und zumal ein Clear im Code steht liegt die Vermutung nahe, dass die Liste dieselbe ist.

Aus der Sicht des Compilers ist .Value call an sich identisch.

D.h. würde man die beiden Aufrufe vertauschen müsste 6 rauskommen.


Zitat:

Zitat von himitsu (Beitrag 1407412)
Wenn es wirklich an der Optimierung liegt, dann den Code anpassen
oder notfalls ein http://docwiki.embarcadero.com/RADSt...erung_(Delphi) drumrum, bzw. an den Anfang der Unit.


Beim Vertauschen der Anweisungen kommt tatsächlich auch 6 als Ergebnis heraus.

Für die Liste war es ja auch so gedacht, dass diese immer die selbe ist, dann brauche ich die nicht immer erzeugen und freigeben, nur der Listeninhalt soll sich ändern. Die Liste wird im constructor von TTyp einmalig erzeugt:
Code:
  FFilteredStanzprogramm:=TEinzelSchrittlist.Create;
  FFilteredStanzprogramm.OwnsObjects:=False;
und bei Programmende wieder freigegeben.

Optimierung war für das ganze Testprojekt eigentlich sowieso schon deaktiviert, auch die Compiler-Direktiven ändern nix am Ergebnis.

Rainer Wolff 16. Jul 2018 14:58

AW: Optimierung oder Compilerfehler oder was?
 
und gerade explizit noch einmal ausprobiert:

unter Berlin läuft der selbe Test durch.

Fritzew 16. Jul 2018 15:03

AW: Optimierung oder Compilerfehler oder was?
 
Der Compiler erzeugt ungefähr:
Delphi-Quellcode:
// Ursprung  
count:=FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']].Count+
         FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']].Count;
         
//Nur Schema: Also macht der Compiler ungefähr das:
   lTemp1 : TFilteredStanzprogramm = FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']];
   lTemp2 : TFilteredStanzprogramm FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']];
   Count := lTemp1.Count + lTemp2.Count;
//   Und da beide Ltemps auf das gleich Object zeigen.....
Sieht aus wie ein Compilerfehler, wobei ich jetzt schon weiss was dabei rauskommt: 'Works as designed'
Es ist soweit ich es kenne nicht dokumentiert was der Compiler da macht, oder machen darf...

MichaelT 16. Jul 2018 15:06

AW: Optimierung oder Compilerfehler oder was?
 
Ist auch kein Vorwurf. Die Idee ist schon ok. Mit wundert eher, dass das jemals funktioniert hat.

Stellt sich die Frage ob sich was im Fall der Zuweisung.

Delphi-Quellcode:

FTypList[0].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_240']].Value + FTypList[1].FilteredEinzelschritte[gWkz.Werkzeug['Zurr_840']].Value;
sofern genug Platz vorhanden ist etwas ändert.

Dann ist es der 'Iterator' und der Compiler durchaus 'intelligent'. Wobei ich nicht vermute dass sich viel ändert. Es könnte aber genügen wenn sich die Adresse der Referenz mit deren Hilfe .Value wird aufgerufen ändert.

Du hast zwei Iteratorobjekte auf einer Liste laufen. Du willst die Summe über beide.

Ansonsten macht das Programm genau was du geschrieben hast. Du hast geschrieben. Hole das Erste Ergebnis, lösche die Liste, hole das zweite Ergebnis aus der selben Liste und addiere.

Das Ergebnis kommt als Referenz zurück und wird nicht auf einen Stack geknallt. Aktueller Objektzustand und davon Value und das addieren.

Ich habe immer separate Objekte gehalten und die Value war immer aktuell ermittelte Summe (abklappern).



Alle Zeitangaben in WEZ +1. Es ist jetzt 23:20 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz