Frage zu Code-Schnipsel

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
wennerer
Beiträge: 524
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Frage zu Code-Schnipsel

Beitrag von wennerer »

Hallo,
ich habe da mal eine Frage. In einem Code von wp_xyz habe ich folgende interessante Zeile gefunden über die ich nun schon länger grüble:

Code: Alles auswählen

type
  TSliderDirection = (sdRight, sdLeft);
  .......
  .......
  .......
 procedure TForm1.Button1Click(Sender: TObject);
  begin 
   FSliderDirection := TSliderDirection((ord(FSliderDirection) + 1) mod 2)
 ........
 .......  
   ;
So wie ich das sehe macht dies das Gleiche wie:

Code: Alles auswählen

 if FSliderDirection = sdRight then FSliderDirection := sdLeft else FSliderDirection := sdRight;
Liegt da noch ein für mich verborgener Vorteil in dieser Variante? Oder ist das einfach nur eleganter?

Viele Grüße
Bernd

wp_xyz
Beiträge: 4893
Registriert: Fr 8. Apr 2011, 09:01

Re: Frage zu Code-Schnipsel

Beitrag von wp_xyz »

Zugegeben, mein Code ist schon etwas nerdig... Aber die Idee dafür, einen Nachfolger einer Aufzählung zu finden, wobei am Ende wieder von vorne angefangen werden soll, ist: Nimm den Zahlenwert des Aufzählungselements und erhöhe ihn um die gewünschte Differenz, damit bist du beim gewünschten Element - es sei denn, du hast die Anzahl der Elemente überschritten und musst wieder von vorne anfangen. Deshalb die Division durch die Anzahl der Aufzählungselemente - der Divisionsrest ist immer ein Element der Menge. Zum Schluss kommt dann noch ein Type-Cast, der die Ordnungszahl des gefundenen Elements wieder in den Aufzählungstyp umwandelt.

Bei einer Aufzählung mit zwei Elementen ist dein Code natürlich einfacher und klarer zu verstehen. Interessanter wird's aber, wenn die Menge mehr Elemente enthält. Statt eines ellenlangen "if" oder "case" geht's bei mir in einer Zeile.

Weiß gerade kein gutes Beispiel, aber versuche mal in der Aufzählung TBitBtnKind = (bkCustom, bkOK, bkCancel, bkHelp, bkYes, bkNo, bkClose, bkAbort, bkRetry, bkIgnore, bkAll, bkNoToAll, bkYesToAll) das übernächste Element zu finden...

Code: Alles auswählen

var
  bk: TBitBtnKind;
  new_bk: TBitBtnKind
...
  new_bk := TBitBtnKind((ord(bk)+2) mod (ord(High(TBitBtnKind))+1));  // ok, ich sehe, das ist noch etwas nerdiger...
// oder
  case bk of
    bkCustom: new_bk := bkCancel;
    bkOK: new_bk := bkHelp;
    bkCancel: new_bk := bkYes;
    bkHelp: new_bk := No;
    bkYes: new_bk := bkClose;
    bkNo: new_bk := bkAbort;
    bkClose: new_bk := bkRetry;
    bkAbort: new_bk := bkIgnore;
    bkRetry: new_bk := bkAll;
    bkIgnore: new_bk := bkNoToAll;
    bkAll: new_bk := bkYesToAll;
    bkNoToAll: new_bk := bkCustom;
    bkYesToAll := new_bk := bkOK;
  end; 

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Frage zu Code-Schnipsel

Beitrag von Socke »

Wie wäre es damit?
Ich fände es lesbarer und es ist unabhängig von der exakten Anzahl der Elemente in der Aufzählung. Soweit ich mich erinnere, funktioniert es aber nur für lückenlose Aufzählungen, während die mathematische Lösung zumindest auch für feste Wertabständen angepasst werden kann.

Code: Alles auswählen

var
  bk: TBitBtnKind;
  new_bk: TBitBtnKind
begin
  if bk = high(TBitBtnKind) then
    new_bk:=low(TBitBtnKind)
  else
    new_bk:=succ(bk);
end;
Die Bedingungen können sich natürlich nachteilig auf die Laufzeit auswirken, während die wp_xyzs mathematische Umsetzung eine konstante Laufzeit hat.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

wennerer
Beiträge: 524
Registriert: Di 19. Mai 2015, 20:05
OS, Lazarus, FPC: Linux Mint 20 Cinnamon,Lazarus 2.2.6 (rev lazarus_2_2_6) FPC 3.2.2 x86_64-linux-
CPU-Target: x86_64-linux-gtk2

Re: Frage zu Code-Schnipsel

Beitrag von wennerer »

