BlitzMax Extended

Kommentare anzeigen Worklog abonnieren
Gehe zu Seite Zurück  1, 2

Worklogs BlitzMax Extended

Ey, du komischer Type!

Montag, 14. Mai 2012 von ProfJake
Heute geht es um die Arten von Variablen und die dazugehörigen Type Tags.

BlitzMax hat ja bekanntermaßen nur eine kleine Auswahl an primitiven Datentypen:
BlitzMax: [AUSKLAPPEN]
Byte, Short, Int, Long, Float und Double

Gerade bei der Umsetzung von Längenangaben, wie zum Beispiel bei String.length
sind die unterstützten Datentypen reichlich unzureichend. So wäre zum Beispiel ein
UInt wie es in C mit uint32_t existiert irre praktisch (von size_t ganz zu schweigen).
Aber das kann ich nicht ändern, da es auf Kompilerebene (bcc) abläuft. Was dagegen
möglich ist, sind Erleichterungen um mit dem vorhanden zu arbeiten.


In die Schranken verwiesen
Hilfsmittel um Variablen nicht überlaufen zu lassen.

Da eine Unterstützung für 64-bit derzeit nicht vorgesehen zu sein scheint,
kann man die Limits der einzelnen Datentypen ganz einfach in Konstanten packen.
Für die ganzzahligen Arten ist das auch total leicht verständlich, weshalb ich mich
erst einmal auf diese beschränken will – soll ja einfach bleiben.

Es wird folgende vordefinierte Konstanten geben:

BlitzMax: [AUSKLAPPEN]
Const BYTE_MIN:Byte = $00
Const BYTE_MAX:Byte = $ff
Const SHORT_MIN:Short = $0000
Const SHORT_MAX:Short = $ffff
Const INT_MIN:Int = $80000000
Const INT_MAX:Int = $7fffffff
Const LONG_MIN:Long = -9223372036854775808:Long
Const LONG_MAX:Long = 9223372036854775807:Long


Nichts besonderes. Jedoch finde ich, dass der angemessene Platz für so etwas
genau im blitz.mod ist. Sollte in Zukunft also 64-bit unterstützt werden
und die Limits geändert werden, dann ist man auf der sicheren Seite.

Auf der dunklen Seite des Codes

Im C-Teil des Moduls gibt es selbstverständlich die dazugehörigen Konstanten.
So ist BBINT deprecated, BBInt heißt der neue Typ, der Werte von
BBINT_MIN bis BBINT_MAX speichern kann. Sollte alles leicht verständlich sein.

Zusatzinformation: Ich hätte gerne alles als fixed-size integer (int32_t für BBInt) definiert,
aber die anderen Module nutzen kein C99. Meh.


Der ominöse Type Tag
Oder auch: Erzähl' mal was interessantes!

