Sind noch bestimmte Typen notwendig?

20

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?

Homde
quelle
6
PHP, Ruby, Perl und andere erfordern keine Angabe der Variablentypen. Die Umwelt findet es für Sie heraus.
FrustratedWithFormsDesigner
7
Unicode-Zeichenfolgen müssen keinen zusätzlichen Speicher belegen, wenn sie nur für ASCII (UTF-8) verwendet werden.
2
Aber es gibt einen Unterschied zwischen varianten und adaptiven Typen IMO. Varianten werden überhaupt nicht getippt, sondern werden bei der Zuweisung getippt, während adaptive Typen getippt werden, jedoch lockerer. (und ich mag das Konzept der
Typbeschränkungen
Das erinnert mich an dieses Projekt: tom.lokhorst.eu/media/…
LennyProgrammers
4
Was ist mit Ada? type hour is range 0 .. 23;
Mouviciel

Antworten:

12

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.

Mark Canlas
quelle
1
Testen Sie die Codeverträge in .NET 4.0.
Steven Jeuris
+1 Wenn es um Datenspeicherung / -übertragung (z. B. Vernetzung) geht, sind die Einschränkungen von grundlegender Bedeutung, um die Effizienz des Protokolls / der Implementierung zu maximieren. Es gibt auch viel zu gewinnen, wenn typisierte Sammlungen verfügbar sind. Davon abgesehen ist davon auszugehen, dass die Effizienz in den Hintergrund treten kann (insbesondere, wenn die Möglichkeit von semantischen Fehlern verringert wird).
Evan Plaice
9

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 ).

Matthieu
quelle
Bitte definieren Sie "Auto-Typisierung".
@delnan: Auto-Typisierung durch späte Bindung ersetzt, was ich meinte :)
Matthieu
Es gibt viele universelle Sprachen, die Typen zur Laufzeit auflösen, Common Lisp, um nur eine zu nennen. (Zu Leistungszwecken können Sie Typen in Common Lisp deklarieren, sodass Sie dies nur in leistungskritischen Abschnitten tun können.)
David Thornley,
@David Thornley: "Durchsetzen" starker Tippfehler könnte zu stark gewesen sein, "Fördern" wäre angemessener, meine Antwort entsprechend aktualisiert. Eine Sprache, mit der Sie je nach Situation zwischen den beiden Bindungsarten wählen können, ist sicherlich besser, als auf die eine oder andere Weise gezwungen zu werden. Vor allem, wenn Sie nicht auf niedriger Ebene programmieren und sich auf Logik konzentrieren.
Matthieu
4

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.

Michael Brown
quelle
1
Die andere Alternative besteht darin, Nummern ähnlich wie Array-Listen zu implementieren, bei denen das Array neu zugewiesen wird, wenn die Anzahl über der aktuellen Größe liegt. Außerdem müssen Sie den Fall berücksichtigen, in dem der Benutzer den Überlauf in einer Schleife ausführen möchte.
Michael Brown
Das stimmt, ist aber eine gewisse Vereinfachung. Sie könnten sich eine effizientere Array-Struktur einfallen lassen, obwohl nicht so schnell wie statisch eingegeben für die meisten Fälle "schnell genug" sein könnte. Sie könnten beispielsweise Informationen zu Blöcken verschiedener Typen speichern, wenn das Array nicht vollständig gezackt wäre und nicht so viel Speicherplatz oder Leistung in Anspruch nehmen würde. Oder das Array könnte Speicher opfern, um einen Index zu haben. Das Array kann sich aufgrund seines Inhalts sogar selbst optimieren. Sie haben weiterhin die Möglichkeit, die Speichergröße über eine Typeinschränkung einzugeben, wenn Sie Leistung benötigen.
Homde
Um fair zu sein, es ist nicht so brutal, wie man es sieht. Vgl. Meine bevorstehende Antwort.
Paul Nathan
3

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 newArray 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, newin 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, varintist a sehr sinnvoll. Es ist wahrscheinlich irgendwo geschrieben.

[*] Siehe Hardwaremathematik-Algorithmen für schnellere Methoden - der Trick besteht jedoch normalerweise in parallelen Operationen.

Paul Nathan
quelle
2

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.

Eric O Lebigot
quelle
1

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 dieBigIntegerBigDecimal 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.

Jprete
quelle
Mir ist klar, dass eine Art dynamisches / adaptives Tippen teuer und weniger performant zu sein scheint als das, was wir jetzt haben, und dass es mit aktuellen Compilern sicherlich auch so wäre. Aber sind wir uns zu 100% sicher, dass Sie eine Sprache und einen Compiler, die von Grund auf neu erstellt wurden, nicht in der Lage sind, sie, wenn auch nicht so schnell wie statisch geschrieben, mindestens so schnell zu erstellen, dass sie sich lohnen?
Homde
1
@MKO: Warum versuchst du es nicht und siehst?
Anon.
1
Ja, Sie können es machbar schnell machen (aber wahrscheinlich nie so schnell wie ein statisches System für Zahlen). Aber der Teil "Ist es das wert?" Ist kniffliger. Die meisten Menschen arbeiten mit Daten, deren Bereich problemlos in ein intoder ein passt double, 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.
2.
Wie alle Programmierer träume ich natürlich davon, eines Tages meine eigene Sprache zu machen;)
Homde
@jprete: Ich stimme nicht zu; Die meisten Menschen sind sich möglicher großer Zwischenergebnisse nicht bewusst. Eine solche Sprache kann und wurde für die meisten Zwecke schnell genug gemacht.
David Thornley
1

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 shortgibt es immer noch einen Platz für die spezifischeren Typen, aber viele Entwicklungsprobleme erfordern diese Präzision nicht.

Berin Loritsch
quelle
0

Ich habe kürzlich einen Kontaktplan-Editor und eine Laufzeitumgebung erstellt und mich entschlossen, die folgenden Typen zu verwenden:

  • Boolean
  • Nummer
  • String
  • Terminzeit

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.

Scott Whitlock
quelle
0

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:

Was ich meine ist: Brauchen wir wirklich Short, Int, Long, Bigint usw. usw.

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 alte longist das neue int) und niemand vermisst es.

Es gibt aber immer noch einen speziellen Typ für Folgen von 8-Bit-Ganzzahlen in Form von bytesund bytearray. Warum nicht jeweils eine tupleoder eine listganze Zahl verwenden? Es bytesstimmt , es gibt zusätzliche stringartige Methoden, die tupledies nicht tun, aber die Effizienz hat sicherlich viel damit zu tun.

Float-, Real- und Double-Werte sind etwas schwieriger, da der Typ davon abhängt, welche Präzision Sie benötigen.

Nicht wirklich. Der Ansatz "Alles ist doppelt präzise" ist weit verbreitet.

dan04
quelle
1
Möglicherweise sollten Basistypen grundlegende Intents des Typs deklarieren, dh int für "normale" Zahlen, double für alle normalen "Dezimalzahlen" (sollten Ints der Einfachheit halber keine Dezimalzahlen haben können?) Money für die Arbeit mit Beträgen und Bytes für die Arbeit mit binären Daten. Eine über ein Attribut deklarierte Typeinschränkung kann das Deklarieren des zulässigen Bereichs, der Dezimalgenauigkeit, der Nullfähigkeit und sogar zulässiger Werte ermöglichen. Es wäre cool, wenn Sie auf diese Weise benutzerdefinierte und wiederverwendbare Typen erstellen könnten
Homde
@konrad: IMHO, der Grund, warum "vorzeichenlose" Ganzzahlen solche Kopfschmerzen in C verursachen, ist, dass sie manchmal zur Darstellung von Zahlen und manchmal zur Darstellung von Mitgliedern eines umhüllenden abstrakten algebraischen Rings verwendet werden. Wenn Sie getrennte "Ring" - und "vorzeichenlose" Nummerntypen haben, kann dies sicherstellen, dass Code wie unum64 += ring32a-ring32bimmer das richtige Verhalten liefert, unabhängig davon, ob der Standard-Integer-Typ 16 Bit oder 64 Bit +=ist. Ein Ausdruck wie unum64a = unum64b + (ring32a-ring32b);sollte als mehrdeutig abgelehnt werden.]
Supercat
0

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;

program real_kinds
integer,parameter :: p6 = selected_real_kind(6)
integer,parameter :: p10r100 = selected_real_kind(10,100) !p is precision, r is range
integer,parameter :: r400 = selected_real_kind(r=400)
real(kind=p6) :: x
real(kind=p10r100) :: y
real(kind=r400) :: z

print *, precision(x), range(x)
print *, precision(y), range(y)
print *, precision(z), range(z)
end program real_kinds

(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.

Turm
quelle