Hallo,
vielen Dank euch beiden für die Antworten.
Daran das man auch mehrere Aufzählungselemente durchlaufen möchte habe ich gar nicht gedacht. Aber irgendwie war mir klar das da noch eine Idee dahinter steckt.
Ich hab es für mich mal mit Farben probiert um es besser testen zu können. Ich finde es genial.

Wer es testen möchte:

Code: Alles auswählen

unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls;

type TMyColors = (myWhite,myRed,myGreen,myBlue,myYellow,myBlack,myLime);

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    Shape1: TShape;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    procedure ShowTheColor;

  public
     myColor  : TMyColors;

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }
procedure TForm1.ShowTheColor;
begin
 case ord(myColor) of
 0 : Shape1.Brush.Color := clWhite;
 1 : Shape1.Brush.Color := clRed;
 2 : Shape1.Brush.Color := clGreen;
 3 : Shape1.Brush.Color := clBlue;
 4 : Shape1.Brush.Color := clYellow;
 5 : Shape1.Brush.Color := clBlack;
 6 : Shape1.Brush.Color := clLime;
 end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 myColor := TMyColors((ord(myColor) + 1) mod 7);
 ShowTheColor;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 myColor := TMyColors((ord(myColor) + 2) mod 7);
 ShowTheColor;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 if myColor = high(TMyColors) then
    myColor:=low(TMyColors)
  else
    myColor:=succ(myColor);
 ShowTheColor;
end;

end.
Viele Grüße
Bernd
Dateianhänge
project1.zip
(139.8 KiB) 90-mal heruntergeladen

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Frage zu Code-Schnipsel

Beitrag von Mathias »

Da wollte ich gerade was probieren,
Aber es kommt nur "Type mismatch".

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
type
  TMyColors = (myWhite,myRed,myGreen,myBlue,myYellow,myBlack,myLime);
begin
  Caption := Length(TMyColors).tostring;
end;
Gibt es eine Möglichkeit die Grösse von TMyColors zu ermitteln ?

Einzig was mir da in den Sinn kommt, so wie es der C Programmierer mit enum macht.

Code: Alles auswählen

type
  TMyColors = (myWhite,myRed,myGreen,myBlue,myYellow,myBlack,myLime,count);
begin
  Caption :=Integer(count).ToString;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Frage zu Code-Schnipsel

Beitrag von Socke »

Mathias hat geschrieben:
Di 5. Dez 2023, 08:43
Da wollte ich gerade was probieren,
Aber es kommt nur "Type mismatch".

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
type
  TMyColors = (myWhite,myRed,myGreen,myBlue,myYellow,myBlack,myLime);
begin
  Caption := Length(TMyColors).tostring;
end;
Gibt es eine Möglichkeit die Grösse von TMyColors zu ermitteln ?
Wenn deine Aufzählung keine Lücken hat, kannst du mit low(EnumType) und high(EnumType) das ordinal niedrigste und höchste Element ermitteln. Daraus kannst du wiederum die Anzahl der Elemente bestimmen.

Wenn du Lücken in der Aufzählung hast, musst du die einzeln abzählen.

Code: Alles auswählen

type
  TMyEnum = (first= 10, second = 20, third = 23);
Die funktionen pred() und succ() konnten soweit ich weiß nur mit lückenlosen Aufzählungen umgehen, da einfach 1 addiert wurde. Ob das immer noch der Fall ist, lässt sich aus der Dokumentation nicht entnehmen.
Hier kann aber die Run Time Type Information aushelfen, da darüber alle Elemente ermittelbar sind - auch wenn das deutlich höhere Laufzeiten hat.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Frage zu Code-Schnipsel

Beitrag von Mathias »

Etwas vermisse ich bei den Pascal Enums, was in C geht und zwar folgendes:

Code: Alles auswählen

int main () {
  enum Buffer_IDs { VertexBuffer, ColorBuffer, NumBuffers };  
  int Buffers[NumBuffers];

  Buffers[VertexBuffer] = 123;
}
Die versucht ich schon so auf Pascal umzusetzen, nur scheitert er schon in der var-Deklaration.
Ach dies nach dem begin geht nicht.

Code: Alles auswählen

type
  TBuffer_IDs = (VertexBuffer, ColorBuffer, NumBuffers);
var
  Buffers: array [0..NumBuffers - 1 ] of integer;

begin
  Buffers[VertexBuffer] := 123;
end.   
Gibt es da in Pascal auch so was elegante wie in C oder geht da nur der Umweg über const ?

Code: Alles auswählen

const
  VertexBuffer = 0;
  ColorBuffer = 1;
  NumBuffers = 2;
var
  Buffers: array [0..NumBuffers - 1] of integer;
begin
  Buffers[VertexBuffer] := 123;