Um zu wissen, welchen Datentyp beispielsweise ein Field hat, speichert BlitzMax
einen kurzen String der den Datentyp beschreibt. Dieser steckt in einem sogenannten
DebugScope (zu finden in blitz_debug.h). Auch Arrays verwenden diese Abkürzungen.
Hier ist eine kurze Liste mit den wichtigsten Type Tags:

  • b Byte
  • s Short
  • i Int
  • l Long
  • f Float
  • d Double
  • $ String
  • [ Array


Hey, wo sind die Objekte?

Genau genommen sind Arrays und Strings ja Objekte, aber das tut jetzt nichts zur Sache.
Bei Objekten (Object und alle benutzerdefinierten) ist der Type Tag : und
danach der Name der Klasse. Zum Beispiel :TBlitzException.

Extending .. Type Tag!

Ich habe mir den Code für das Allozieren von Arrays angesehen und mich gewundert
ob man wirklich für jeden Aufruf einmal switch durchlaufen lassen muss, um Größe,
Initialwert und noch andere Informationen für den gewünschten Datentyp rauszukriegen.

Natürlich nicht!

Eigentlich zählt ja immer nur der erste Buchstabe. Den kann man als Ganzzahl darstellen.
Damit hätte man zum Beispiel für s den Wert 115. Diese Zahl als Schlüssel für ein
Array zu benutzen wäre nun aber auch leicht verschwenderisch, denn dieses Array müsste
ja 115 Felder haben, würde aber nur ca. 13 brauchen. Was tun?

Hello Type Key
Der Schlüssel zur komfortablen Datentyperei.

Meine Lösung ist jetzt ein zweites Array zu nehmen. Dieses hat die ASCII-Codes des ersten
Buchstaben eines jeden Type Tags als Schlüssel. Der jeweilige Wert ist eine Konstante die
fortan zur Repräsentation eines Datentyps verwendet werden kann. Das ist der Type Key.

Hier mal ein kleiner Codeausschnitt (noch nicht final, läuft aber):

Code: [AUSKLAPPEN]
enum BBTypeKey
{
/* ... */
   BBTYPEKEY_INT,
   BBTYPEKEY_LONG,
   BBTYPEKEY_FLOAT,
   BBTYPEKEY_DOUBLE,
/* ... */
   BBTYPEKEY_OBJECT,
   BBTYPEKEY_STRING,
   BBTYPEKEY_ARRAY
};

const BBTypeKey bbTypeTagToTypeKeyData[] =
{
/* ... */
   ['i'] = BBTYPEKEY_INT,
   ['l'] = BBTYPEKEY_LONG,
   ['f'] = BBTYPEKEY_FLOAT,
   ['d'] = BBTYPEKEY_DOUBLE,
/* ... */   
   ['$'] = BBTYPEKEY_STRING,
   [':'] = BBTYPEKEY_OBJECT,
   ['['] = BBTYPEKEY_ARRAY,
};

const BBTypeKeyInfo bbTypeKeyInfo[] =
{
/* ... */
   [BBTYPEKEY_INT] = {
      .size   = sizeof (BBInt),
      .init   = (void *)0,
      .ident   = "Int"
   },
   [BBTYPEKEY_LONG] = {
      .size   = sizeof (BBLong),
      .init   = (void *)0,
      .ident   = "Long"
   },
   [BBTYPEKEY_FLOAT] = {
      .size   = sizeof (BBFloat),
      .init   = (void *)0,
      .ident   = "Float"
   },
   [BBTYPEKEY_DOUBLE] = {
      .size   = sizeof (BBDouble),
      .init   = (void *)0,
      .ident   = "Double"
   },
/* ... */   
   [BBTYPEKEY_OBJECT] = {
      .size   = sizeof (BBObject*),
      .init   = (void *)&bbNullObject,
      .ident   = "Object"
   },
   [BBTYPEKEY_STRING] = {
      .size   = sizeof (BBString*),
      .init   = (void *)&bbEmptyString,
      .ident   = "String"
   },
   [BBTYPEKEY_ARRAY] = {
      .size   = sizeof (BBArray*),
      .init   = (void *)&bbEmptyArray,
      .ident   = "Array"
   },
};


Ein kleines Anwendungsbeispiel zur Verdeutlichung:

Code: [AUSKLAPPEN]
// wichtig für bbArrayNew
printf("sizeof (BBInt) = %i\n", bbTypeKeyInfo[bbTypeTagToTypeKeyData['i']].size);

// das Gleiche mit komfortablerem Makro
printf("sizeof (BBInt) = %i\n", BBTYPETAG_SIZE("i"));


Der Vorteil liegt auf der Hand: Jegliche typspezifischen Informationen können
nun einmal fest gespeichert werden ohne Platz zu verschwenden. Das Abrufen
ist auch extrem schnell, da nur für 2 konstante Arrays der Offset berechnet
werden muss. Egal welchen Datentyp man braucht, alles kann in bbTypeKeyInfo
gespeichert werden und muss nicht neu berechnet werden.

Extra-Super-Duper-Extended

Noch schnuckeliger sind die Type Keys ja, weil man mit ihnen auch individuelle Arrays
anlegen und nur die BBTYPEKEY_* Konstanten als Schlüssel benutzten kann.
Das mache ich zum Beispiel in blitz_array.c, weil es da einige Informationen gibt,
die nur für die Erstellung von BBArray benötigt werden. Ich nutze dafür die
Konvertierungsroutinen von Type Tags zu Type Keys, die ich in blitz_types.h
definiert habe. Diese stehen natürlich allen anderen für eigene Zwecke zur Verfügung.


Danke für eure Zeit, ich hoffe ich konnte euch etwas Neues erzählen. Falls ihr Fehler findet,
oder Wünsche habt, immer her damit. Das Modul soll schließlich für alle besser werden.
Beim nächsten Mal gibt's dann auch mehr "Candy", also neue Funktionen und so.


Stay caffeinated,
Fabian

Features, Dokumentation und ZOMBIES!

Samstag, 5. Mai 2012 von ProfJake
Hallo BlitzMax'ler,

die folgenden Zeilen sollen euch einen kleinen Ausblick auf
mein aktuelles Projekt geben: Die Überarbeitung des brl.blitz Modules.


Rückblick
Was wurde denn früher schon so vermurkst?

Wie sich einige vielleicht noch erinnern können, habe ich mal an
einer Standard library für BlitzMax gearbeitet (BSL). Im Laufe der
Entwicklung habe ich mich dabei allerdings immer mehr in den
Interna von BlitzMax festgebissen. Das führte dazu, dass ich dort
viel geändert habe ohne wirklich daran zu denken, dass das
ja dann auch jeder bei sich installieren müsste – schlecht.

Nach langjährigen Depressionen, Klinikaufenthalten und Kinder-
geburtstagen bei kolumbianischen Drogenbossen war es dann so weit:
Ich hatte genug Wahnsinn angesammelt um bei BRL vorstellig
zu werden. Und siehe da, kaum 2 Wochen nachdem ich Simon per E-Mail
genervt hatte, haben sie mit v1.48 alles (!) unter die zlib-Lizenz gestellt.

Awesome.


Na schön, was jetzt?
Wer liest schon Lizenzen? Ich will bunte Bilder!

Als Konsequenz davon kann ich jetzt Veränderungen im brl.blitz Modul
auf externen Domains veröffentlichen, nicht nur auf blitzmax.com.

Warum sollte man das wollen? Jeder der schonmal in den Quelltext
geschaut hat, wird genau das Gleiche gedacht haben wie ich: DAFUQ?
Einige von den Ninjaprüfungen die man bestehen muss sind hardcodierte
Speichergrößen, Zen-ähnliche Dokumentation (= nix) und Variablennamen
aus der Hölle. Nein wirklich. Hier mal ein Beispiel:

Code: [AUSKLAPPEN]
void bbStartup( int argc,char *argv[],void *dummy1,void *dummy2 ){
   int i,k;
   BBString **p;
[...]
   if( i>0 ){
      char *p;
      buf[i]=0;
      bbAppFile=bbStringFromUTF8String( buf );
      p=strrchr( buf,'/' );
      if( p ){
         *p=0;
         bbAppDir=bbStringFromUTF8String( buf );
      }else{
         bbAppDir=&bbEmptyString;
      }
   }
[...]
}


Hier wird Marks Lieblingsvariable p am Anfang einer 170 Zeilen
langen Funktion als BBString** deklariert. Aber 96 Zeilen
danach wird sie in einem if-Block als char* neudeklariert.
Viel Spaß beim nächtlichen Lesen.

Die Zielstellungen sind also leicht zusammen zu fassen:

  • Quelltext aufräumen
  • Features hinzufügen
  • alles dokumentieren


Bitte beachtet, dass dies NICHT die BSL ersetzt. Das hier
ist quasi die Grundlage für die Standard library und von ihr
somit unabhängig. Ich versuche mich auf die interne Struktur
zu konzentrieren, so dass man besser auf die C API zugreifen kann.
Features sollen nur dann dazukommen, wenn sie nicht durch
andere Module eingefügt werden können, z.B die Stringklasse.


Ausblick
Wann gibt's Geschenke?

Beim nächsten Mal zeige ich euch mal einige Neuerungen und
vielleicht sogar ein bisschen Quelltext. Es ist zwar noch alles in
so einer Art Alpha-Version, aber es läuft schon recht stabil.

Ich bin zwar immernoch fleißig am aufräumen, aber ein paar
Features sind schon eingebaut. So haben Strings ein paar Funktionen
mehr auf dem Kasten als jetzt. Wer den altes Worklog gelesen hat,
wird sie aber schon kennen. Auch der GC hat zwei popelig kleine
Helfer-Funktionen dazubekommen und es gibt ein Basisklasse
für Exceptions. Von der werden jetzt auch die TBlitzExceptions abgeleitet.


Werde versuchen bald eine Probeversion zu veröffentlichen.
Wer also Features will muss sich melden. Gleiches gilt auch für Proteste
gegen das einführen von Features, Stichwort "Code bloat".


Stay caffeinated,
Fabian

Gehe zu Seite Zurück  1, 2