SSC

Achtung! Das Projekt wurde eingestellt, da ich stattdessen von der Sprache Rust überzeugt wurde. Diesen Artikel behalte ich zu Bildungszwecken hier.

Eigentlich habe ich diese Programmiersprache nur als mein eigenes Werkzeug entwickelt. Ich bin Perfektionist und mit C, Java oder JavaScript zu arbeiten befriedigt mich nur beschränkt. SSC ist eine sehr abstrakte Sprache, die sich aber theoretisch dennoch effizient ausführen lässt. Die erste offizielle Anwendung fand im Sonden-Projekt "CanSat" 2016 statt. Hierfür war auch eine ausführliche Dokumentation der Sprache notwendig, um eine Bewertung meines Programmes zu gewährleisten. Dieses Dokument soll eine überarbeitete und praxisnähere Ausgabe jener Dokumentation sein.

Diese Dokumentation ist offen zugänglich und darf nicht als Kopie, sondern nur als Verweis auf diese Seite (l3p3.de) weitergegeben werden. Sie zu erlernen, kann die Denkweise beim Programmieren stark beeinflussen. Eine reine Anwendung ist zum Stand 2018 noch nicht so praktikabel. Außerdem ist SSC nur ein Zwischenschritt zu der noch abstrakteren Programmiermethode SENG (script engine), an der ich ebenfalls arbeite. Jene Methode baut auf SSC im Sinne des Bootstrappings auf. SSC (SENG source code) wird nach ihrer Fertigstellung (idealerweise) nicht mehr benötigt. Ich möchte verhindern, dass SSC später in Konkurrenz zum eigentlichen Zielprodukt steht.

Motivation

Ich bevorzuge abstrakte Programmiersprachen und setze sie überall dort ein, wo es geht. Dabei gefällt mir aus der Welt der etablierten Sprachen der Ansatz von JavaScript am meisten, besonders dessen Portabilität und Einfachheit. Heute sind Rechnersysteme "intelligent" genug, zu sprechen und zu hören, zu sehen, komplexe wirtschaftliche Vorhersagen zu treffen, gute Produktempfehlungen an Internetnutzer zu richten oder beste Fahrtwege mit Berücksichtigung von Umwelteinflüssen zu finden. In Anbetracht dieser Tatsachen scheint es mir absurd, dem Rechner im Beispiel von Java noch mitteilen zu müssen, dass 15 eine Zahl und true ein Wahrheitswert sind. Und new Rose() ist vom Typ Rose ist vom Typ Rose. Sicher hat diese Redundanz ihre historische Berechtigung, nämlich wenn ein Programm mit einem primitiven Texteditor oder gar mit dem Stift auf Papier verfasst wird. Bei Textverarbeitung, grafischer 2D- und 3D-Gestaltung und Erzeugung von Musikstücken ist der Übergang vom Quelltext hin zu interaktiven Eingabemöglichkeiten längst vollzogen — und ein Schritt zurück scheint in den allermeisten Fällen absurd. Ich möchte einen radikalen Neuanfang wagen. Schon seit vielen Jahren denke ich oft darüber nach, was eine ideale saubere Programmiersprache ausmacht. Schon mehrere Fachgenossen, mit denen ich darüber sprach, sind der Meinung gewesen, dass Programmierung bald automatisiert wird. Ich kann mir eine komplette Automatisierung nicht vorstellen. Wiederholende Schritte werden durch Funktionsbanken minimiert. Bei Algorithmen sehe ich kein Bedarf nach künstlicher Intelligenz. Denn Probleme werden ausschließlich von Menschen, die der Schwäche des Willens unterliegen, beschrieben. Ein Rechner kann noch so viel verstehen — einen Willen zur Veränderung wird er nur haben, wenn dieser explizit einprogrammiert wurde — und allein dafür sehe ich schon keinerlei Anlass! Die Symbiose von menschlicher Kreativität und Willen in Verbindung mit künstlicher Intelligenz und Rechenkraft wird also in absehbarer Zeit bestehen bleiben. Also macht es Sinn, sich ein optimiertes Konzept zu suchen, mit dem der umzusetzende Wille dem Rechner kommuniziert werden kann — eine optimale Programmiersprache also. Analog zur Mathematik soll sie möglichst abstrakt und übertragbar sein. Um die Umsetzung in Maschinenbefehlsketten haben sich die Rechner zu kümmern! SSC selbst ist nicht annähernd so optimal, wie ich es mir wünsche. Aber für die Programmierung der "optimalen" Programmierumgebung reicht meines Ermessens nach keine der verbreiteten Programmiersprachen aus — daher muss SSC als Kompromiss einspringen. Für manche mag SSC mit ihrer Abstraktheit eher komplizierter als andere Sprachen sein. Für mich ist sie einfacher und ich mache generell nur wenige Denkfehler.

Grundlagen

