AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren

Maßeinheiten als Typen

Ein Thema von Ghostwalker · begonnen am 11. Okt 2018 · letzter Beitrag vom 18. Okt 2018
Antwort Antwort
Seite 1 von 8  1 23     Letzte » 
Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.241 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

Maßeinheiten als Typen

  Alt 11. Okt 2018, 07:54
Moinmoin,

da hier Unittests generieren die Frage aufgekommen ist, ob das Konzept, das als eigene Typen zu implementieren, stell ich hier mal die Frage nach Alternativen (schließlich kann auch ein SE mal irren).

Dabei ist das ganze als Grundstock für ein größeres Bibleotheks-Projekt gedacht. Dabei gibts natürlich einige Anforderungen:

1. Die einzelnen Typen sollen sicher und eindeutig sein.

Gemeint ist, das, wenn man das ganze als Parameter an eine Methode übergibt, keine andere Maßeinheit
übergeben werden kann

Beispiel:

   Procedure TuWas(const a:gramm); Wenn versucht wird, hier Kilogram zu übergeben, soll der Compiler meckern.

2. Rechenoperationen sollen möglich sein. D.h. Addition, Subtraktion, Division und Multiplikation
3. Vergleichsoperation sollen auch möglich sein.

4. Eine Möglichkeit, von einer Maßeinheit in eine andere Maßeinheit zu konvertieren/umzurechnen

Wärend der Konzeptions und Tüftelphase () bin ich auch auf das ein oder andere Problem gestoßen:

a) Klassen funktionieren hier nicht

Das größte Manko hier ist, das man keine Operatoren in Klassen definieren kann. Ein zweites, wenn auch
weniger wichtiges Manko ist, das Klassen explizit erzeugt werden müssen.

b) Records können nicht wirklich vererbt werden

Ansonsten hätte man einen "Basistypen" geschaffen, und den Rest einfach davon abgeleitet, so das
man das ganze mit weniger Aufwand umsetzen hätte können.

c) Kein wirkliches forwarding bei Records

Da man Records nur mit Zeigern forwarden kann, müssen einiges an Operatoren an ungewöhnlicher Stelle
implementiert werden. D. h. dass zu Beispiel der Add-Operator für Gramm+Kilogram bei Kilogram implementiert
wird, obwohl der Rückgabewert Gramm ist.

Daher der Ansatz, für jede Maßeinheit einen entsprechenden Record schaffen.

Wenn jemand einen alternativen Ansatz hat, immer her damit
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat
Schokohase

Registriert seit: 17. Apr 2018
450 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 08:09
Dann erklär doch was die Problematik ist, wenn du ein Gewicht mit unterschiedlichen Einheiten übergibst.

Ich sehe da eigentlich kein Problem und bin daher der Meinung, dass ein Typ für Gewicht ausreicht und du keine Aufsplittung in Gramm, Kilogramm, Tonne Typen benötigst.
  Mit Zitat antworten Zitat
Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.241 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#3

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 08:46
Genaugenommen gibts 2:

1. Beispiel

Delphi-Quellcode:
Procedure Tuwas(const gramm:integer);overload;
Procedure Tuwas(const kilogram:integer);overload;
das tut so nicht, da der Compiler meint es wären die gleichen Parameter.

2. Beispiel

Procedure TuwasAnderes(const gramm:integer;const Kilogramm:integer); Hier könnte ich z.B. problemlos auch Tonnen übergeben, was u.U. zu recht...interresanten Problemen führen kann.
Mit entsprechenden Typen kann ich sicherstellen, das dort, wo Gramm als Parameter erwartet wird, auch nur Gramm übergeben werden können.

3. Angenehmer Nebeneffekt

Delphi-Quellcode:
var
  a : Gramm;
  b : Kilogramm;
  erg : Gramm;

begin
  a := 10;
  b := 10;
  erg := a+b; //<-- Ergibt 10010 Gramm !
end;
Würde ich hier z.B. einfach integer nehmen, könnte man das Ergebnis in die Tonne treten.
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat
Schokohase

Registriert seit: 17. Apr 2018
450 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#4

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 08:54
Das ist die Begründung dafür, warum du einen Typen für Gewicht benötigst, aber noch nicht die Begründung dafür, warum du mehrere Typen für Gewicht benötigst.

Delphi-Quellcode:
procedure Tuwas( const gewicht: TWeight );
begin
  ...
