Zusammenspiel von Units

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Antworten
LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Zusammenspiel von Units

Beitrag von LazProgger »

Ich hoffe, dass ich mein Problem halbwegs verständlich machen kann:

Ich habe einige Units, die ich in mehreren Programmen verwenden möchte und programmspezifische Units, die nur für ein Programm gelten.

Die programmübergreifenden Units habe ich alle in einen Ordner gepackt und es funktioniert auch wunderbar, diese aufzurufen.

Ein Problem taucht jetzt bei einer programmübergreifenden Unit, die allerdings auf eine programmspezifische Unit zugreifen muss. Dazu habe ich in den USES-Abschnitt der programmübergreifenden Unit die programmspezifische Unit eingefügt.

Dies hat zunächst Probleme mit dem Compiler verursacht. Immer hieß es, die Unit kann nicht gefunden werden, wenn man auf die Unit mit der Maus geklickt hat, stimmte aber die Referenz. Im Endeffekt habe ich es zum laufen bekommen, indem ich beide Units in die LPR-Datei geschrieben habe.

Dazu meine erste Frage: Welche Besonderheit hat der USES-Abschnitt in der LPR-Datei, wieso funktioniert damit die Referenzierung und ansonsten nicht?

Meine zweite Frage betrifft generell das Design der Units in diesem Fall. Ich finde diese Referenzierung nicht wirklich optimal (programmübergreifende Unit greift auf programmspezifische Unit zu). Gibt es hier Möglichkeiten, wie man das Problem besser lösen kann? Eine Idee wäre es gewesen, eine Funktion in der programmübergreifenden Unit zu definieren, die dann dynamisch die Informationen aus der programmspezifischen Unit holt. Mit dieser Lösung kann man zwar auf die Referenz verzichten, aber wirklich praxistauglich ist das ja auch nicht. Hat jemand eine Idee?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2639
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Zusammenspiel von Units

Beitrag von m.fuchs »

Mal angesehen von deinem eigentlichen Problem:
LazProgger hat geschrieben:Ein Problem taucht jetzt bei einer programmübergreifenden Unit, die allerdings auf eine programmspezifische Unit zugreifen muss.

Wenn eine Unit von einer Programmübergreifenden Unit benutzt wird, muss sie wohl per Definition auch programmübergreifend sein.

Oder ist das pro Projekt eine eigene Unit, die aber immer dne gleichen Namen trägt? Das klingt dann erstmal wie ein suboptimales Design. Beschreib doch mal ein bisschen genauer worum es geht.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

m.fuchs hat geschrieben:Oder ist das pro Projekt eine eigene Unit, die aber immer dne gleichen Namen trägt? Das klingt dann erstmal wie ein suboptimales Design. Beschreib doch mal ein bisschen genauer worum es geht.


Ja, genau das suboptimale Design ist das Problem.

Jedes Projekt hat eine Unit mit dem gleichen Namen, die dann in der programmübergreifenden Unit verwendet wird. Diese Unit unterscheidet sich je nach Projekt, die Namen der Funktionen innerhalb der Unit etc sind gleich, aber die Inhalte verschieden und programmspezifisch.

Dass dieses Design nicht besonders toll ist war Anlass meiner Frage, wie man das besser lösen könnte. Ungern würde ich die programmübergreifenden Funktionen in jede programmspezifische Unit kopieren, weil man dann natürlich Probleme bei der Wartung bekommt.

Konkret geht es hauptsächlich darum, dass in der programmspezifischen Unit ein Array mit Werten gefüllt wird, der dann in der programmübergreifenden Unit gebraucht wird. In der programmübergreifenden Unit gibt es genau dasselbe nochmal, dann nur eben mit programmübergreifenden Werten und Arrays.

Normalerweise würde ich in solch einem Fall den Array einfach komplett an die andere Unit übergeben, das geht in diesem Fall aber vor allen Dingen deswegen nicht, weil die Indices des Arrays als Konstanten in der programmspezifischen Unit definiert sind und in jedem Programm sind dies andere Konstanten. Und diese Konstanten brauche ich eben auch in der programmübergreifenden Unit. Ohne diese Anforderung wäre es natürlich relativ einfach zu lösen. Außerdem kann sich die Belegung des Arrays dynamisch ändern und ich möchte ungern den Array zweimal im Speicher haben (deswegen diese vermurkste Lösung bisher).

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: Zusammenspiel von Units