Gemessen an meinen Idealen ist SSC eine primitive Textsprache, die auch mit Stift auf Papier angewendet werden kann. Sie ist jedoch redundanzarmer und abstrakter als beispielsweise Javascript. Sie ist wie Skriptsprachen aufgebaut und kann als eine solche behandelt werden. Vor der Ausführung von Programmtext kann dieser aber auch in einen Bytecode übersetzt werden, welcher wiederum von einer virtuellen Maschine ausgeführt oder in eine Maschinenbefehlskette übersetzt werden kann.

Es gibt eine begrenzte Menge an Schlüsselbegriffen und vorgegebenen Klassen, welche alle höchstens 3 Zeichen umfassen. Dazu kommen Struktursymbole und Operatoren. Es besteht bei der Belegung dieser Symbole große Ähnlichkeit mit C-ähnlichen Sprachen (Java/JavaScript).

Wie bei vielen Skriptsprachen üblich, können in SSC viele redundante Klammern und Trennzeichen weggelassen werden. Das aus JavaScript bekannte (und berüchtigte) Konstrukt with(...){...} findet in ähnlicher Form ständige Verwendung. Es ist in SSC sehr einfach, verschachtelte Klassen zu erstellen und auch set- und get-Methoden sind praktisch anwendbar. Ebenfalls sehr einfach können Unterklassen erstellt und erweitert werden. Enumeratoren sind fester Bestandteil und sie können als Schlüssel in Tabellen und als abstrakte Werte verwendet werden, anstatt intern Strings zu benutzen, wie es bei JavaScript und Java leider immer üblicher wird. Ein effektives Programm in SSC benötigt deutlich weniger Zeichen als in anderen Sprachen und lässt den zugrundeliegenden Algorithmus viel einfacher erkennen und manipulieren als mit alten Sprachen. Noch eine gewöhnungsbedürftige Änderung ist, dass Klammern und Trennzeichen optional sind und oft weggelassen werden können. Damit ist die Einrückung nicht völlig egal, wie es bei C-ähnlichen Sprachen der Fall ist. Zu allem Überfluss sind innerhalb einer Funktion direkte Sprünge möglich.

Es gibt eine umfangreiche zentrale Bank an Funktionen und Daten, die automatisch per Netzwerk auf allen angebundenen Rechnern zur Verfügung steht und in Programme einbezogen werden kann. Mittels automatischer Paketverwaltung können Bankelemente einfach im Programm adressiert werden — und werden bei der Installation automatisch geladen. Der Programmierer muss sich um nichts mehr kümmern außer um sein Programm — und sein Leben, natürlich. SSC kann in der generellen Entwicklungsumgebung (wie auch andere Datentypen) verfasst werden und ist voll in das neue Ökosystem integriert, welches ein Killer sämtlicher Betriebssysteme ist: Von Symbian bis Windows.

Beispielprogramm: Primzahlen

Um ein grobes Gespür zu vermitteln, biete ich hier ein kleines Beispiel. Alle verwendeten Sprachelemente werden natürlich später erklärt.

a=lop 2,1000
  if idx>2 lop 2,idx-1
    if a.idx%idx==0 a.cnt
  .app.terminal.write a.idx

Dieses Programm durchläuft Zahlen von 2 bis 1000. Für jede Zahl wird geprüft, ob es eine kleinere gibt, die sie teilt. Falls es keine gibt, wird sie im Terminal ausgegeben. Zu beachten ist, dass die Überprüfung für 2 übersprungen wird, da sonst die Schleife über 2 und 2-1=1 ausgeführt laufen würde. Für 3 wird nur die 2 einmalig überprüft. Das gleiche lässt sich zum Spaß auch mit Sprungbefehlen lösen:

n=2
:c
a: n+!
m=2
b: if n%m==0 :d
m+!
if m<n :b
c: .app.terminal.write n
d: if n<1000 :a

Denjenigen, die daran keinen Spaß haben, zur Beruhigung: Durch automatische Optimierungen sollten beide Implementierungen die gleiche Befehlskette generieren. Man sieht deutlich, dass Sprungbefehle nicht für Geschwindigkeitssteigerung angeboten werden, sondern die Übersichtlichkeit unterstützen sollen.

Begriffserklärung

Da ich schon lange programmierte, bevor ich anfing, alles zu wissen, verwende ich wahrscheinlich unübliche Begriffe. Außerdem möchte ich auch für Anfänger Klarheit schaffen.