end.   
Was natürlich nicht elegant ist, wen man in der Enum einen Wert ergänzen will.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Frage zu Code-Schnipsel

Beitrag von Socke »

Es geht, die Syntax ist aber anders:

Code: Alles auswählen

type
  TBuffer_IDs = (VertexBuffer, ColorBuffer, NumBuffers);
var
  Buffers: array [TBuffer_IDs] of integer;

begin
  Buffers[VertexBuffer] := 123;
end.   
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

wp_xyz
Beiträge: 4893
Registriert: Fr 8. Apr 2011, 09:01

Re: Frage zu Code-Schnipsel

Beitrag von wp_xyz »

Socke hat geschrieben:
Di 5. Dez 2023, 09:06
Die funktionen pred() und succ() konnten soweit ich weiß nur mit lückenlosen Aufzählungen umgehen...
Ja, ich habe das Gefühlt, da hat der Entwickler (Delphi?) nicht zu Ende gedacht:

Code: Alles auswählen

program Project1;

type
  TMyEnum = (first = 1, second = 2, tenth = 10, last = 100);
var
  e: TMyEnum;
begin
  e := second;
  //WriteLn(succ(e), ' = ', ord(succ(e)));  // <--- Kompiliert nicht: "succ or pred on enums with assignments not possible"

  WriteLn(e, ' = ', ord(e));
  WriteLn(Low(TMyEnum), ' = ', ord(Low(TMyEnum)));
  WriteLn(High(TMyEnum), ' = ', ord(High(TMyEnum)));

  ReadLn;
end. 
Daraus lerne ich: ord liefert nicht die Ordnungszahl, sondern den zugeordneten Zahlenwert. succ und pred gehen nicht -- wie soll man da bitte von Element zu Element laufen? Auch eine Bestimmung der Anzahl der Aufzählungselemente mit Hilfe von High geht nicht, denn High liefert wieder den zugeordneten größten Zahlenwert.

Also: ziemlich nutzlos, diese Konstruktion...

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Frage zu Code-Schnipsel

Beitrag von Mathias »

Socke hat geschrieben:
Di 5. Dez 2023, 17:55
Es geht, die Syntax ist aber anders:

Code: Alles auswählen

type
  TBuffer_IDs = (VertexBuffer, ColorBuffer, NumBuffers);
var
  Buffers: array [TBuffer_IDs] of integer;
begin
  Buffers[VertexBuffer] := 123;
end.   
Danke, dies habe ich gesucht. Und erst noch eleganter als die C-Version.
Ich konnte es sogar vereinfachen.

Code: Alles auswählen

var
  Mesh_Buffers: array [(VBO, VBOColor, VBONormal, VBOJoint, UBO)] of TGLuint;
 begin
  glGenBuffers(Length(Mesh_Buffers), Mesh_Buffers);
  ...
  glBindBuffer(GL_UNIFORM_BUFFER, Mesh_Buffers[UBO]); 
Dies funktioniert aber nur solange, wen man keine forto-Schleife braucht.
Ansonsten sehe ich keine Alternative zu als der Umweg über type.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Socke
Lazarusforum e. V.
Beiträge: 3158
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Frage zu Code-Schnipsel

Beitrag von Socke »

Mathias hat geschrieben:
Mi 6. Dez 2023, 13:59
Dies funktioniert aber nur solange, wen man keine forto-Schleife braucht.
Ansonsten sehe ich keine Alternative zu als der Umweg über type.
Was meinst du konkret damit?
Du kannst problemlos über alle Aufzählungselemente iterieren:

Code: Alles auswählen

var
  x: TAlign;
begin
  for x := low(x) to high(x) do
  begin

  end;
end; 
Du kannst die Funktionen low() und high() auch auf einen Array anwenden und dann über alle Array-Indizes iterieren.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Mathias
Beiträge: 6208
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Frage zu Code-Schnipsel

Beitrag von Mathias »

Was meinst du konkret damit?
Ohne Umwege über type, den sowas geht nicht:

Code: Alles auswählen

var
  Mesh_Buffers: array [(mbVBO, mbVBOColor, mbVBONormal, mbVBOJoint, mbUBO)] of integer;
begin
  for Mesh_Buffers := Low(Mesh_Buffers) to High(Mesh_Buffers) do begin
    WriteLn();
  end;   
Du kannst problemlos über alle Aufzählungselemente iterieren:
Nur der Umweg über einen type geht:

Code: Alles auswählen

type
  TBuffer = (mbVBO, mbVBOColor, mbVBONormal, mbVBOJoint, mbUBO);
var
  Mesh_Buffers: array [TBuffer] of integer;
  x:TBuffer;
begin
  for x := Low(x) to High(x) do begin
    WriteLn(Integer(x));
  end;    
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten