Eine Sache, die mir neulich einfiel, sind bestimmte Typen, die noch notwendig sind, oder ein Vermächtnis, das uns zurückhält. Was ich meine ist: Brauchen wir wirklich Short, Int, Long, Bigint usw. usw.
Ich verstehe die Argumentation, Variablen / Objekte werden im Speicher gehalten, Speicher muss zugewiesen werden und daher müssen wir wissen, wie groß eine Variable sein kann. Aber eigentlich sollte eine moderne Programmiersprache nicht in der Lage sein, mit "adaptiven Typen" umzugehen, dh wenn etwas immer nur im Shortint-Bereich zugewiesen wird, werden weniger Bytes benötigt, und wenn etwas plötzlich einer sehr großen Zahl zugewiesen wird, wird der Speicher zugewiesen entsprechend für diesen bestimmten Fall.
Float-, Real- und Double-Werte sind etwas schwieriger, da der Typ davon abhängt, welche Präzision Sie benötigen. Strings sollten jedoch in der Lage sein, in vielen Fällen (in .Net), in denen meistens ASCII verwendet wird, weniger Speicherplatz in Anspruch zu nehmen, aber Strings belegen aufgrund der Unicode-Codierung immer den doppelten Speicherplatz.
Ein Argument für bestimmte Typen könnte sein, dass es Teil der Spezifikation ist, dh zum Beispiel sollte eine Variable nicht größer als ein bestimmter Wert sein können, also setzen wir ihn auf shortint. Aber warum nicht stattdessen Typbeschränkungen haben? Es wäre viel flexibler und leistungsfähiger, zulässige Bereiche und Werte für Variablen (und Eigenschaften) festlegen zu können.
Ich erkenne das immense Problem bei der Überarbeitung der Typarchitektur, da sie so eng in die zugrunde liegende Hardware integriert ist und Dinge wie die Serialisierung in der Tat schwierig werden könnten. Aber aus programmtechnischer Sicht sollte es toll sein, nein?
quelle
type hour is range 0 .. 23;
Antworten:
Ich bin davon überzeugt, dass dies der Fall ist. Semantische Einschränkungen sind mehr wert als Einschränkungen der Implementierung. Sich Gedanken über die Größe von etwas zu machen, fühlt sich an, als würde man sich Gedanken über die Geschwindigkeit von etwas machen, wenn objektorientierte Programmierung zustande kommt.
Es hat die leistungskritische Programmierung nicht ersetzt. Es wird lediglich die Produktivität der nicht leistungskritischen Programmierung gesteigert.
quelle
Adaptative Typen bedeuten Logik für die Anpassung und die Ausführung dieser Logik zur Laufzeit (Templating und Kompilierungszeit erfordern einen bestimmten Typ, wobei die Typinferenz ein Sonderfall ist, bei dem Sie das Beste aus zwei Welten erhalten). Diese zusätzliche Arbeit kann in Umgebungen in Ordnung sein, in denen die Leistung nicht kritisch ist und das System eine angemessene Größe beibehält. In anderen Umgebungen ist dies nicht der Fall (bei eingebetteten Systemen müssen gelegentlich ganzzahlige 32/64-Bit-Typen für die CPU-Leistung und ganzzahlige 8/16-Bit-Typen für die Optimierung der statischen Speichersicherung verwendet werden).
Sogar Allzwecksprachen, die späte Bindung unterstützen (Auflösung von Typen zur Laufzeit, wie VB6), tendieren aufgrund der Leistungseinbußen, die früher auftraten, als die späte Bindung missbraucht wurde, und weil Sie häufig zu starker Typisierung neigten (VB.NET) Das Ergebnis ist hässlicher Code, wenn die Typen nicht explizit sind ( Referenz / Professionelles Refactoring in Visual Basic - Danijel Arsenovski ).
quelle
Einfachheit, Speicher und Geschwindigkeit Wenn ich eine Variable deklariere, wird der Speicher für diese Variable in einem Block zugewiesen. Um eine dynamisch wachsende Variable zu unterstützen, müsste ich das Konzept des nicht zusammenhängenden Speichers zu dieser Variablen hinzufügen (entweder das oder den größten Block reservieren, den die Variable darstellen kann). Ein nicht zusammenhängender Speicher würde die Leistung beim Zuweisen / Abrufen verringern. In dem Szenario, in dem ich nur ein Byte benötige, das System aber lange Zeit reserviert, wäre es verschwenderisch, das größtmögliche zuzuweisen.
Denken Sie an die Kompromisse zwischen einem Array und einem Vektor (oder einer verknüpften Liste). Bei einem Array ist es einfach, eine bestimmte Position zu suchen, indem Sie die Startposition ermitteln und den Speicherzeiger x Leerzeichen verschieben, um diese neue Position im Speicher zu lokalisieren. Stellen Sie sich ein int als ein Bit vor [32] Beim Lesen eines int durchlaufen Sie dieses Array, um alle Bitwerte abzurufen.
Um einen dynamischen Zahlentyp zu erstellen, müssen Sie diesen von einem Array von Bits in einen Vektor von Bits ändern. Zum Lesen Ihrer dynamischen Nummer müssen Sie zum Kopf gehen, das Bit abrufen, nachfragen, wo sich das nächste Bit im Speicher befindet, zu dieser Position gehen, das Bit abrufen usw. Für jedes Bit in der dynamischen Nummer führen Sie drei Operationen aus: Lesen ( aktuell), lesen (Adresse des nächsten), bewegen (nächsten). Stellen Sie sich vor, Sie lesen die Werte von einer Million Zahlen. Das sind eine Million zusätzliche Operationen. Es mag unbedeutend erscheinen. Denken Sie jedoch an die Systeme (wie Finanzdaten), bei denen jede Millisekunde eine Rolle spielt.
Die Entscheidung wurde getroffen, dass die Verpflichtung des Entwicklers zur Überprüfung der Größe und Validierung einen kleinen Kompromiss darstellt, verglichen mit der Beeinträchtigung der Leistung des Systems.
quelle
Für hardwarezentrierte Sprachen und Projekte sind bestimmte Typen erforderlich. Ein Beispiel sind drahtgebundene Netzwerkprotokolle.
Aber lassen Sie uns zum Spaß einen Varint-Typ in einer Sprache wie C ++ erstellen. Erstellen Sie es aus einem
new
Array von Ints.Es ist nicht schwer, eine Addition zu implementieren: x oder die Bytes zusammen und überprüfe die hohen Bits: Wenn es eine Übertragsoperation gibt,
new
in einem neuen oberen Byte und übertrage das Bit. Die Subtraktion folgt trivial in der Komplementdarstellung von 2. (Dies wird auch als Ripple-Carry-Addierer bezeichnet.)Die Multiplikation folgt ähnlich; Verwenden Sie das iterative Hinzufügen / Verschieben. Wie immer ist die wahre Wendung in deinem Schwanz die Teilung [*].
Was hast du dabei verloren?
Deterministische Zeit. Sie haben ein syscall (
new
), das an Punkten ausgelöst werden kann, die nicht unbedingt steuerbar sind.Deterministischer Raum.
Semi-Software Mathe ist langsam.
Wenn Sie eine Hardware-Layer-Sprache verwenden und auch auf einer hohen (langsamen) Ebene arbeiten müssen und keine Skript-Engine einbetten möchten,
varint
ist a sehr sinnvoll. Es ist wahrscheinlich irgendwo geschrieben.[*] Siehe Hardwaremathematik-Algorithmen für schnellere Methoden - der Trick besteht jedoch normalerweise in parallelen Operationen.
quelle
Das ist eine gute Frage. Es erklärt, warum eine Sprache wie Python nicht "short, int, long, bigint etc." benötigt: Ganzzahlen sind nun, Ganzzahlen (es gibt einen einzelnen Ganzzahlentyp in Python 3) und haben keine Begrenzungsgröße (über die von der Speicher des Computers natürlich).
Bei Unicode wird bei der UTF-8-Codierung (die Teil von Unicode ist) nur ein einzelnes Zeichen für ASCII-Zeichen verwendet, daher ist dies nicht so schlimm.
Generell scheinen dynamische Sprachen in die von Ihnen erwähnte Richtung zu gehen. Aus Effizienzgründen sind jedoch in einigen Fällen eingeschränktere Typen hilfreich (z. B. Programme, die schnell ausgeführt werden müssen). Ich sehe in absehbarer Zeit keine großen Veränderungen, da Prozessoren Daten in Bytes (oder 2, 4, 8 usw. Bytes) organisieren.
quelle
Sprachtheoretisch haben Sie recht. Die Typen sollten auf einer Reihe von rechtlichen Zuständen, den Transformationen, die für diese Zustände verfügbar sind, und den Operationen, die für diese Zustände ausgeführt werden können, basieren.
Dies ist jedoch ungefähr das, was Ihnen die OOP-Programmierung in ihrer typischen Form bietet. In der Tat sprechen Sie in Java effektiv über die
BigInteger
BigDecimal
Klassen und , die Speicherplatz zuweisen, je nachdem, wie viel zum Speichern des Objekts erforderlich ist. (Wie FrustratedWithFormsDesigner feststellte, sind viele Skriptsprachen noch weiter auf diesem Weg und erfordern nicht einmal eine Typdeklaration und speichern alles, was Sie ihnen geben.)Die Leistung ist jedoch immer noch relevant. Da das Wechseln von Typen zur Laufzeit kostspielig ist und Compiler zur Kompilierungszeit nicht die maximale Größe einer Variablen garantieren können, verfügen wir immer noch über statisch große Variablen für einfache Typen in vielen Sprachen.
quelle
int
oder ein passtdouble
, und wenn dies nicht der Fall ist, sind sie sich dessen bewusst. Daher ist die dynamische Größenanpassung eine Funktion, für die sie nicht bezahlen müssen.Das hängt von der Sprache ab. Für übergeordnete Sprachen wie Python, Ruby, Erlang usw. gibt es nur das Konzept von Integral- und Dezimalzahlen.
Für eine bestimmte Klasse von Sprachen mit diesen Typen sind jedoch sehr wichtig. Wenn Sie Code zum Lesen und Schreiben von Binärformaten wie PNG, JPeg usw. schreiben, müssen Sie genau wissen, wie viele Informationen gleichzeitig eingelesen werden. Dasselbe gilt für das Schreiben von Betriebssystemkernen und Gerätetreibern. Nicht jeder tut dies, und in den höheren Sprachen verwenden sie C-Bibliotheken, um das detaillierte schwere Heben durchzuführen.
In
short
gibt es immer noch einen Platz für die spezifischeren Typen, aber viele Entwicklungsprobleme erfordern diese Präzision nicht.quelle
Ich habe kürzlich einen Kontaktplan-Editor und eine Laufzeitumgebung erstellt und mich entschlossen, die folgenden Typen zu verwenden:
Ich glaube, es hat es für den Benutzer intuitiver gemacht. Dies ist eine radikale Abkehr von den meisten SPS, die alle "normalen" Typen haben, die Sie in einer Sprache wie C sehen würden.
quelle
Die Programmiersprachen haben sich in diese Richtung bewegt. Nehmen Sie zum Beispiel Zeichenfolgen. In alten Sprachen müssen Sie die Größe der Zeichenfolge deklarieren, wie
PIC X(42)
in COBOL,DIM A$(42)
in einigen Versionen von BASIC oder [VAR
]CHAR(42)
in SQL. In modernen Sprachen haben Sie nur eine dynamisch zugewiesenestring
Typ und müssen nicht über die Größe nachdenken.Ganzzahlen sind jedoch unterschiedlich:
Schauen Sie sich Python an. Früher wurde zwischen maschinengroßen (
int
) und willkürlich großen (long
) Ganzzahlen unterschieden. In 3.x ist das frühere weg (das altelong
ist das neueint
) und niemand vermisst es.Es gibt aber immer noch einen speziellen Typ für Folgen von 8-Bit-Ganzzahlen in Form von
bytes
undbytearray
. Warum nicht jeweils einetuple
oder einelist
ganze Zahl verwenden? Esbytes
stimmt , es gibt zusätzliche stringartige Methoden, dietuple
dies nicht tun, aber die Effizienz hat sicherlich viel damit zu tun.Nicht wirklich. Der Ansatz "Alles ist doppelt präzise" ist weit verbreitet.
quelle
unum64 += ring32a-ring32b
immer das richtige Verhalten liefert, unabhängig davon, ob der Standard-Integer-Typ 16 Bit oder 64 Bit+=
ist. Ein Ausdruck wieunum64a = unum64b + (ring32a-ring32b);
sollte als mehrdeutig abgelehnt werden.]Ich verstehe die Argumentation, Variablen / Objekte werden im Speicher gehalten, Speicher muss zugewiesen werden und daher müssen wir wissen, wie groß eine Variable sein kann. Aber eigentlich sollte eine moderne Programmiersprache nicht in der Lage sein, mit "adaptiven Typen" umzugehen, dh wenn etwas immer nur im Shortint-Bereich zugewiesen wird, werden weniger Bytes benötigt, und wenn etwas plötzlich einer sehr großen Zahl zugewiesen wird, wird der Speicher zugewiesen entsprechend für diesen bestimmten Fall.
Float-, Real- und Double-Werte sind etwas schwieriger, da der Typ davon abhängt, welche Präzision Sie benötigen. Strings sollten jedoch in der Lage sein, in vielen Fällen (in .Net), in denen meistens ASCII verwendet wird, weniger Speicherplatz in Anspruch zu nehmen, aber Strings belegen aufgrund der Unicode-Codierung immer den doppelten Speicherplatz.
Fortran hatte etwas Ähnliches (ich weiß nicht, ob das genau das ist, was Sie meinen, da ich zwei Fragen wirklich offen sehe). Zum Beispiel müssen Sie in F90 aufwärts sozusagen keine explizite Schriftgröße definieren . Das ist gut, da Sie hier nicht nur zentral Ihre Datentypen definieren können, sondern auch portabel. REAL * 4 ist nicht bei allen Implementierungen auf allen Prozessoren gleich (und mit Prozessor meine ich CPU + Compiler), nicht bei Weitem.
selected_real_kind (p, r) gibt den Art-Wert eines realen Datentyps mit einer Dezimalgenauigkeit von mindestens p Ziffern und einem Exponentenbereich von mindestens r zurück.
So gehts zum Beispiel;
(Ich denke, es ist ein ziemlich selbsterklärendes Beispiel).
Ich weiß immer noch nicht, ob ich Ihre Frage richtig verstanden habe, und das ist, was Sie erwähnen.
quelle