Begriff (aka)ErklärungBeispiele
Block (scope)Ansammlung an Anweisungenif(...){...}
f=fun(x){...}
Verweis (Variable)Block-abhängig namentlich identifizierter Platzhalter für Objektesdl=43
sag sdl-1
Eigenschaft (Attribut)Objekt-abhängiger Verweis auf Kinder-Objekteich.sdl=43
Objekt (Abstraktwert)Instanz einer Klasse, die dessen Eigenschaften instanziell übernimmt; alle nachfolgenden Dinge sind auch Objekteich={.sdl=43}
sache=obj!
FunktionObjekt, das einen Block repräsentiert und ausführbar istanull=fun a=0
y=f 43
MethodeFunktion als Eigenschaft, die sich auf das Eltern-Objekt beziehtich.hüpf!
Klasse (constructor)Objekt, von dem Instanzen gebildet werden könnenMensch=obj+{.alter=0}
Wert (Primitivwert)Einer der folgenden 3 Datentypen
numerischer Wert (Zahl)Element der komplexen Zahlensdl=43
Auswahl-Wert (enum)Individuell bestimmte Optionos=oses#debian
Tabelle (map)Zuordnung von Werten zu Schlüsselnoses=[#debian:os!]
boolescher Wert (Wahrheitswert)Wahr oder falschx=sdl>42
Menge (set)Menge, die Elemente enthält oder nichtmyoses=set!+[#debian]
Vektor (array)Menge, die Elemente in bestimmter Reihenfolge enthältospri=[#debian,#wxp]

Symbolverzeichnis

SymbolErklärung
abcVerweis
#abcAuswahl
"abc"UTF-8-String
.abcEigenschaft
abc:Sprungmarke setzen
:abcSpringen zur Marke
xiImaginäre Zahl
-xNegative Zahl
/xStammbruch
x+y, x-y, x*y, x/y, x%y, x^yAddieren/Subtrahieren/Multiplizieren/Dividieren/Modulo/Potenzieren
x&y, x|y, x~yUnd/Oder/Exklusiv-Oder
~xNicht
x<y, x<=y, x>y, x>=yNumerischer Vergleich
==, x~=yÜberprüfung Gleichwertigkeit
===, x~==yÜberprüfung Identität
abc=...Verweis/Eigenschaft auf Objekt setzen
f!Instanzieren
f(...)Instanzieren mit Parametern
x~!Boolesch umkehren
x+!, x-!Um 1 erhöhen/verringern
x+=y, x-=y, x*=y, x/=y, x%=y, x^=yVerrechnen und x überschreiben
{...}Objekt mit darauf bezogenen Anweisungen
[...]Tabelle/Menge/Vektor
nulVerweis ist Wertlos
retRückgabewert von Funktion
req xTautologie
if x ...Bedingte Ausführung
els ...Sonstige Ausführung
swt x[...]Führt x aus der Sprungtabelle aus
wfr xWartet bis Bedingung erfüllt
lopSchleife
idx, itmAktuelles Schleifenelement
brk, cntBlock verlassen/neu beginnen
lop ...Endlosschleife
lop x ...Wiederholen, solange x wahr ist bzw. x-mal
lop x,y ...Von x bis y wiederholen

Struktursymbole

Diese sind Trennzeichen und Klammern.

KontextStruktur
Block{x;x}
Parameter(x,x)
Tabelle/Menge/Vektor[x,x]

Sie können mit Ausnahme von [] weggelassen und ggf. durch Leerzeichen ersetzt werden, wenn die Struktur eindeutig ist. Werden sie weggelassen, so wird sich an Tabulator-Einrückung orientiert. Fehlt diese, so wird nach der Methode des minimalen Rahmens vorgegangen. Ich bevorzuge, Struktursymbole nur in Notfällen zu verwenden und möglichst viel einzurücken. () können benutzt werden, um Dinge zusammenzufassen.

Bei mangelhafter Einrückung/Abgrenzung können Dinge sehr kompliziert werden und schnell zu ungewollten Effekten führen. Beispiel:

g=f x=5

Dieser Text bedeutet g=f(x=5) bzw. x=5;g=f(x) — und nicht g=f;x=5. Eine korrekte Einrückung oder ;/() würde Klarheit schaffen. Einrückung scheint mir am schönsten:

g=f
  x=5

g=f
x=5

Ja, das eine Tabulatorzeichen kann den Unterschied machen! Nimmt f im ersten Fall keine Parameter entgegen oder ist gar keine Funktion, wird der Syntaxfehler gemeldet. Ja, der Syntax ist von Verweis-Objekt-Klassen abhängig!

Kommentare

Längere Dokumentationen haben im Quelltext nichts zu suchen. Also gibt es ausschließlich einzeilige Kommentare, die durch ein // begrinnen.

Vorgegebene Klassen

Folgende Klassen sind vorgegeben und können, wie alle importierten Dinge, nicht verändert, wohl aber erweitert werden.

KlasseErklärungBeispiel
objObjekt{}
obj!
clsKlassestudent=schüler+{.abitur=1}
obj+{.x=5}
numZahl43
num!+43
(7+3i)^-1
bolWahrheitswertsdl==43
tru|fal
optAuswahlwert#apfel
opt!+[#apfel,#birne]+#apfel
mapTabelle[1:"s",5:"z"]
map!+{.key=opt;.val=num}
arrVektor[1,2,3]
setMengeset!+[#A,#B]+[#C]
map!.vals
strZeichenkette"abc"
"x="+x
funFunktionfun x ret=x*2

Vorgegebene Objekte

ObjektErklärungBeispiel
eulEulersche Zahle^5
piKreiszahle^(pi/3)
truWahrlop tru endlos!
x=tru
falFalschlop fal nie!
modModulobjektmod.ding=obj
.ding=obj
mod.app.terminal.write "Hallo, Welt!"
libBankwfr lib.time.point!+5