Beitrag von Socke »

LazProgger hat geschrieben:Jedes Projekt hat eine Unit mit dem gleichen Namen, die dann in der programmübergreifenden Unit verwendet wird. Diese Unit unterscheidet sich je nach Projekt, die Namen der Funktionen innerhalb der Unit etc sind gleich, aber die Inhalte verschieden und programmspezifisch.

Die übergreifende Unit definiert Prozedurtypen und Variablen, die mit Prozeduren dieser Typen gefüllt werden können.

Code: Alles auswählen

unit uebergreifend;
interface
type
  tmyarray = array of integer;
  tmyinitproc = procedure(var arr: tmyarray);
 
var
  initproc: tmyinitproc = nil;
 
procedure DoTheInitProc(var arr: tmyarray);
 
implementation
 
procedure DoTheInitProc(var arr: tmyarray);
begin
  // array befüllen
  setlength(arr, 3);
  arr[0] := 0;
  // aus programmspezifischer Unit aufrufen.
  if Assigned(initproc) then
    initproc(arr);
end;
end.

Code: Alles auswählen

unit spezifisch;
interface
uses uebergreifend;
 
procedure MyAppInitProc(var arr: tmyarray);
 
implementation
 
procedure MyAppInitProc(var arr: tmyarray);
begin
  // Array programmabhängig initialisieren
  setlength(arr, 5);
  arr[0] := 3;
end;
 
initialization
  // Prozedur der übergreifenden Unit bekannt machen
  uebergreifend.initproc := @MyAppInitProc;
end.

Falls das viel mehr Prozeduren werden, können Interfaces oder Records, die die Variablen zusammenfassen, verwendet werden.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2639
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Zusammenspiel von Units

Beitrag von m.fuchs »

LazProgger hat geschrieben:Normalerweise würde ich in solch einem Fall den Array einfach komplett an die andere Unit übergeben, das geht in diesem Fall aber vor allen Dingen deswegen nicht, weil die Indices des Arrays als Konstanten in der programmspezifischen Unit definiert sind und in jedem Programm sind dies andere Konstanten. Und diese Konstanten brauche ich eben auch in der programmübergreifenden Unit.

Hm, genau daran wird es scheitern.

Was für Konstanten sind das denn? Ich glaube immer noch nicht, dass es wirklich notwendig ist, auf diese Weise vorzugehen.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

m.fuchs hat geschrieben:Was für Konstanten sind das denn? Ich glaube immer noch nicht, dass es wirklich notwendig ist, auf diese Weise vorzugehen.


Ich benutze in der programmspezifischen Unit unter anderem so etwas hier:

Code: Alles auswählen

 
 
type
    ARR_INDICES = (ARR_NAME1, ARR_NAME2, ARR_INDICES_MAX);
 
 


ARR_INDICES ist in jeder programmspezifischen Unit definiert und wird dann in der globalen Unit benutzt, ARR_NAME1, ARR_NAME2 etc haben je nach Programm andere Bezeichnungen, auch kommen je nach Programm verschieden viele davon vor (sind hunderte).

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

@Socke: Vielen Dank für diesen Ansatz. Eventuell kann ich daraus etwas machen und das auf meinen Fall übertragen... Sieht schon mal recht gut aus...

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

Mit dem Ansatz von Socke habe ich jetzt alles hinbekommen, außer eine Sache:

In der lokalen Unit habe ich für die Indices definiert:

Code: Alles auswählen

type  
  ARR_LOCAL = (L1, L2, L3, ARR_LOCAL_MAX);


In der globalen Unit habe ich für die Indices definiert:

Code: Alles auswählen

type  
  ARR_GLOBAL = (L1, L2, L3, ARR_GLOBAL_MAX);