end;
Und verwenden so
Delphi-Quellcode:
begin
  Tuwas( TWeight.FromKilograms( 10 ) );
  Tuwas( TWeight.FromGrams( 10 ) );
  Tuwas( TWeight.FromTons( 10 ) );
end;
PS Als kleines Beispiel sei gennant, dass die Geschwindigkeit als Weg pro Zeit definiert ist und nicht als Meter pro Sekunde. Jede Geschwindigkeit kann auch als Meter pro Sekunde dargestellt werden und trotzdem gilt das auch wenn der Weg in Kilometer angegeben ist und die Zeit in Nanosekunden.

Geändert von Schokohase (11. Okt 2018 um 09:01 Uhr)
  Mit Zitat antworten Zitat
Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.241 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#5

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:11
und woher weis Tuwas, was er nun übergeben bekommen hat ?

Wenn die Methode nur mit bestimmte Einheiten arbeiten soll, hab ich hier nur die Möglichkeit, das über einen weiteren Parameter (nämlich die Einheit) und unterscheidet dann diese innerhalb der Methode.

oder

Es gibt für die entsprechenden Einheiten, entsprechende Überladungen.

hmmmm...


Natürlich könnte man in TWeight z.B. noch einen zusätzlichen wert für die Einheit mitführen. Aber letztlich würde das keine Vorteil bringen. Die Methoden und Operatoren müssten ja trotzdem die Einheiten unterscheiden.
Uwe
e=mc² or energy = milk * coffee²

Geändert von Ghostwalker (11. Okt 2018 um 09:23 Uhr) Grund: Idee
  Mit Zitat antworten Zitat
Benutzerbild von bernau
bernau

Registriert seit: 1. Dez 2004
Ort: Köln
973 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#6

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:22
und woher weis Tuwas, was er nun übergeben bekommen hat ?

Wenn die Methode nur mit bestimmte Einheiten arbeiten soll, hab ich hier nur die Möglichkeit, das über einen weiteren Parameter (nämlich die Einheit) und unterscheidet dann diese innerhalb der Methode.

oder

Es gibt für die entsprechenden Einheiten, entsprechende Überladungen.
"TuWas" wurde TWeight übergeben. Mehr muss "Tuwas" nicht wissen. TWeight ist ein Record welches ein Value mit der Einheit (z.B. "Gramm") besitzt. Über die Funktionen "FromKilograms( 10 )" wird automatisch in Gramm umgerechnet. So mache ich das auch seit einiger Zeit, seit ich Operatoren in Records kennen gelernt habe. Ich mache daraus noch ein "Property asKilogram" somit kann man in beide Richtungen arbeiten.

Das ergibt dann sowas wie

Delphi-Quellcode:
var
  a:TWeight;
  b:TWeight;
begin
  a.asKilogram = 10;
  b.asGramm = 10;
  TuWas(a+b); // 1010gramm werden übergeben
end;
Gerd
Kölner Delphi Usergroup: http://wiki.delphitreff.de
  Mit Zitat antworten Zitat
Ghostwalker

Registriert seit: 16. Jun 2003
Ort: Schönwald
1.241 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#7

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:26
Soweit schon richtig.

Und was machst du wenn Tuwas nur Gramm und Kilogramm verarbeiten soll nicht aber Tonnen oder Milligram ?

Wie ich grad oben erweitert hab, kann Tuwas das ganze nicht unterscheiden.
Uwe
e=mc² or energy = milk * coffee²
  Mit Zitat antworten Zitat
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
414 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#8

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:31
Hilft dir sowas?

Code:
Type
  TKilogramm= type of Integer;
  TGramm = type of integer;
http://docwiki.embarcadero.com/RADSt...%A4t_von_Typen
  Mit Zitat antworten Zitat
TiGü
Online

Registriert seit: 6. Apr 2011
Ort: Berlin
1.893 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#9

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:36
1. Die einzelnen Typen sollen sicher und eindeutig sein.

Gemeint ist, das, wenn man das ganze als Parameter an eine Methode übergibt, keine andere Maßeinheit
übergeben werden kann

Beispiel:

   Procedure TuWas(const a:gramm); Wenn versucht wird, hier Kilogram zu übergeben, soll der Compiler meckern.