Beides soll auf den gleichen Array zugreifen, über die folgenden Funktionen:

Code: Alles auswählen

function GetArrItem(AIndex: ARR_GLOBAL): string;
begin
  result:=GlobalArr[ord(AIndex)];
end;
 
function GetArrItem(AIndex: ARR_LOCAL): string;
begin
  result:=GlobalArr[ord(ARR_GLOBAL_MAX)+ord(AIndex)];
end;     


Beide Funktionen sollen in der globalen Unit definiert sein, da sie auch von anderen globalen Units aufgerufen werden.

Die Funktion GetArrItem(AIndex: ARR_GLOBAL) funktioniert perfekt, die Funktion GetArrItem(AIndex: ARR_LOCAL) leider nur dann, wenn die lokale Unit eingebunden ist. Ich brauche schließlich die Type-Definition von ARR_LOCAL.

Kann man das irgendwie lösen? Der Funktion der globalen Unit muss ja nur gesagt werden dass ARR_LOCAL ein enum-Type ist, damit die Funktion aufgerufen werden kann. Der Inhalt spielt ja hier keine Rolle. Sowas wie "type ARR_LOCAL = enum" hat leider nicht funktioniert dafür.

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: Zusammenspiel von Units

Beitrag von Socke »

LazProgger hat geschrieben:Die Funktion GetArrItem(AIndex: ARR_GLOBAL) funktioniert perfekt, die Funktion GetArrItem(AIndex: ARR_LOCAL) leider nur dann, wenn die lokale Unit eingebunden ist. Ich brauche schließlich die Type-Definition von ARR_LOCAL.

Kann man das irgendwie lösen? Der Funktion der globalen Unit muss ja nur gesagt werden dass ARR_LOCAL ein enum-Type ist, damit die Funktion aufgerufen werden kann. Der Inhalt spielt ja hier keine Rolle. Sowas wie "type ARR_LOCAL = enum" hat leider nicht funktioniert dafür.

Nein, das geht nicht. Enums werden fest definiert. In dem Fall musst du einen anderen Weg gehen.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

Socke hat geschrieben:Nein, das geht nicht. Enums werden fest definiert. In dem Fall musst du einen anderen Weg gehen.


Ein anderer Weg wäre es ja, den Enum schon vorher in einen Integer umzurechnen und dann als Integer weiter zu geben, aber damit hätte man die Sache ja auch nicht vereinfacht.

Gibt es denn etwas anderes, so ähnlich wie die Enums, was man hier verwenden könnte? Ich bräuchte halt nur eine Hand voll Konstanten die für die Array-Indices stehen und um die sich der Compiler dann selber kümmert...

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: Zusammenspiel von Units

Beitrag von Socke »

LazProgger hat geschrieben:Gibt es denn etwas anderes, so ähnlich wie die Enums, was man hier verwenden könnte? Ich bräuchte halt nur eine Hand voll Konstanten die für die Array-Indices stehen und um die sich der Compiler dann selber kümmert...

Gerade die Tatsache, dass deine "Konstanten" nicht über alle Units konstant sind, impliziert doch, dass es keine Konstanten sind.

Was willst du denn damit am Ende überhaupt erreichen? In deinem Beispiel sind die Werte der Aufzählungen identisch, trotzdem sind es komplett unterschiedliche Typen mit komplett unterschiedlichen Elementen (der Name interessiert den Compiler nicht, wenn er dies feststellt). Kannst du nicht eine Aufzählung verwenden?

Die Grenzen eines Arrays kannst du mit low() und high() herausfinden.

Möglicherweise kannst du dein Vorhaben anstatt über einen Array über mehrere Arrays in mehreren Klassen abbilden. In der allgemeinen Unit hast du eine Basisiklasse, die die Basis-Indizes des Arrays bereitstellt; in den programmspezifischen Units wird von dieser Klasse abgeleitet und ein zusätzlicher Array beinhaltet die programmspezifischen Indizes.
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

Erreichen möchte ich, dass ich von fast überall im Programm mit einer Funktion auf den Array zugreifen kann, dieser aber eben programmspezifische und unspezifische Inhalte haben kann.

Konstanten ist vielleicht der falsche Ausdruck dafür. Die Enums habe ich nur deswegen gewählt, da sie mir ermöglichen viele fortlaufende "Indices-Zahlen" mit einem mal zu definieren, man sie überall verwenden kann und auch mal am Anfang eine neue einfügen kann, ohne dass die Indices hinterher nicht mehr stimmen. Ich möchte halt lieber Funktion(ENUM_VARXYZ) als Funktion(100) aufrufen und dann immer wieder den ganzen Code ändern müssen.

Daher spielt es auch keine Rolle ob das unterschiedliche Typen sind, ich brauch halt nur die Zahlen, die ich mit ord() bekomme um auf den Array zuzugreifen und die Namen, um im Quellcode zu wissen auf welche Stelle ich zugreife. Der Compiler macht ja hinterher eh die Zahl daraus und das ist ja genau das, was passieren soll.

low() und high() nutzen mir nichts, ich durchlaufe den Array ja nicht sondern will gezielt auf bestimmte Elemente zugreifen. Daher ja diese Enum-Geschichte, dass ich im Quellcode immer den entsprechenden Enum aufrufen kann und weiß was es für ein Element ist.

Dies alles funktioniert ja auch wunderbar bis auf die eine Stelle hier in der globalen Funktion

Code: Alles auswählen

function GetArrItem(AIndex: ARR_LOCAL): string;
begin
  result:=GlobalArr[ord(ARR_GLOBAL_MAX)+ord(AIndex)];
end;   


wo ARR_LOCAL nicht bekannt ist.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2639
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Zusammenspiel von Units

Beitrag von m.fuchs »

Magst du vielleicht doch einmal den Hintergrund deines Problems beschreiben? Was machen deine Programme, was für Daten stehen in den Arrays und in den Enums? Ich vermute, dass es da ganz andere Lösungsmöglichkeiten gibt.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

Socke hat geschrieben:
LazProgger hat geschrieben:Kannst du nicht eine Aufzählung verwenden?


Wie verwendet man eine Aufzählung? Oder was meinst du damit?

LazProgger
Beiträge: 63
Registriert: Di 11. Mär 2014, 00:33

Re: Zusammenspiel von Units

Beitrag von LazProgger »

Ich bin jetzt durch ausprobieren auf folgendes gekommen:

Code: Alles auswählen

 
// Globale Unit 
 
function GetArrItem(AIndex: ARR_GLOBAL): string; overload;
function GetArrItem(AIndex: variant): string; overload;
 
// Funktion für die global definierten Enums:
 
function GetArrItem(AIndex: ARR_GLOBAL): string;
begin
  result:=GlobalArr[ord(AIndex)];
end;
 
// Funktion für die hier nicht sichtbaren lokal definierten Enums:
 
function GetArrItem(AIndex: variant): string;
var
  k: integer;
begin
  k:=AIndex;
  result:=GlobalArr[ord(ARR_GLOBAL_MAX)+k];
end;


Das kompiliert zumindest und gibt mir die richtigen Ergebnisse - auch ohne die lokale Unit in die globale eingebunden zu haben. Also fast super..

Allerdings habe ich noch folgende Fragen dazu:

  • Kann ich mich darauf verlassen, dass ARR_GLOBAL immer die erste Funktion aufruft? Schließlich könnte ARR_GLOBAL ja auch als Variant übergeben werden. Oder zieht der Compiler hier die "passendere" Funktion vor?
  • Im Wiki wird davor gewarnt zu oft Variants einzusetzen, was hier natürlich ein paar hundert mal geschehen würde. Wäre das ein großes Problem?
  • Kann man das auch irgendwie mit Generics oder Templates lösen, wie man es aus manch anderen Programmiersprachen kennt? Ich habe leider nichts dazu gefunden, ob man eine generische Variable einer Funktion übergeben kann. Geht das?
  • Ist es anzuraten noch den VarType auf VarInteger zu prüfen oder wäre das überflüssig hier?
Vielen Dank schon mal!

Antworten