Vorweg:
Ich empfehle eine kurze Recherche bei Wikipedia zu Maßeinheiten, Vorsätzen und Einheitensystem zur Auffrischung.
Möglich wäre auch, dass du dir mal anschaust wie das die Delphi RTL für System.TimeSpan.TTimeSpan regelt.

Es ist mir beim Überfliegen dieses und des anderen Threads nicht ganz klar geworden, ob das mit den Gewicht nur ein Beispiel/Analogie ist oder du wirklich mit Gewichtsangaben arbeiten musst.

Nehmen wir mal an, es geht wirklich um Gewicht, also du willst die physikalische Maßeinheit für die Masse in einer bestimmten Gravation beziffern:
Gramm, Kilogramm, Tonne (1000 kg), Kilotonne (1000 * 1000 kg) sind keine verschiedenen Maßeinheiten.
Es bezieht sich immer auf ein und dasselbe mit verschiedenen Vorsätzen für Maßeinheiten.
Die SI-Basiseinheit für Masse ist das Kilogramm. Ein Gramm ist ein Tausendstel Kilogramm. Soweit bekannt, nix neues.
Schaffe dir einfach einen einzigen konkreten Basisdatentyp, bspw. mit Gramm und gebe ihm die entsprechenden Methoden.

Delphi-Quellcode:
type
  TKilogramm = type UInt64;
  TTonne = type UInt64;

  TKilogrammHelper = record helper for TKilogramm
    function ToString: string;
  end;

  TTonneHelper = record helper for TTonne
    function ToString: string;
  end;

  TGramm = type Double;

  TGewicht = record
  strict private
    FDasRichtigeGewichtInGrammAlsFliesskommazahl: TGramm;
    // Warum Fliesskomma? Vielleicht willst du auch mal Milli- und/oder Mikrogramm verarbeiten.
    // Man kann natürlich auch mit einen UInt32 oder UInt64 als Basis arbeiten, dann muss das aber im Vorfeld klar sein, welche die kleinste Größe ist.
    // Bei einen Kuchenrezept bspw. ist höchstwahrscheinlich die kleinste Gewichtsangabe sowas wie "eine Prise Salz/ein halbes Gramm".
  private
    // ggf. mit richtigen Gettern und Settern versehen
    property RawValue: TGramm read FDasRichtigeGewichtInGrammAlsFliesskommazahl write FDasRichtigeGewichtInGrammAlsFliesskommazahl;
  public
    class function Add(const A, B: TGewicht): TGewicht; static;
    function AsKilogramm: TKilogramm;
    // Hier kommen nur sinnvolle Werte größer null bei raus, wenn die interne Variable vor dem Komma mehr als 1000 groß ist.
    function AsTonne: TTonne;
    // Hier kommen nur sinnvolle Werte größer null bei raus, wenn die interne Variable vor dem Komma mehr als 1000 * 1000 groß ist.
  end;

implementation

{ TGewicht }

class function TGewicht.Add(const A, B: TGewicht): TGewicht;
begin
  Result.RawValue := A.RawValue + B.RawValue;
end;

function TGewicht.AsKilogramm: TKilogramm;
begin
  Result := Round(RawValue / 1000);
end;

function TGewicht.AsTonne: TTonne;
begin
  Result := Round(RawValue / 1000 * 1000);
end;

{ TKilogrammHelper }

function TKilogrammHelper.ToString: string;
begin

end;

{ TTonneHelper }

function TTonneHelper.ToString: string;
begin

end;
  Mit Zitat antworten Zitat
Benutzerbild von bernau
bernau

Registriert seit: 1. Dez 2004
Ort: Köln
973 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#10

AW: Maßeinheiten als Typen

  Alt 11. Okt 2018, 09:38
Soweit schon richtig.

Und was machst du wenn Tuwas nur Gramm und Kilogramm verarbeiten soll nicht aber Tonnen oder Milligram ?

Wie ich grad oben erweitert hab, kann Tuwas das ganze nicht unterscheiden.
"TuWas" muss es ja auch nicht unterscheiden. "TuWas" erhält immer nur den Wert "TWeight".

Aber du wirst deinen Grund haben. Interessieren würde es mich schon, weshalb z.B. nur "Tonnen" verwendet werden soll und alle anderen nicht. Gewicht ist Gewicht, egal welche Maßzahl verwendet wird.
Gerd
Kölner Delphi Usergroup: http://wiki.delphitreff.de
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:58 Uhr.
Powered by vBulletin® Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2018 by Daniel R. Wolf