Vorbemerkung:
Hier geht es im zwei relativ junge und noch nicht zu Ende entwickelte
Pogrammierpsrachen, die
- nicht morgen schon C++, Java & Co komplett ersetzen sollen,
- nicht für Softwarefirmen, die bereits einen riesigen Pool von
Softwaremodulen in einer anderen Sprache aufgebaut haben, geeignet
sind und
- nicht auf 8-Bit-Mikrocontroller lauffähig sind,
also derzeit eher den ambitionierten und neophilen Freizeitprogrammierer
auf PCs oder nicht allzu mickrig ausgestatteten Embedded-Systemen
ansprechen.
Unter diesem Gesichtspunkt würde ich gerne die Diskussion hier sehen.
————————————————————————————————————————————————————————————————————————
Ich bin schon länger auf der Suche nach einer Programmiersprache, die
die Geschwindigkeit von C mit der Ausdrucksstärke von Python verbindet
oder zumindest einen guten Kompromiss zwischen beiden darstellt.
Die heißesten Kandidaten in dieser Richtung waren für mich bisher
Haskell und Lisp, die beide den zusätzlichen Vorteil haben, dass die
Arbeit mit ihnen auf Grund ihrer Andersartigkeit unglaublich viel Spaß
macht.
Da ich sie aber nur hobbymäßig einsetze, bin ich nicht wirklich geübt
darin, so dass ich für das Zusammenklopfen von Programmen, die ich
schnell mal brauche, meist doch auf Python zurückfalle (oder C, wenn die
Laufzeit eine Rolle spielt).
In diesen beiden Threads
Beitrag "go or nogo ;)"Beitrag "Scriptsprache lernen"
wurden nun weitere Alternativen genannt, u.a. Rust und Nimrod. Weil mich
Stefan noch einmal daran erinnert hat
Beitrag "Re: Was ist eine Instanz?"
gestern schlechtes Wetter war und von Rust kürzlich ein neues Release
herauskam, habe ich die beiden Compiler installiert, die Tutorials
durchgearbeitet und angefangen, damit herumzuspielen. Hier sind meine
vorläufigen Eindrücke und Erkenntnisse:
So richtig aus den Socken gehauen (so seinerzeit bei Pascal, C, Python,
Lisp und Haskell) hat es mich bei keiner der beiden Sprachen, aber man
ist ja mittlerweile auch ziemlich verwöhnt ;-)
Ich habe hier die für mich persönlich wichtigen High- und Lowlights
zusammengestellt:
Beide:
- Multiparadigma (prozedural, objektorientiert und ein Bisschen
funktional)
- statische Typisierung, strenge Typprüfung, Typinferenz (mit
Einschränkungen)
- durch Kompilierung, statische Typisiering und andere
Spracheigenschaften schnell (habe allerdings keine Benchmarks gemacht)
- recht hohes Abstraktionsniveau
- keine Speicherlecks, Array-Überläufe und invalide Pointer
- mächtiges Makrosystem, gute Unterstützung von Metaprogrammierung
- Operaturüberladung, Closures, Generics
- ziemlich stabil, aber noch im Aufbau und Wandel begriffen
- Angebot an Bibliotheken ist da, aber noch bei weitem nicht so
umfangreich
wie bspw. für Python
- Foreign-Function-Interface zur Einbindung von bestehendem Code
vorhanden
- keine Anfängersprachen, aber für jemanden, der bereits eine der
Mainstream-Sprachen beherrscht, relativ leicht und schnell zu lernen
Rust:
- Kompromiss zwischen Ressourcenkontrolle und Abstraktionsniveau ist in
weiten Grenzen wählbar
- Syntax: Blockstruktur ähnlich wie C, Deklarationen ähnlich wie Pascal
- algebraische Datentypen mit Pattern-Matching
- etwas mehr funktionales Feeling als bei Nimrod, aber ohne rigorose
Einschränkungen wie bspw. bei Haskell
- eine Art Typklassensystem durch Traits nachgebildet
- Schwerpunkt auf sicherer multithreaded Programmierung
- Speicherprobleme, Race-Conditions u.ä. werden vielfach bereits zur
Compilezeit erkannt oder bereits durch das Sprachdesign ausgeschlossen
- verschiedene Speichermöglichkeiten für Variablen: Static, Stack,
Boxed, Reference-Counting, Garbage-Collection.
- relativ lange Kompilierzeiten
- kein interaktiver Modus
Nimrod:
- Syntax: Blockstruktur ähnlich wie Python, Deklarationen ähnlich wie
Pascal
- benutzerdefinierte Operatoren
- named Arguments und Defaultwerte für Argumente
- Iteratoren/Generatoren ähnlich wie Python
- Subranges von Integer- und Enum-Typen als neuer Typ
- Makrosystem wohl noch mächtiger als in Rust
- Interpreter für interaktive Benutzung vorhanden, aber noch ziemlich
buggy
Jede der beiden Sprachen hat ein paar coole Features, die die jeweils
andere nicht hat, weswegen ich bei keiner von beiden klar "Die isses!"
sagen kann.
Tendenziell sagt mir aber Rust ein klein wenig mehr zu, weil es – so
mein Eindruck – mehr Möglichkeiten bietet, den Programmstil je nach Art
der Anwendung (und aktueller Laune ;-)) aus den folgenden Alternativen
auszuwählen:
- C-Stil: geschwindgkeitsoptimiert, Variablen primär auf dem Stack oder
statisch, feste Variablengrößen, ...
- C++-Stil: Objekte, Traits, dynamische Container-Typen, Smart-Pointers,
...
- Python-Stil: dynamische Container-Typen, Garbage-Collection, nicht
mehr viel nachdenken müssen, ...
- Haskell-Stil (naja, wenigstens ansatzweise): immutable Variablen,
Algebraische Datentypen, Pattern-Matching, logische Fehler führen mit
recht hoher Wahrscheinlichkeit zu Compilezeit-Fehlern, ...
Gerade bei größeren Programmen, die oft aus High- und Low-Level-,
rechenzeitkritischen und -unkritischen Teile bestehen, hat man somit für
jeden Teil die richtigen Werkzeuge, ohne dafür die Sprache wechseln zu
müssen.
Wesentlich besser würde mir Rust aber gefallen, wenn es wie in Nimrod
einen interaktiven Interpreter, benutzerdefinierte Operatoren und
Generatoren gäbe. Außerdem habe ich eine wachsende Abneigung gegen
geschweifte Klammern, die nicht nur hässlich aussehen, sondern auch auf
deutschen Tastaturen schwer zu tippen sind. Leider braucht man sie in
Rust noch öfter als in C(++).
Trotzdem werde ich in der nächsten Zeit wohl noch etwas tiefer in Rust
eindringen, auch in der Hoffnung, dass vielleicht das eine oder andere
fehlende Feature noch nachgereicht wird.
Wenn jemand von euch ebenfalls schon Erfahrungen mit diesen Sprachen
gesammelt hat, würde mich eure Meinung dazu interessieren.
Rust ist auch deshalb cool, weil die Entwickler schwer darauf acht
geben, daß es (für kleine eingebettete Systeme) auch ohne
Standardbibliothek sinnvoll nutzbar ist.
Warum wird der Kram immer, immer komplizierter??
Was nützt es, die Auswahl zwischen X Programmiersprachen zu haben, wenn
man 5 Minuten für den Algorithmus des Programmes braucht, aber 5 Wochen,
um sich mit mistiger Syntax herumzuzanken?
Das mußte ich mal sagen, auch wenn es nicht zum Thema passt und wohl
auch niemanden anhebt.
MfG Paul
Paul Baumann schrieb:> Was nützt es, die Auswahl zwischen X Programmiersprachen zu haben, wenn> man 5 Minuten für den Algorithmus des Programmes braucht, aber 5 Wochen,> um sich mit mistiger Syntax herumzuzanken?
Es geht ja eben darum, die mistige Syntax von C und C++ zu verbessern,
so daß der Programmierer leichter und klarer ausdrücken kann, was er
will.
Paul Baumann (paul_baumann) schrieb:
> Warum wird der Kram immer, immer komplizierter??
Wahrscheinlich liegt's ein wenig hieran:
http://www.linux-magazin.de/Ausgaben/2012/10/Rust/%28offset%29/8
" Rust soll sich offenbar zu einer eierlegenden Wollmilchsau entwickeln:
Der Code will die Geschwindigkeit von C++ erreichen, eine
Speicherverwaltung verhindert nervende Abstürze, die funktionale
Programmierung vereinfacht nebenläufige Aufgaben. Um das alles zu
erreichen, übernehmen die Entwickler die ihrer Meinung nach besten
Konzepte aus anderen Sprachen. Einfluss genommen haben laut
Sprachreferenz so illustre Gestalten wie NIL, Hermes, Erlang, Sather,
Newsqueak, Napier, Go, SML, C#, C++, Haskell, Python und Ruby. Die
erstgenannten Exoten stammen durchweg aus den 80er Jahren.
Das Ergebnis ist ein Programmiersprachen-Cocktail "
Außerdem wäre für Windows die Frage, wie leicht lassen sich solche
Sprachen zu GUI Programmem übersetzen. Daran hapert's dann oft, weil
sich solche Exoten in erster Linie für sich selbst interessieren.
Solange nicht so eine labernde Syntax wie die von Delphi übernommen
wird, denke ich, kann man gespannt sein, ob da was Brauchbares
rauskommt. Warum sollte man es von vornherein verurteilen?
Yalu X. schrieb:> Außerdem habe ich eine wachsende Abneigung gegen> geschweifte Klammern, die nicht nur hässlich aussehen, sondern auch auf> deutschen Tastaturen schwer zu tippen sind.
Deshalb arbeite ich mit einer amerikanischen Tastatur, wenn es um das
Programieren geht.
Ich finde es interessant, welche Klimmzüge veranstaltet werden um eine
neue Sprache zu etablieren bzw. zu greieren.
Ein Frage die mich beschäftigt ist die, warum soll ich eine neue Sprache
lernen (hätte kein Problem damit), wenn das OS auf dem ich diese Sprache
einsetze in purem C und ein bisschen Assembler geschrieben ist?
Macht aus meiner Sicht keinen Sinn. Denn wenn das OS in der neuen
Sprache geschrieben wäre, dann sollte doch das Gesamte in sich stabiler
sein? Oder sehe ich etwas falsch?
Vor einigen Jahren gab es einmal einen Ansatz zur Sprache D, sehr C
lastig.
Davon habe ich nichts mehr gehört / gelesen.
Habe in meinem Umfeld noch kein OS gesehen, das mit einer anderen
Sprache als C/Assembler geschrieben war/ist.
Wenn hierzu jemand eine Info hätte, würde mich das sehr interessieren.
Hello World ;) schrieb:> Außerdem wäre für Windows die Frage, wie leicht lassen sich solche> Sprachen zu GUI Programmem übersetzen. Daran hapert's dann oft, weil> sich solche Exoten in erster Linie für sich selbst interessieren.
Erstens ist Rust kein Exot, es vereint etablierte moderne Konzepte und
macht dir keine Vorschriften welches Paradigma du zu nutzen hast. Exoten
sind Sprachen wie Haskell und Lisp.
Zweitens warum sollte es Probleme mit der GUI geben? Rust kann ohne
Probleme C Code aufrufen und damit auch die WinAPI und GTK. Wrapper und
Bindings gibt es schon.
DingsDa schrieb:> Ein Frage die mich beschäftigt ist die, warum soll ich eine neue Sprache> lernen (hätte kein Problem damit), wenn das OS auf dem ich diese Sprache> einsetze in purem C und ein bisschen Assembler geschrieben ist?> Macht aus meiner Sicht keinen Sinn. Denn wenn das OS in der neuen> Sprache geschrieben wäre, dann sollte doch das Gesamte in sich stabiler> sein? Oder sehe ich etwas falsch?
Klar mit C und Assembler kannst du alles schreiben was du willst. Aber
mal im Ernst willst du immer noch so programmieren wie in den 70er/80er?
Es gibt gute Gründe weshalb sich neue Sprachen und Konzepte entwickelt
haben, nämlich um die Produktivität, Wiederverwendbarkeit und Sicherheit
zu steigern. Vor allem die Sicherheit wird in Zukunft immer wichtiger
werden und bei den Prozessoren die es heute gibt, kann man auf ein paar
Nanosekunden verzichten und eine Sprache einsetzen die automatische
Rangechecks etc. vornehmen. Gerade C hat ein paar Eigenschaften die
Exploits begünstigen, dass sieht man immer wieder in Bugfixes im Linux
Kernel.
Und dann gibt es da noch etwas, dass erst vor ein paar Jahren ein Thema
(auf Heimrechnern) geworden ist: Parallität. Die Prozessoren haben immer
mehr Kerne und Gesamtleistung. Das Problem ist nur, dass von der
Gesamtleistung teils nur wenig übrig bleibt, dank Raceconditions und
Co.. Es werden dann Sprachen entwickelt die das verbessern sollen, wie
z.B. Go und Rust. C willst du da nicht verwenden und C++ muss/musste
dafür noch nachrüsten.
DingsDa schrieb:> Habe in meinem Umfeld noch kein OS gesehen, das mit einer anderen> Sprache als C/Assembler geschrieben war/ist.> Wenn hierzu jemand eine Info hätte, würde mich das sehr interessieren.
Das ist natürlich klar. Die etablierten und für den produktiven Gebrauch
entwickelten Betriebsysteme (Linux/Windows/MacOS...) sind das Resultat
mehrerer Jahre/Jahrzehnte, da stecken mehrere millionen Codezeilen drin.
Sowas schreibt man nicht einfach so mal neu. Damals gabs nur C und
Assembler.
TriHexagon (Gast) schrieb:
Hello World ;) schrieb:
>> Außerdem wäre für Windows die Frage, wie leicht lassen sich solche>> Sprachen zu GUI Programmem übersetzen. Daran hapert's dann oft, weil>> sich solche Exoten in erster Linie für sich selbst interessieren.> Erstens ist Rust kein Exot, es vereint etablierte moderne Konzepte und> macht dir keine Vorschriften welches Paradigma du zu nutzen hast. Exoten> sind Sprachen wie Haskell und Lisp.
Käse. Natürlich ist Rust ein Exot. Alle neuen Programmierdialekte die
sich noch nicht durchgesetzt haben führen ihr Dasein als Exot unter den
Eteblierten. Lisp ist alles andere als ein Exot. Lisp hat seine
Tauglichkeit längst bei AutoCAD unter Beweis gestellt. Haskell ist für
mich dagegen ebenso eine recht exotische Programmiersprache. Was wurde
damit bisher groß entwickelt? Im Gegensatz zu Rust ist Haskell aber
zumindest schon länger in der Entwicklung.
ICh hab außerdem gar nichts gegen neue Dialekte. Die Frage die sich mir
stellt ist eher, wer braucht die eignetlich? Wo ist der Mehrwert?
Außerdem gilt generell für alles was entwickelt wird, neue
Programmiersprache, neue Probleme. Und den zeitlichen Aufwand den man
dort investiert muss man an anderer Stelle einsparen wie immer im Leben.
Hello World ;) schrieb:> Käse. Natürlich ist Rust ein Exot. Alle neuen Programmierdialekte die> sich noch nicht durchgesetzt haben führen ihr Dasein als Exot unter den> Eteblierten. Lisp ist alles andere als ein Exot. Lisp hat seine> Tauglichkeit längst bei AutoCAD unter Beweis gestellt. Haskell ist für> mich dagegen ebenso eine recht exotische Programmiersprache. Was wurde> damit bisher groß entwickelt? Im Gegensatz zu Rust ist Haskell aber> zumindest schon länger in der Entwicklung.
Du schaust nur auf die Verbreitung und die ist bei Rust natürlich noch
verhalten. Rust ist noch nicht fertig, es können immer noch große und
starke Designänderungen kommen. Vielen Gefällt der Gedanke, dass jede
Zeile Code mit der Zeit unbrauchbar werden kann, da sich noch viel
ändern kann, einfach nicht. In Sachen Design ist Rust relativ
konservativ und streut noch Puderzucker drauf.
Hello World ;) schrieb:> ICh hab außerdem gar nichts gegen neue Dialekte. Die Frage die sich mir> stellt ist eher, wer braucht die eignetlich? Wo ist der Mehrwert?> Außerdem gilt generell für alles was entwickelt wird, neue> Programmiersprache, neue Probleme. Und den zeitlichen Aufwand den man> dort investiert muss man an anderer Stelle einsparen wie immer im Leben.
Da geb ich dir Recht, aber die alten Programmiersprachen wie C und C++
zu der es noch keine richtige Alternativen gibt, sind alles andere als
Perfekt. C ist voller Designfehler und ohne Erfahrung gefährlich. C++
hat davon noch so einiges geerbt (dank C Subset) und ist mit der Zeit zu
einem unüberschaubaren und komplexen Ungeheuer mutiert. Die
fundamentalen Probleme der beiden Sprachen werden nicht mehr
ausgebügelt, da sonst Unmengen von Code ungültig werden würde und sich
das Standardkomitee nicht traut einen harten Schnitt zu machen. Also
gibt es nur eine Lösung: eine neue bessere Sprache muss her, die von der
Erfahrung der letzten Jahrzehnte profitiert. Das ist jedenfalls meine
Meinung bei den Systemsprachen, wo sich nichts mehr getan hat bis vor
kurzem. Vielleicht kann Rust/Go/Nimrod endlich mal eine moderne
Alternative bieten.
Yalu X. schrieb:> gestern schlechtes Wetter war und von Rust kürzlich ein neues Release> herauskam, habe ich die beiden Compiler installiert, die Tutorials> durchgearbeitet und angefangen, damit herumzuspielen.
Hallo Yalu!
Du bist ja echt fix! Ich hatte Nimrod vor ca. 3 Monaten entdeckt, als
ich nach Neuigkeiten zu Rust gesucht hatte. Seit dem habe ich mich im
Wesentlichen auf Nimrod konzentriert -- Rust beobachte ich aber weiter,
habe es aber bisher nicht installiert. Momentan benutze ich vorwiegend
Ruby -- ich hatte damit vor einigen Jahren angefangen. Ist auch eine
schöne, elegante Sprache, gefällt mir ein wenig besser als Python. Aber
manchmal hätte man eben gerne Geschwindigkeit vergleichbar zu C, und
wenn Projekte etwas größer werden, erscheint mir statische Typisierung
zusammen mit all den Überprüfungen, die ein Kompiler machen kann, doch
vorteilhaft.
Von den modernen schnellen, universellen Sprachen, die auch für
Systemprogrammierung nutzbar sind, erscheinen mir derzeit Nimrod und
Rust am interessantesten, jedenfalls in der freien Welt. Kürzlich kam ja
Swift heraus, als überfälliger Nachfolger von Objective-C. Interessiert
mich nicht wirklich. Für Matlab ähnliche Anwendungen ist natürlich Julia
sehr interessant. Und Go und nun Dart sollte man auch nicht vergessen,
Go soll ja recht einfach sein, und wäre damit vielleicht gerade für
Hobbyprogrammierer interessant. Und Dart eben als Java-Script
Alternative. Haskell ist natürlich vom Konzept sehr interessant, bei
einigen Benchmarks aber doch recht langsam. Python und Ruby -- ich
denke dass deren große Zeit etwas zu Ende geht, auch wenn mit PyPy und
Cython für Python das Geschwindigkeitsproblem nicht mehr so groß ist.
Aber heute würde ich statt der beiden wohl eher Go oder Julia lernen --
nun gibt es für die letztgenannten auch gute GTK wrapper, was mir
wichtig ist.
Aber nun zurück zu Rust und Nimrod:
Ein wesentlicher Aspekt ist, dass Rust von einem größeren Team
entwickelt wird, einige davon wohl bezahlte Ganztagsprogrammierer. Bei
Nimrod ist es wohl ein Hauptentwickler mit einigen Unterstützern -- wohl
eher unbezahlt, aber sehr helle Köpfe. Und bei Nimrod steckt wohl eher
ein Plan hinter der Entwicklung, bei Rust geht es noch etwas chaotisch
zu. Etwa zu der Speicherverwaltung bei Rust -- Garbage-Collector mag man
nicht so recht, daher gibt es diese "sicheren" (owned) Pointer -- habe
ich noch nicht so richtig verstanden, ich hatte dazu auch manchmal
widersprüchliches gelesen. Nimrod hat einen Garbage-Collector, der
weitgehend echtzeitfähig sein soll, und zusätzlich einfache Pointer die
manuell verwaltet werden. Beeindruckt hat mich an Nimrod die Eleganz und
Kompaktheit -- der Compiler hat wohl nur einige 10k Zeilen Code und
übersetzt sich selbst in wenigen Sekunden. Grundsätzlich ist Nimrod wohl
wirklich als universelle Sprache konzipiert, Systemprogrammierung (ein
minimaler bootfähiger Kernel existiert!), Scripting bis zu großen
Anwendungen. Rust ist wohl auch universell, aber Hauptziel war wohl ein
multitaskingfähiger Browser und Betriebssystemprogrammierung. Als ein
Beispiel hatte ich mir mal deren GTK2-Editor Aporia angesehen, ein gedit
Equivalent, in wenigen Sekunden installiert, läuft gut, und der
Quellcode sieht recht gut aus, ähnlich wie bei Python oder Ruby.
Übrigens was mich sehr an Rust stört, sind die von C übernommenen
geschweiften Klammern. Irgendwie habe ich da den Eindruck, dass man
unbedingt ein vertrautes Erscheinungsbild haben wollte, damit sich C und
Java Programmierer gleich zuhause fühlen. Und sonst: Nimrod generiert ja
gewöhnlich C Zwischencode, so dass man Nimrod grundsätzlich auch für
8-Bit Mikroprozessoren einsetzen könnte -- jedenfall wurde irgendwo auch
ein AVR erwähnt, Das Problem sind wohl eher die angepassten
Bibliotheken, war früher für GCC ja auch das Problem. (Ich persöhnlich
denke allerdings, dass C für 8-bit gut genug ist.). Bindings zu
C-Bibliotheken lassen sich für Nimrod übrigens recht einfach mit einen
Tool und ein wenig Handarbeit erstellen -- ich hatte kürzlich einfache
GTK3 Bindings aus den C-Headern erzeugt. Ja das wäre es dann erstmal --
ich werde mir die übrigen Beiträge dann auch noch mal ansehen...
Gruß
Stefan
DingsDa schrieb:> Ein Frage die mich beschäftigt ist die, warum soll ich eine neue Sprache> lernen (hätte kein Problem damit), wenn das OS auf dem ich diese Sprache> einsetze in purem C und ein bisschen Assembler geschrieben ist?
Rust kann man sehr gut und einfach mit C zusammen einsetzen.
Warum man nicht einfach rasch das OS auch in Rustz schreibt? Mach mal.
Und berichte nächste Woche von deinen Erfahrungen. g
Stefan Salewski schrieb:> bei Rust geht es noch etwas chaotisch> zu. Etwa zu der Speicherverwaltung bei Rust -- Garbage-Collector mag man> nicht so recht,
Rust hat sehr wohl einen Garbage Collector, sowohl einen echten, als
auch Reference Counting.
Die Unterstützung ist nur vor geraumer Zeit aus dem Sprachkern entfernt
worden und in die Standardbibliothek gewandert.
Und das ist ein sehr gutes Zeichen für stimmiges Sprachdesign:
offensichtlich kann man bei Rust derart grundlegende Funktionalität und
Semantik in Bibliotheken auslagern.
Alte Lisper kennen das natürlcih schon, aber für etwas mainstreamigere
Sprachen ist das schon etwas ganz besonderes.
Fritz schrieb:> Alte Lisper kennen das natürlcih schon, aber für etwas mainstreamigere> Sprachen ist das schon etwas ganz besonderes.
In C++ wird das seit Jahr und Tag ebenfalls als Library gemacht, dank
Templates ("smart pointer"). Seit 3 Jahren ist der refcounting-basierte
auch im Standard:
http://de.cppreference.com/w/cpp/memory/shared_ptr
Stefan Salewski schrieb:> Ein wesentlicher Aspekt ist, dass Rust von einem größeren Team> entwickelt wird, einige davon wohl bezahlte Ganztagsprogrammierer. Bei> Nimrod ist es wohl ein Hauptentwickler mit einigen Unterstützern -- wohl> eher unbezahlt, aber sehr helle Köpfe. Und bei Nimrod steckt wohl eher> ein Plan hinter der Entwicklung, bei Rust geht es noch etwas chaotisch> zu.
Ja am Anfang war es etwas chaotisch, das hat sich aber gebessert. Die
Entwickler wissen was sie wollen, waren sich am Anfang aber unsicher wie
die Inhalte im Detail aussehen sollen. Das sieht man gut an den GC und
RefCount Zeiger die zuerst in der Syntax etabliert waren und dann in die
Standardbibliothek gewandert sind (richtige Entscheidung!). Mir gefällt
vor allem die communitynahe Entwicklung. Jeder kann sich auf Github
beteiligen und Vorschläge machen. Die Entwicklungszeit ist zwar länger,
aber die Qualität der Sprache ist (theoretisch) besser, wenn es externe
Leute gibt, die einen Blick auf das Sprachdesign werfen.
Stefan Salewski schrieb:> Nimrod generiert ja> gewöhnlich C Zwischencode, so dass man Nimrod grundsätzlich auch für> 8-Bit Mikroprozessoren einsetzen könnte -- jedenfall wurde irgendwo auch> ein AVR erwähnt, Das Problem sind wohl eher die angepassten> Bibliotheken, war früher für GCC ja auch das Problem. (Ich persöhnlich> denke allerdings, dass C für 8-bit gut genug ist.).
Nur weil Nimrod C Code erzeugt bedeutet das nicht, dass Nimrod auf einem
8-Bit µC sinnvoll oder möglich ist. C wird auf einem µC benutzt weil C
nichts verschleiert und extrem performant ist. In einem Lowlevel Feld wo
sich selbst C++ nicht durchsetzen kann, wird es für Nimrod noch
schwieriger haben. Und dann noch der aufgezwungene GC. Für 8-Bit µC ein
absolutes NoGo.
Zum Glück ist der GC Hype am Abflachen und jeder müsste nun wissen, dass
ein GC keine Allheilslösung ist, also warum einen GC erzwingen? Schon
deshalb ist Rust für mich der absolute Favorit über Nimrod und Go. Wobei
Go natürlich eher für Serveranwendungen konzipiert ist.
Stefan Salewski schrieb:> Übrigens was mich sehr an Rust stört, sind die von C übernommenen> geschweiften Klammern. Irgendwie habe ich da den Eindruck, dass man> unbedingt ein vertrautes Erscheinungsbild haben wollte, damit sich C und> Java Programmierer gleich zuhause fühlen.
Das kommt wohl daher, dass die Rust Entwickler (Mozilla) sonst
hauptsächlich mit C++ arbeiten. Aber ehrlich gesagt gefallen mir die
Klammern lieber als irgendwelche Schlüsselwörter wie "end". Zugegeben
auf der deutschen Tastatur nicht optimal, aber das macht den Code
luftiger, die Klammern fallen beim Lesen kaum auf damit bleibt der Fokus
auf den wichtigen Teilen des Quellcodes. Basic finde ich deshalb so
häßlich, der Code besteht dann immer aus riesigen zusammenhängenden
Blöcken.
TriHexagon schrieb:> Nur weil Nimrod C Code erzeugt bedeutet das nicht, dass Nimrod auf einem> 8-Bit µC sinnvoll oder möglich ist. C wird auf einem µC benutzt weil C> nichts verschleiert und extrem performant ist. In einem Lowlevel Feld wo> sich selbst C++ nicht durchsetzen kann, wird es für Nimrod noch> schwieriger haben. Und dann noch der aufgezwungene GC. Für 8-Bit µC ein> absolutes NoGo.>> Zum Glück ist der GC Hype am Abflachen und jeder müsste nun wissen, dass> ein GC keine Allheilslösung ist, also warum einen GC erzwingen?
Ich bin mir eigentlich ziemlich sicher, dass Nimrod keinesfalls einen
Garbage-Collector "erzwingt". Das wäre in der Tat schlecht. Der Nimrod
GC arbeitet mit Pointern die mit dem Schlüselwort ref gekennzeichgnet
sind, Pointer gekennzeichnet mit ptr werden manuell verwaltet. Wenn also
das Schlüsselwort ref nirgends auftaucht, bekommt man ein Programm ohne
GC. Klar darf man dann keine Bibliotheken verwenden, die den GC
benötigen. Nimrod hat den GC zwar in der Sprache integriert, aber bieted
durchaus verschiedene GC Varianten. Ob es jetzt besser ist, den GC nicht
in die Sprache zu integrieren, sondern nur als Bibliothek anzubieten?
Glaube ich eher nicht. Bei Rust war der GC ja anfangs sehr unbeliebt, da
er für systemnahe Programmierung eh nicht verwendet wird, und
insbesondere da Garbage-Collection den Rechner für einige Zeit zum
Stehen bringen kann. Das ist für viele Anwendungen ein großen Problem,
etwa für Systemprogrammierung oder auch Spiele. Bei Nimrods GC sollen
diese erzwungenen Pausen aber sehr klein sein, ms oder so.
Und zu den geschweiften Klammern: Dass man } lieber mag als das
Schlüsselwort end kann ich verstehen, in Ruby verwende ich auch oft das
Paar {} statt etwa do end. Aber für jeden Block nach if, else, while
usw. ein {} Paar wie in C und Java üblich? Da gefällt mir etwa Ruby's
Syntax doch besser. Mit den erzwungenen Einrückungen vom Python hatte
ich anfangs auch meine Probleme, da ich manchmal einfach drauf lostippe
ohne mich um Formatierung zu kümmern. Aber damit kommen die Leute wohl
doch gut zurecht, sonst wäre Python ja nicht so populär geworden. Und
die Strukturierung durch Einrückungen in Python, Haskell und Nimrod
ergibt eben kompakten, gut lesbaren Code und wird daher in Lehrbüchern
und Pseudo-Code ja auch oft verwendet.
TriHexagon schrieb:> Nur weil Nimrod C Code erzeugt bedeutet das nicht, dass Nimrod auf einem> 8-Bit µC sinnvoll oder möglich ist. C wird auf einem µC benutzt weil C> nichts verschleiert und extrem performant ist. In einem Lowlevel Feld wo> sich selbst C++ nicht durchsetzen kann, wird es für Nimrod noch> schwieriger haben. Und dann noch der aufgezwungene GC. Für 8-Bit µC ein> absolutes NoGo.
Von aufgezwungen lese ich auf der Nimrod-Seite nichts...
"System programming features: Ability to manage your own memory and
access the hardware directly. Pointers to garbage collected memory are
distinguished from pointers to manually managed memory."
Kenne die Sprache aber zu wenig, um da genaueres sagen zu können.
DingsDa schrieb:> Habe in meinem Umfeld noch kein OS gesehen, das mit einer anderen> Sprache als C/Assembler geschrieben war/ist.> Wenn hierzu jemand eine Info hätte, würde mich das sehr interessieren.
Es gibt einige Betriebssysteme die nicht C als Hauptsprache verwenden
u.a.:
Oberon: Bluebottle, AOS, Native Oberon
Java: JX
Lisp: Interlisp, Symbolics Genera
BitC: Coyotos (sollte das erste formal verifizierte OS werden, was aber
seL4 wurde)
Sing# (C#-Ableger): Singularity
C#, TAL, Boogie/Z3: Verve
Zu den beiden letztgenannten: http://singularity.codeplex.com/http://research.microsoft.com/apps/pubs/?id=122884http://research.microsoft.com/en-us/projects/singularity/Yalu X. schrieb:> Wesentlich besser würde mir Rust aber gefallen, wenn es wie in Nimrod> einen interaktiven Interpreter, benutzerdefinierte Operatoren und> Generatoren gäbe.
REPL (rusti) wird es (wieder) geben, zwischenzeitlich kann man
https://github.com/tarcieri/irust ausprobieren.
TriHexagon schrieb:> Nur weil Nimrod C Code erzeugt bedeutet das nicht, dass Nimrod auf einem> 8-Bit µC sinnvoll oder möglich ist.
Ich habe gerade Google noch mal nachlesen lassen...
http://nimrod-lang.org/nimrodc.html#nimrod-for-embedded-systems
Da wird vom 16 bit uC ohne OS geschrieben und AVR erwähnt -- wobei GCC
die AVR's ja als 16 bittig betrachtet, weil eben der Adressbereich
größer als 8 Bit sein kann. Gut, ich selbst würde für die AVR's C
nehmen, ich kann mir nicht vorstellen, dass man da mit Rust oder Nimrod
viel gewinnt. Eher schon für einen kleinen ARM...
Es freut mich, dass da schon eine rege Diskussion im Gange ist, wie ich
sie fast nicht erwartet hätte :)
VielenDank schon jetzt an alle Teilnehmer.
Ich fange hier mal an, ein paar Dinge zu kommentieren:
Fritz schrieb:> Rust ist auch deshalb cool, weil die Entwickler schwer darauf acht> geben, daß es (für kleine eingebettete Systeme) auch ohne> Standardbibliothek sinnvoll nutzbar ist.
So wirklich klein sind die Executables aber auch nicht: Ein leeres main
ist bei mir schon 812024 Bytes lang (gestrippt). Dazu kommen noch
folgend Shared Objects, die allerdings auf einem normale Linux-System
sowieso ständig geladen sind und damit nicht ins Gewicht fallen:
1
linux-vdso.so.1
2
libdl.so.2
3
libpthread.so.0
4
libgcc_s.so.1
5
libc.so.6
6
ld-linux-x86-64.so.2
7
libm.so.6
Stefan Salewski schrieb:> Garbage-Collector mag man nicht so recht, daher gibt es diese> "sicheren" (owned) Pointer -- habe ich noch nicht so richtig> verstanden, ich hatte dazu auch manchmal widersprüchliches gelesen.
Owned Objects sind Objekte, die manuell alloziert (mit dem box-Operator)
und automatisch, wenn ihr Scope verallsen wird, wieder freigegeben
werden. Bis dahin hat das Ähnlichkeit mit RAII. Zusätzlich können aber
solche Objekte in einen anderen Scope gemovet werden. Das geschieht
durch eine Zuweisung, Argumentübergabe oder Funktionswertrückgabe.
Wichtig dabei ist, dass immer nur ein einziger Pointer auf das Objekt
zeigt, weil man dann ohne Reference-Counting o.ä. auskommt. Wird also
ein Pointer einer anderen Variablen zugewiesn, wird dir ursprünglich
Pointervariable ungültig, und jeder weitere Zugriff darauf ist ein
Fehler, der bereits beim Kompilieren aufgedeckt wird.
Ein typisches Anwendungsfeld für solche Pointer sind Funktionen, die
dynamisch erzeugte Daten an den Aufrufer zurückgeben. In solchen Fällen
ist der Aufrufer für die Freigabe des belegten Speichers verantwortlich.
In Rust geschieht das automatisch. Beispiel:
1
fnerzeuge_daten()->Box<int>{
2
letp=box123;
3
p
4
}
5
6
fnaufrufer(){
7
letp=erzeuge_daten();
8
println!("{}",*p);
9
}
Hier wird der in erzeuge_daten reservierte Speicher am Ende von
aufrufer automatisch zurückgegeben. Der Rechenaufwand ist der eines
malloc/free-Kombination und damit geringer als bei Smart-Pointern, die
man in C++ für solche Dinge benutzen würde.
Stefan Salewski schrieb:> Nimrod hat einen Garbage-Collector, der weitgehend echtzeitfähig sein> soll, und zusätzlich einfache Pointer die manuell verwaltet werden.
Es gibt in Nimrod auch allocate() und deallocate() für die manuelle
Speicherverwaltung. Die wird man aber nicht gerne nutzen, weil man damit
die in C gefürchteten Speicherlecks heraufbeschwört. Wenn man also
dynamisch Objekte anlegen will, gibt es nur unsicher oder GC, aber
nichts dazwischen. In Rust gibt es eben zusätzlich noch die
Owned-Objekte und Reference-Counting als effizienetere Alternativen.
Wobei die GCs mittlerweile so gut sind, dass sie ein Programm im Mittel
kaum verlangsamen. Schlimm ist nur, wenn der GC zu einem ungünstigen
Zeitpunkt zuschlägt und dann gleich den kompletten Speicher auf einmal
aufräumt, was entsprechend dauern kann. In Nimrod kann deswegen die GC
lokal beschränkt werden, so dass sie immer nur kleinere Häppchen am
Stück bearbeiten muss.
Fritz schrieb:> Und das ist ein sehr gutes Zeichen für stimmiges Sprachdesign:> offensichtlich kann man bei Rust derart grundlegende Funktionalität und> Semantik in Bibliotheken auslagern.
Dazu gibt es in der mitgelieferten Regex-Bibliothek auch ein schönes
Beispiel:
1
#![feature(phase)]
2
#[phase(plugin)]
3
externcrateregex_macros;
4
externcrateregex;
5
6
fnmain(){
7
letre=regex!(r"^\d{4}-\d{2}-\d{2}$");
8
assert_eq!(re.is_match("2014-01-01"),true);
9
}
Die Zeile "let re = ..." kompiliert den als String übergebenen regulären
Ausdruck. Das passiert aber nicht wie in anderen Sprachen zur Laufzeit,
sondern zu Compile-Zeit. Entsprechend werden auch Syntaxfehler bereits
beim Kompilieren angezeigt. Lässt man bspw. die letzte geschweifte
Klammer weg, meckert der Compiler:
1
regex.rs:7:14: 7:44 error: Regex syntax error near position 15: No closing brace for counted repetition starting at position 15.
2
regex.rs:7 let re = regex!(r"^\d{4}-\d{2}-\d{2$");
3
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4
error: aborting due to previous error
Nicht nur, dass eine Fehlermeldung angezeigt wird, sie ist sogar sofort
verständlich. Man denkt hier, die Regexe seien fester Sprachbestandteil
von Rust. Tatsächlich sind sie aber ein geniales (fast an Lisp
erinnerndes) Beispiel von Metaprogrammierung, die man auch selber nutzen
kann. In C++ ist etwas Ähnliches nur möglich, wenn man die Regex-Syntax
so abändert, dass sie nicht als String, sondern als Ausdruck mit
Operatoren zwischen den einzelnen Primitiven dargestellt werden kann (s.
Boost:Xpressive), da ein String zur Compile-Zeit nur schwerlich
analysiert werden kann.
Das ist übrigens etwas, wo es mich beim Lesen und anschließendem
Ausprobieren dann doch etwas aus den Socken gehauen hat ;-)
In Nimrod sollten solche Dinge aber ebenfalls problemlos gehen.
Arc Net schrieb:> REPL (rusti) wird es (wieder) geben, zwischenzeitlich kann man> https://github.com/tarcieri/irust ausprobieren.
Klasse, werde ich bei nächster Gelegenheit ausprobieren :)
Yalu X. schrieb:> So wirklich klein sind die Executables aber auch nicht: Ein leeres main> ist bei mir schon 812024 Bytes lang (gestrippt).
Wenn dem so ist, wird sich das hoffentlich noch stark verbessern --
womöglich ist aber viel Debugging-Code enthalten?
Ich hatte zuletzt den Convex-Hull Algorithmus von Wikibooks mit Nimrod
probiert, executable size mit Linux AMD64 sind 75946 Bytes. Kompiliert
mit "nimrod c -d:release convex_hull.nim" (mit gcc version 4.8.3 und gcc
Option O3). Soweit ich mich errinnere schaltet -d:release Debugging und
Dinge wie Stack-Check ab -- es gibt aber noch eine Option für noch
kleinere Executables, die finde ich aber gerade nicht. Ist wohl dann gcc
mit -Os.
stefan@AMD64X2 ~ $ ldd convex_hull
linux-vdso.so.1 (0x00007fff3c3ff000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f25acb2b000)
libc.so.6 => /lib64/libc.so.6 (0x00007f25ac784000)
/lib64/ld-linux-x86-64.so.2 (0x00007f25acd2f000)
Der Code ist hier -- für Rust leider noch nicht.
http://en.wikibooks.org/wiki/Algorithm_Implementation/Geometry/Convex_hull/Monotone_chainhttp://forum.nimrod-lang.org/t/483
Demnächst werde ich es mal mit zwei Threads probieren, jeweils für die
untere und obere Hülle.
Erst einmal gab es vom Nimrod-Compiler Gemecker, weil in einem
mitgelieferten System-File (system.nim) irgendwelche Array-Typen
deklariert werden, deren Elementzahl gößer als 65535 ist. Hab's
hingefrickelt, indem ich die Werte durch kleinere ersetzt habe und dann
mit folgendem Kommando das Programm kompiliert:
1
nimrod c --cpu:avr --os:standalone --deadCodeElim:on --genScript -x:off --opt:size avrtest.nim
Mit -x:off werden sämtlich Laufzeitüberprüfungen abgeschaltet, was den
erzeugten Code deutlich kompakter macht.
Das Ganze brach vor der Generierung des Binärcodes mit Fehlermeldungen
ab, weil die generierten C-Dateien vom C-Compiler nicht gefunden wurden.
Zudem wurde der falsche Compiler gestartet (gcc statt avr-gcc). Ich
schätze, das man das alles durch weitere Optionen oder irgenwelche
Konfigurationsdateien in den Griff bekommen kann.
Immerhin wurden aber zwei C-Files generiert, die ich dann manuell vom
AVR-GCC 4.7.2 übersetzen ließ.
Hui, und das Ergebnis kann sich sehen lassen:
1
$ avr-size avrtest
2
text data bss dec hex filename
3
126 0 15 141 8d avrtest
Das Disassembly habe ich angehängt.
Damit ist Nimrod entgegen meiner ursprünglichen Vermutung sogar ein
Kandidat für die AVR-Programmierung. Allerdings müsste sich noch jemand
hinsetzen und Makros für die Zugriffe auf die I/O-Register schreiben.
Oder gibt es so etwas vielleicht sogar schon?
Stefan Salewski schrieb:> Gut, ich selbst würde für die AVR's C nehmen, ich kann mir nicht> vorstellen, dass man da mit Rust oder Nimrod viel gewinnt.
Ja, so sehe ich das auch. Die Programme, die man typischerweise für
einen AVR schreibt, sind so klein, dass man sich um höherlevelige
Programmierung nicht viele Gedanken machen muss. Trotzdem finde ich es
toll, mit wie wenig Ressourcen Nimrod auskommt. Damit wird es auf jeden
Fall interessant für komplexere Mikrocontrollerprogramme, die dann bspw.
auf kleinen bis mittelgroßen ARMs laufen.
Yalu X. schrieb:> Der Rechenaufwand ist der eines> malloc/free-Kombination und damit geringer als bei Smart-Pointern, die> man in C++ für solche Dinge benutzen würde
Nicht seit C++11, unique_ptr und move semantics. Bei Verwendung davon
passiert exakt das selbe...
Yalu X. schrieb:> Immerhin wurden aber zwei C-Files generiert, die ich dann manuell vom> AVR-GCC 4.7.2 übersetzen ließ.>> Hui, und das Ergebnis kann sich sehen lassen:> $ avr-size avrtest> text data bss dec hex filename> 126 0 15 141 8d avrtest>> Das Disassembly habe ich angehängt.>> Damit ist Nimrod entgegen meiner ursprünglichen Vermutung sogar ein> Kandidat für die AVR-Programmierung.
Das ist wirklich interessant!
Schön dass Du Dir die Mühe gemacht hast das mal auszuprobieren.
> Allerdings müsste sich noch jemand> hinsetzen und Makros für die Zugriffe auf die I/O-Register schreiben.> Oder gibt es so etwas vielleicht sogar schon?
Denke ich nicht. Aber vielleicht wäre das gar nicht so extrem aufwändig,
zu Nimrod gibt es das Tool c2nim das C-Header und zum Teil auch C-Code
nach Nimrod wandeln kann. Na ja, das wäre dann eine Alternative für die
Leute, die eine starke Abneigung gegen C haben und für die AVR's BASIC
oder ähnliches benutzen...
Nicht dass ich das jetzt für wirklich sinnvoll halte, ich würde für AVR
bei C bleiben, wahrscheinlich würde ich heute gar nicht mehr mit AVR
anfangen sondern gleich mit ARM beginnen. Aber dass es mit Nimrod
grundsätzlich möglich wäre gefällt mir schon.
Mhm das weckt nun doch mein Interesse, werde ich mal ausprobieren. Wäre
mal interessant wie sich das anfühlt. Ich hab mir vor ein paar Monaten
einen kleinen Überblick über Nimrod beschaft. Solange ich den Heap nicht
benutze, wird der GC also nicht einmal angerührt?
Dr. Sommer schrieb:> Yalu X. schrieb:>> Der Rechenaufwand ist der eines>> malloc/free-Kombination und damit geringer als bei Smart-Pointern, die>> man in C++ für solche Dinge benutzen würde> Nicht seit C++11, unique_ptr und move semantics. Bei Verwendung davon> passiert exakt das selbe...
Ja, stimmt, die unique_ptr gibt es ja auch noch. Die haben tatsächlich
die gleiche Funktion wie die Owned Boxes in Rust, unterscheiden sich von
diesen aber in zwei Punkten, von denen der erste von entscheidender
Bedeutung ist:
1. Die Dereferenzierung eines leeren unique_ptr in C++ führt zu
undefiniertem Verhalten (üblicherweise ein Segfault), während der
entsprechende Fehler in Rust bereits beim Kompilieren erkannt wird.
Damit sind die Owned Boxes im Gegensatz zu den unique_ptr absolut
idiotensicher.
2. Die unique_ptr sind geringfügig ineffizienter, weil beim Move der
alte Pointer explizit auf null gesetzt werden muss und beim Verlassen
des Scopes der Pointer auf null geprüft werden muss, um zu
entscheiden, ob ein Objekt gelöscht muss kann oder nicht. Da in Rust
diese Entscheidung bereits zur Compile-Zeit erfolgt, ist die
Verwendung von Owned Boxes genauso effizient wie die manuelle
Speicherverwaltung mit new und delete.
>Und>die Strukturierung durch Einrückungen in Python, Haskell und Nimrod>ergibt eben kompakten, gut lesbaren Code
Ab ein paar Ebenen sieht man überhaupt nichts mehr!
Ausserdem, eine Stufe zuweit eingerückt (was schnell passieren kann),
und alles ist Mist.
Bei mit end.. oder } (oder ähnlichem) lässt sich eindeutig
nachvollziehen, wo's hingehört. Alles andere ist für grössere Progr.
völlig unbrauchbar!
Das Blocken durch Einrücken halte ich auch für keine gute Idee. Bei
Python als Anfängersprache ist das vielleicht sinnvoll, aber wenn es
größere Programme werden, kann man das nicht mehr gebrauchen. Nicht
umsonst gibt es in guten IDE die Möglichkeit zur automatischen
Einrückung. Man benötigt eine neue Ebene oder hat eine Ebene zu viel und
schon darf man ewig viel Code neu einrücken.
Stützräder sind für Fahranfänger sicher eine gute Idee, aber trotzdem
habe ich noch keinen Rennradfahrer mit Stützrädern gesehen…
Yalu X. schrieb:> Außerdem habe ich eine wachsende Abneigung gegen> geschweifte Klammern, die nicht nur hässlich aussehen, sondern auch auf> deutschen Tastaturen schwer zu tippen sind.
Wenn du mit Windows arbeitest: Mit MSKLC (Microsoft Keyboard Layout
Creator) kannst du supereinfach dein Tastaturlayout anpassen. Da fällt
ein kleiner Installer für x86/amd64/ia64 raus, den du auf deinen
Rechnern installierst und dann als Standardtastatur setzt.
Ich hab mir die wichtigsten Zeichen auf AltGr = rechter Daumen plus
linke Hand gelegt, also:
qwert = @\/^`
asdf = {[]}
Seitdem mach ich sehr gerne ein paar Schweife oder Array Indexe. Für
Linux gibt es sowas bestimmt auch. Auf dem Mac, gut, da gibt es ein
Problem, weil der leider kein AltGr hat.
MCUA schrieb:> Ab ein paar Ebenen sieht man überhaupt nichts mehr!
Das ist doch stets das Problem, sofern man nicht einen Editor verwendet,
der die Ebenen irgendwie besonders kenntlich macht. Was nützt einem ein
{}-Paar, wenn nur eine der Klammern sichtbar ist? Man braucht also
Editor-Support, im einfasten Fall das Hin- und Herspringen zwischen den
Klammern.
Und generell gilt es ja eher als schlechter Stil, wenn man extrem lange
Funktionen mit unzähligen Einrückungsebenen hat.
Bei Ruby hat man ja das Schlüsselwort end -- der Stil gefällt mir
eigentlich am besten, nur verbraucht man durch jedes end eine Zeile.
Bei Python, Haskell, Nimrod ist wohl das größte (und einzige) Problem
das Umkopieren von Programmtext, aber auch dafür ist Editorunterstützung
möglich.
Und natürlich ist es recht einfach möglich, alternativ zu der
Einrückungssyntax etwa geschweifte Klammern anzubieten -- {} ist für den
Parser ja trivial.
>Das ist doch stets das Problem, sofern man nicht einen Editor verwendet,>der die Ebenen irgendwie besonders kenntlich macht.
Problem nur, wenn eine Ebene (auch wenns nur 2 sind) mit space endet.
Man sieht nichts! Diese Syntax ist beschi??en. Es macht einfach keinen
Sinn, Blöcke/Ebenen bloss mit Einrücktiefe zu kennzeichen, ohne dass man
es dem Text selbst ansieht. (Und wehe, es wurde versehentlich mal falsch
eingerückt (was schnell passieren kann). Da sucht man ewig. Wogegen im
anderen Fall dadurch überhaupt kein Fehler entstehen kann, und man es
ggfs sogar autom einrücken lassen kann).
Soweit ich weiß gab es für Python mal die Option, nach einer
Einrückungsebene ein endif einzufügen, also ähnlich wie bei Ruby. Wollte
wohl aber keiner verwenden. Und natürlich kann man einfach
End-Kommentare verwenden, etwa "# end". Oder "# {" und "# }"
Aber das Thema hat sich durch die Popularität vom Python wohl eh
erledigt, die meisten Leute kommen mit den Einrückungen scheinbar gut
klar. Ich selbst muss mich noch etwas daran gewöhnen.
Micha Lu schrieb:> Ich hab mir die wichtigsten Zeichen auf AltGr = rechter Daumen plus> linke Hand gelegt, also:>> qwert = @\/^`> asdf = {[]}
So etwas ist sicher ganz praktisch. Ich habe dabei nur die Befürchtung,
dass, wenn ich auf einem fremden Rechner arbeite, ständig irgendwelche
fremdartigen Zeichen auf dem Bildschirm erscheinen ;-)
DingsDa schrieb:> Habe in meinem Umfeld noch kein OS gesehen, das mit einer anderen> Sprache als C/Assembler geschrieben war/ist.> Wenn hierzu jemand eine Info hätte, würde mich das sehr interessieren.
AmigaOS ist teilweise in C und teilweise in BCPL geschrieben worden.
Diese Mischung ist auch für Anwendungsentwickler relevant, da man bei
jedem API schauen muss, in welcher Sprache es entwickelt wurde. Will man
also eine in BCPL implementierte Funktion aufrufen, sollte man tunlichst
keine nullterminierten Strings übergeben, sondern solche mit Längenfeld.
Zeiger sind um zwei Bit nach rechts verschoben, da BCPL mit
Langwortadressierung statt Byteadressierung arbeitet.
NeXTSTEP, Apple OS X und iOS sind größtenteils in Objective-C
entwickelt.
Yalu X. schrieb:> Damit sind die Owned Boxes im Gegensatz zu den unique_ptr absolut> idiotensicher.
Aber unflexibler, denn man kann sie wohl nicht aus Member-Variablen
herausmoven ohne die Instanz zu zerstören.
> 2. Die unique_ptr sind geringfügig ineffizienter, weil beim Move der> alte Pointer explizit auf null gesetzt werden muss...
Dafür kann man in C++ einen moved-from unique_ptr auch wieder zuweisen;
Allerdings sollten halbwegs schlaue Compiler in den meisten Fällen
erkennen dass die Extra-Operationen sinnlos sind und weggelassen werden
können.
Hello World ;) schrieb:> Lisp ist alles andere als ein Exot. Lisp hat seine> Tauglichkeit längst bei AutoCAD unter Beweis gestellt.
Und natürlich bei EMACS!
Früher gab es auch spezielle auf die Ausführung von LISP optimierte
Mikroprozessoren (Texas Instruments Explorer) bzw. Computer (Symbolics
36xx), und zwar zu Zeiten des großen KI-Hypes.
Sun verfolgte in der Anfangszeit von Java einen ähnlichen Ansatz mit dem
picoJava-Mikroprozessor, der direkt Java-Bytecode ausführte. Ich kann
mich noch dunkel an eine "Embedded Systems" (heute: "Embedded World")
erinnern, auf der Sun einige verschlossene Glasvitrinen mit picoJavas
und zugehörige Entwicklungsboards präsentierte. Angeblich sollten die
Prozessoren kurz vor der Auslieferung gestanden haben, aber dafür gab es
noch erstaunlich spärliche Informationen...
MCUA schrieb:>>Aber das Thema hat sich durch die Popularität vom Python...> Popularität? Im uC-Bereich eigentl. unbekannt.
Im uC-Bereich eigentlich extrem verbreitet, jedoch weniger zur
Ausführung auf dem Microcontroller, sondern für Tools und Testskripte.
>Sun verfolgte in der Anfangszeit von Java einen ähnlichen Ansatz mit dem>picoJava-Mikroprozessor, der direkt Java-Bytecode ausführte.
..den keiner haben wollte.
Das pardoxe bei Java ist, dass es keiner dafür benutzt, wofür es urspr.
gedacht war.
>Im uC-Bereich eigentlich extrem verbreitet, jedoch weniger zur>Ausführung auf dem Microcontroller,
das widerspricht sich
MCUA schrieb:>>Im uC-Bereich eigentlich extrem verbreitet, jedoch weniger zur>>Ausführung auf dem Microcontroller,> das widerspricht sich
Zitiere gefälligst vollständig.
Lötkolben sind im uC-Bereich auch extrem verbreitet, auch wenn sie nur
sehr kurzzeitig mit einem uC in Kontakt kommen.
Dr. Sommer schrieb:> Yalu X. schrieb:>> Damit sind die Owned Boxes im Gegensatz zu den unique_ptr absolut>> idiotensicher.> Aber unflexibler, denn man kann sie wohl nicht aus Member-Variablen> herausmoven ohne die Instanz zu zerstören.
Nur die gemovete Member-Variable wird ungültig, auf den Rest der
Struktur kannst du nach wie vor zugreifen.
>> 2. Die unique_ptr sind geringfügig ineffizienter, weil beim Move der>> alte Pointer explizit auf null gesetzt werden muss...> Dafür kann man in C++ einen moved-from unique_ptr auch wieder zuweisen;
Das geht in Rust auch, sofern die Pointer-Variable mutual ist.
Edit: Es muss natürlich "mutable" und nicht "mutual" heißen (immer diese
neumodischen Ausdrücke, hätte vielleicht, wenn ich schon keine Ahnung
habe, einfach "veränderlich" schreiben sollen ;-))
Yalu X. (yalu) (Moderator) schrieb:
> Das geht in Rust auch, sofern die Pointer-Variable mutual ist.
Apropos "gemovete Member-Variable" und co. Täuscht mich der Eindruck,
dass auch Rust, go, Nimrod ähnlich wie D vielleicht wunderbare,
interessante "Kommandozeilendialekte" sind, aber man spätestens in
Sachen GUI-Anbindung auf eine Mauer trifft?
Zum Vergleich mal ein Blick auf D in Sachen GUI
http://qznc.github.io/d-tut/gui.html
Also für Windows Programme stelle ich mir Werbung dann doch ein wenig
anders vor, als diese drei kläglichen Verweise. Das reicht nicht mal zum
anmotivieren.
Jetzt könnte man Rust und Nimrod noch zugute halten, diese Sprachen sind
ja noch recht neu (wird also vielleicht noch werden). Aber D ist jetzt
wie viele Jahre auf dem Radar? Laut Bugliste minimum 7 Jahre seit v2.0,
eher 10 Jahre (also lange genug für umfangreiche Frameworkbeispiele, die
es jedochbis heute kaum oder gar nicht gibt).
Eine "Hobbyprogrammiersprache" wird's mit den Neuen wenn überhaupt wohl
eher nur für Nicht-Windows-GUI-Programme bzw. für Dialog orientierte
GUI-Programme und Progrämmchen wird der geneigte Hobbyist nach einem
kurzen Kontakt mehr auf Frust wohl schnell lieber auf sein gewohntes
Lazarus (samt IDE), sein C# (samt Visual) oder sein QT-Framework mit
zahlreichen Beispielen zurückgreifen. Denn dort wird ihm geholfen.
Die Überschrift hätte folglich vielleicht eher lauten sollen
"Rust oder Nimrod als neue Spezialistenprogrammiersprache?"
Yalu X. schrieb:>> qwert = @\/^`>> asdf = {[]}>> So etwas ist sicher ganz praktisch. Ich habe dabei nur die Befürchtung,> dass, wenn ich auf einem fremden Rechner arbeite, ständig irgendwelche> fremdartigen Zeichen auf dem Bildschirm erscheinen ;-)
Nicht ständig, nur einmal, dann schalten Gehirn und Finger in den alten
Modus um. Ich hatte die gleiche Befürchtung wie du. Ist aber kein
Problem, ich war selber erstaunt, wie leicht es geht, macht alles das
Kleinhirn für dich. :)
Yalu X. schrieb:> Nur die gemovete Member-Variable wird ungültig, auf den Rest der> Struktur kannst du nach wie vor zugreifen.>>>> 2. Die unique_ptr sind geringfügig ineffizienter, weil beim Move der>>> alte Pointer explizit auf null gesetzt werden muss...>> Dafür kann man in C++ einen moved-from unique_ptr auch wieder zuweisen;>> Das geht in Rust auch, sofern die Pointer-Variable mutual ist.
Das würde aber bedeuten dass sie zwischen move-from und zuweisung "null"
ist, man beim Zugriff einen Fehler erhält, und die Pointer-Variable
immer auf != 0 geprüft wird. Also exakt genauso wie std::unique_ptr ?!?!
Hello World ;) schrieb:> Täuscht mich der Eindruck,> dass auch Rust, go, Nimrod ähnlich wie D vielleicht wunderbare,> interessante "Kommandozeilendialekte" sind, aber man spätestens in> Sachen GUI-Anbindung auf eine Mauer trifft?
GTK2 und GTK3 (ungetestet) gibt es für Nimrod, für Rust gibt es auch ein
GTK, das mir aber etwas verwaist erschien.
Bei GO und Haskell hat es ja auch gedauert, bis es GTK Bindings gab. Und
QT Bindings zu machen ist schon schwieriger und mehr Arbeit.
Wann es native GUI Unterstützung für Windows und Apple geben wird weiß
ich nicht, aber wahrscheinlich arbeiten Bill und Steve schon daran...
Aber Du hast schon recht, GUI ist wohl nicht der Schwerpunkt der
Entwickler. Bei Nimrod ist sicher einer der Schwerpunkte
Server_Anwendungen, da wo noch vorwiegend Python und ähnliches
eingesetzt wird. Da gibt es großes finanzielles Einsparpotential
Und bei Apple werden sich jetzt eh alle auf Swift stürzen (müssen). Und
für Windows kann man sicher mit C# leben. Zu Android weiß ich nichts...
Und zur Überschrift: Beides sind sicher keine Hobbysprachen -- ich wüßte
jetzt auch keine richtige Hobbysprache, na ja vielleicht dieses AVR
Basic? Einsetzen kann man beide sicherlich im Hobbybereich, aber da muss
die Dokumentation noch etwas besser werden.
Dr. Sommer schrieb:> Das würde aber bedeuten dass sie zwischen move-from und zuweisung "null"> ist, man beim Zugriff einen Fehler erhält, und die Pointer-Variable> immer auf != 0 geprüft wird. Also exakt genauso wie std::unique_ptr ?!?!
Man erhält die Fehlermeldung nicht erst beim realen Zugriff (also zur
Laufzeit), sondern bereits beim Kompilieren. Deswegen muss der Pointer
zur Laufzeit weder genullt noch abgeprüft werden, da die Situation, wo
dies von Nutzen wäre, bei einem erfolgreich kompilierten Programm gar
nie einteten kann.
Hier ist ein kleines Beispiel:
1
fnmain(){
2
letmutp1=box123i;// zunächst ist p1 Owner
3
println!("{}",p1);// OK
4
5
letp2=p1;// dann übernimmt p2 die Ownerschaft
6
println!("{}",p1);// Compiler meckert: "use of moved value: `p1`"
7
8
p1=p2;// p1 wird erneut Owner
9
println!("{}",p1);// OK
10
}
Das Programm kompiliert nur dann, wenn man die zweite (fehlerhafte)
println-Anweisung weglässt. Das dritte println ist in Ordnung, obwohl p1
temporär die Ownerschaft an p2 abgegeben hat.
Yalu X. schrieb:>> Ich habe das mal anhand eines ganz einfachen Beispiels versucht:>>
1
> # avrtest.nim
2
> proc arithReihe(n: int8): int8 =
3
> for i in countup(1, n):
4
> result += i
5
>
6
> var a = arithReihe(10)
7
>
>> [...]>
1
nimrod c --cpu:avr --os:standalone --deadCodeElim:on --genScript -x:off --opt:size avrtest.nim
>> [...]>> Immerhin wurden aber zwei C-Files generiert, die ich dann manuell vom> AVR-GCC 4.7.2 übersetzen ließ.
Wobei sich bei einem Transpiler generell die Frage stellt, wie flauschig
sich das debuggt. Der Debugger sieht ja nicht mehr als generierten
Code...
Bei dem einfachen Beispiel geht das noch, aber bei richtigen Programmen?
Johann L. schrieb:> Wobei sich bei einem Transpiler generell die Frage stellt, wie flauschig> sich das debuggt. Der Debugger sieht ja nicht mehr als generierten> Code...
Dich gibt es hier also doch noch -- hatte lange nichts mehr von dir
gelesen!
Das mit dem Debuggen ist ein guter Einwand. Für den PC hat Nimrod wohl
einen einfachen (langsamen) Debugger. Ich selbst habe (fast) nie einen
Debugger verwenden mögen -- für einfache Dinge brauche ich ihn nicht,
für komplizierten Code mit verschachtelten Datenstrukturen und Rekursion
kann ich mir nicht vorstellen, dass ein Debugger mir viel hilft. Und in
einer guten Sprache treten ja auch lange nicht so viele Fehler auf. Aber
für Hobby-Kids mag so Zeug wie AVR-Studio schon hilfreich sein.
Yalu X. schrieb:> Das Programm kompiliert nur dann, wenn man die zweite (fehlerhafte)> println-Anweisung weglässt. Das dritte println ist in Ordnung, obwohl p1> temporär die Ownerschaft an p2 abgegeben hat.
Hm, interessant. Das kann C++ nicht. Und wie funktioniert das wenn die
Referenz eine Member-Variable ist? Wenn man in einer Member-Funktion a()
dann aus der Referenz heraus-movt, kann man dann in einer
Member-Funktion b() noch drauf zugreifen?
Und was ist in so einem Fall, angenommen der Rückgabewert von getInput()
ist erst zur Laufzeit bekannt (Tastatureingabe oder so) (modulo Syntax):
1
fn main() {
2
let mut p1 = box 123i; // zunächst ist p1 Owner
3
println!("{}", p1); // OK
4
5
if (getInput () == 27) {
6
let p2 = p1; // dann übernimmt p2 die Ownerschaft
7
}
8
9
p1 = box 456i; // p1 wird erneut Owner
10
println!("{}", p1); // OK
11
}
Ob also "p1" am Ende etwas enthält oder nicht weiß der Compiler nicht,
was macht er dann?
Funktioniert das in Rust dann nur mit solchen Referenzen oder kann man
sich auch seine eigenen Typen mit move semantics bauen, bei denen man
ebenfalls nicht auf eine moved-from Instanz zugreifen kann?
Salewski, Stefan schrieb:> für komplizierten Code mit verschachtelten Datenstrukturen und Rekursion> kann ich mir nicht vorstellen, dass ein Debugger mir viel hilft.
Wie findest du denn dann da Fehler? 10000x printf? Wenn es irgendwo
abschmiert auf die letzte printf-Ausgabe gucken, die hoffentlich alle
relevanten Variablen ausgibt?
Wie findest du Fehler dass in C(++) versehentlich eine Variable
überschrieben wird (Speicherfehler) wenn nicht mit Watchpoints?
Was wenn die printf-Informationen so viele sind dass sie nicht einfach
über UART an den PC übertragen werden können? Bei Verwendung eines
Debuggers kann man zu beliebigem Zeitpunkt (ISR, ...) anhalten (lassen)
und sich alles angucken, egal wie schnell der Code läuft...
Dr. Sommer schrieb:> Wie findest du denn dann da Fehler?
Ein paar Textausgaben (bei uC etwa über UART) und etwas Nachdenken. Gut,
funktioniert nicht immer. Ich kann mich noch erinnern, bei meiner
USB-Firmware hatte ich lange Zeit den Chip einfach nicht anbekommen, war
einfach tot. Da habe ich wohl eine Woche herumprobiert -- Lösung war
einfach, dass man drei Befehle aus dem Datenblatt in einer bestimmten
Reihenfolge schreiben musste, eventuell noch mit einem Delay dazwischen.
Das stand aber nicht im Datenblatt. Oder bei meinem PCB-Router, da habe
ich schon mal ein paar Tage nach manch trivialem Fehler gesucht. Aber
ich wüsste überhaupt nicht, wo ich da etwa einen Breakpoint setzen
sollte...
Debugger kann ich mir eigentlich nur für fremde Software vorstellen,
wenn die etwa mit segfault abricht und man nicht weiss wo. Das soll ja
mit dem gcc gnu Debugger gehen, müßte ich vielleicht auch mal lernen...
Salewski, Stefan schrieb:> Debugger kann ich mir eigentlich nur für fremde Software vorstellen,> wenn die etwa mit segfault abricht und man nicht weiss wo. Das soll ja> mit dem gcc gnu Debugger gehen, müßte ich vielleicht auch mal lernen...
Klar geht das, dafür ist der da... Aber auch bei eigener Software, wenn
die plötzlich abschmiert - wie willst du rausfinden wo das war?
Salewski, Stefan schrieb:> Ein paar Textausgaben (bei uC etwa über UART)
Und was wenn der relevante Code 100000x pro Sekunde läuft, so viele
Ausgaben inkl. der relevanten Variablen kriegste per UART nicht hin...
Ich würde mal sagen gerade bei komplexen Projekten ist ein richtiger
Debugger extrem hilfreich...
Dr. Sommer schrieb:> Klar geht das, dafür ist der da... Aber auch bei eigener Software, wenn> die plötzlich abschmiert - wie willst du rausfinden wo das war?>
Na bei eigener Software weiß man ja, an welcher Stelle man zuletzt
gearbeitet hat.
> Salewski, Stefan schrieb:>> Ein paar Textausgaben (bei uC etwa über UART)> Und was wenn der relevante Code 100000x pro Sekunde läuft, so viele> Ausgaben inkl. der relevanten Variablen kriegste per UART nicht hin...>
Und Deine Augen können 100000x pro Sekunde Ausgaben des Debuggers
verarbeiten?
> Ich würde mal sagen gerade bei komplexen Projekten ist ein richtiger> Debugger extrem hilfreich...
Beispiel: Ich habe ein ganz einfaches PCB Test-Layout generiert per
Zufallsgenerator, mit vielleicht 20 Leiterbahnen, zweiseitiges Layout,
der Rechner rechnet daran nur 0.03 Sekunden. 1000 mal ist alles perfekt,
aber dann, für einen bestimmten Seed-Wert kreuzen sich irgendwo die
Bahnen. In den 0.03 Sekunden hat der Rechner vielleicht eine Million
Zeilen Code abgearbeitet. Und ich habe keine Idee. Was soll ich da mit
dem Debugger anfangen? (Wenn ich eine Idee habe, dann ist das Problem eh
schon fast gelöst.)Oder anderes Beispiel: In meiner Jugend hatte ich mal
ein etwas dümmliches Schachprogramm gemacht -- das Stichwort
alpha-beta-prunnung kannte ich da noch nicht -- ich habe also die Züge
in voller Breite rekursiv durchgerechnet. Natürlich kamen da auch Feher
vor, und ich hatte mir dann tatsächlich für 200 D-Mark den
Oberon-Debugger gekauft. War auch ein nettes Spielzeug, Breakpoint
setzen, Durchlaufen bis bestimmte Variablen bestimmte Werte haben,
Speicherstellen modifizieren, alles schön grafisch dargestellt. Aber für
das Schachprogramm war das alles keine Hilfe, da musste ich dann doch
nachdenken. Auch ohne Rekursion, wenn ich also eine Zug-Baum im Speicher
generiert hätte, wüsste ich nicht wirklich was mir der Debugger da
helfen sollte.
Dr. Sommer schrieb:> fn main() {> let mut p1 = box 123i; // zunächst ist p1 Owner> println!("{}", p1); // OK>> if (getInput () == 27) {> let p2 = p1; // dann übernimmt p2 die Ownerschaft> }>> p1 = box 456i; // p1 wird erneut Owner> println!("{}", p1); // OK> }>> Ob also "p1" am Ende etwas enthält oder nicht weiß der Compiler nicht,> was macht er dann?
In diesem konkreten Fall ist p1 beim letzten println auf jeden Fall
gültig, weil du ihm in der Zeile davor einen neuen Wert zugewiesen hast.
Aber lassen wir die Zeile "p1 = box 456i" mal weg. Jetzt gibt es zwei
Möglichkeiten:
1. Die If-Bedingung ist falsch, dann ist p1 bis zum Schluss gültig, und
das Programm läuft fehlerfrei ab.
2. Die If-Bedingung ist wahr, dann wird p1 nach p2 gemovet und p1 somit
ungültig. Damit kann der Zugriff auf p1 im letzten println nicht mehr
ausgeführt werden.
Rust geht davon aus, dass bei Verzweigungen immer beide Alternativen
eintreten können. Wenn mindestens eine der beiden zum Fehler führt, gilt
das Programm als fehlerhaft und der Compiler gibt eine "use of moved
value"-Meldung in der Zeile mit dem println aus. Ein Zugriff auf eine
Owned Box ist nur dann zulässig, wenn alle Ablaufpfade, die zu
entsprechenden Stelle führen, zu einen gültigen Pointer führen. Das wird
vom Compiler durch eine entsprechende Datenflussanalyse überprüft.
> Und wie funktioniert das wenn die Referenz eine Member-Variable ist?> Wenn man in einer Member-Funktion a() dann aus der Referenz> heraus-movt, kann man dann in einer Member-Funktion b() noch drauf> zugreifen?
So genau kann ich das im Moment noch nicht sagen (bin ja noch Anfänger).
Ein wenig Herumprobieren hat ergeben, dass es ziemlich schwierig, wenn
nicht sogar unmöglich ist, eine Box, die ein Member ist, mit Zustimmung
des Compilers per Methode aus einem Objekt nach außen zu moven. Die
Frage ist aber, ob man das überhaupt möchte, da man dadurch ja auf jeden
Fall ein "Loch" im Objekt hinterlässt. Die Alternativen wären:
- Man lässt sich eine Kopie des Inhalts der Box zurückgeben. Das geht
immer, ist aber bei größeren Datenstrukturen evtl. zu ineffizient.
- Man lässt sich eine "geborgte" Referenz zurückgeben. Dabei bleibt die
Ownership unangetastet. Allerdings ist dabei sicherzustellen, dass die
geborgte Referenz nicht länger lebt als das Objekt, auf dessen Member
sie zeigt. Ist sich der Compiler diesbezüglich nicht sicher, meckert
er "cannot infer an appropriate lifetime for borrow expression due to
conflicting requirements", gibt aber netterweise einen konstruktiven
Hinweis: "consider using an explicit lifetime parameter as shown: fn
getPtr<'a>(&'a self) -> &'a int".
Was es mit diesem Lifetime-Parameter auf sich hat, muss ich erst noch
nachlesen.
Salewski, Stefan schrieb:> Beispiel: Ich habe ein ganz einfaches PCB Test-Layout generiert per> Zufallsgenerator, mit vielleicht 20 Leiterbahnen, zweiseitiges Layout,> der Rechner rechnet daran nur 0.03 Sekunden. 1000 mal ist alles perfekt,> aber dann, für einen bestimmten Seed-Wert kreuzen sich irgendwo die> Bahnen. In den 0.03 Sekunden hat der Rechner vielleicht eine Million> Zeilen Code abgearbeitet. Und ich habe keine Idee. Was soll ich da mit> dem Debugger anfangen? (Wenn ich eine Idee habe, dann ist das Problem eh> schon fast gelöst.)
Stichwort Reverse Debugging (erste Paper aus den 1970ern, aber je nach
Verfahren erst heute praktikabel). Kurz gefasst: Es werden bspw.
Programmzustände aufgezeichnet und es kann rückwärts durch den
Programmablauf debuggt werden.
Gute Artikelserie dazu
Übersicht
http://jakob.engbloms.se/archives/1547
Forschung/Paper
http://jakob.engbloms.se/archives/1554
Produkte die das unterstützen
http://jakob.engbloms.se/archives/1564
Salewski, Stefan schrieb:> Dr. Sommer schrieb:>> Klar geht das, dafür ist der da... Aber auch bei eigener Software, wenn>> die plötzlich abschmiert - wie willst du rausfinden wo das war?>>>> Na bei eigener Software weiß man ja, an welcher Stelle man zuletzt> gearbeitet hat.
Und es stürzt bei dir immer nur da ab? Und du schreibst immer nur ein
paar Zeilen auf einmal? Dann bist du ein Spezialfall...
>>> Salewski, Stefan schrieb:>>> Ein paar Textausgaben (bei uC etwa über UART)>> Und was wenn der relevante Code 100000x pro Sekunde läuft, so viele>> Ausgaben inkl. der relevanten Variablen kriegste per UART nicht hin...>>>> Und Deine Augen können 100000x pro Sekunde Ausgaben des Debuggers> verarbeiten?
Nein. Aber wenn der Code abschmiert, bleibt der Debugger stehen und ich
kann alle Variablen analysieren.
> Und ich habe keine Idee. Was soll ich da mit> dem Debugger anfangen?
Die Werte mit assert() überprüfen. Sind sie ungültig, bleibt der
Debugger stehen und man kann alles analysieren.
> Auch ohne Rekursion, wenn ich also eine Zug-Baum im Speicher> generiert hätte, wüsste ich nicht wirklich was mir der Debugger da> helfen sollte.
Fehler, die sich nur in ungültigen Werten äußern die man nicht einfach
per if() auf Gültigkeit/Konsistenz prüfen kann äußern, sind aber nur
eine Klasse. Ja, bei denen muss man sich tatsächlich eine Menge
debug-Informationen ausgeben lassen und die analysieren.
Gegenbeispiel: Du hast einen riesigen Code und irgendwo ganz tief
versteckt ist ein Array aus Funktionspointern, die nacheinander
aufgerufen werden. Leider ist die Größe verkehrt angegeben, und es wird
ein undefinierter Wert aus dem Speicher geholt und dieser als
Funktionspointer "aufgerufen" (klassischer Buffer-Overflow). Das
Programm stürzt ab. Mit einem Debugger ist das Problem schnell gefunden,
man macht einen Backtrace, findet den ungültigen Aufruf, stellt fest
dass eine falsche Adresse geladen wird, stellt fest dass die Größe
falsch war.
Durch pures Nachdenken hätte man den Fehler nicht gefunden. Und sich die
(vermeintliche) Größe dieses Arrays per printf() auszugeben, darauf muss
man auch erstmal kommen.
Salewski, Stefan schrieb:> und ich hatte mir dann tatsächlich für 200 D-Mark den> Oberon-Debugger gekauft.
der GDB ist heutzutage gratis... Bei Hardware-Entwicklung braucht man
noch einen Adapter, aber den braucht man zB bei ARM sowieso.
Yalu X. schrieb:> Das wird> vom Compiler durch eine entsprechende Datenflussanalyse überprüft.
Das ist sehr interessant. Das kann C++ tatsächlich überhaupt nicht und
wird es wohl auch so schnell nicht bekommen... Das ermöglicht dann
natürlich einige interessante Dinge.
Hallo Yalu (und Johann),
was ich noch nicht wirklich verstanden habe: Wann muss man eigentlich
(bei PC-Programmierung) unbedingt auf einen Garbage-Collector
verzichten? Ich habe dazu eben u.a. diesen Beitrag gefunden
http://stackoverflow.com/questions/19612801/how-do-i-do-realtime-programming-in-rust
aber so wirklich viel hilft der mir auch nicht. Es gibt ja jetzt wohl
Algorithmen für Garbage-Collectoren, die nur Pausen von wenigen ms
erzwingen, und eh allenfalls dann aufgerufen werden, wenn Speicher
angefordert wird. So ist das ja wohl bei Nimrod (und die
Oberon-Betriebssysteme der ETH Zürich etwa verwenden ja schon immer GC.)
Und viel Performance kosten die GC auch nicht. Grundsätzlich wird man GC
ja wohl auch kurzzeitig blockieren können, so dass etwa ein
zeitkritischer Interrupt nicht unterbrochen wird?
Klar, wenn man C-Bibliotheken verwendet, muss man deren interner
Speicherverwantung folgen, GC geht also nicht so ohne weiteres, man
müßte Wrapper schreiben. Kann man das mit den verschiedenen
Rust-Pointern wirklich einfacher erschlagen.
Und sonst: Bei mehreren Threads oder Prozessen und geneinsam genutzten
Datenstrukturen könnte ich mir Probleme verstellen.
Im Embedded-Bereich ist es mir schon klarer, da kann eine Pause von 1 ms
womöglich schon zu lang sein, und insbesondere möchte man, dass der
gesammte Code so klein wie möglich ist, also kein Platz für den GC.
Von außen sieht es mal so aus als wäre Rust bald ready to roll.
https://github.com/rust-lang/rust/issues/milestones
Das könnte man jedenfalls wegen diesem Balken, der sich fast jeden Tag
um 1% verschiebt, und der Tatsache, dass extra ein Mann abgestellt wurde
um die Dokumentation/Tutorials zu vollenden, so interpretieren.
Dann bekommt Rust hoffentlich die Libs und Tools die es verdient. Ich
bin ja schon mal sehr gespannt.
Stefan Salewski schrieb:> Im Embedded-Bereich ist es mir schon klarer, da kann eine Pause von 1 ms> womöglich schon zu lang sein, und insbesondere möchte man, dass der> gesammte Code so klein wie möglich ist, also kein Platz für den GC.
luna (avr) hat ja einen GC, mich würde da tatsächlich mal interessieren
wie das effizient funktionieren soll. Gut, er ist optional aber per
default aktiv. Bei den kritischen Zeitzuständen im Controller frage ich
mich ernsthaft wieviel Sinn das macht da eine dynamische
Speicherverwaltung mit einem GC zu verwenden. Sind die notwendigen
Verwaltungsdaten nicht sinnlose Speicherverschwendung, oder kommt das
auf den Anwendungsfall an?
Die Welt geht vor die Hunde schrieb:> Sind die notwendigen> Verwaltungsdaten nicht sinnlose Speicherverschwendung
Noch jemand, der glaubt, malloc() käme ohne Verwaltungsdaten aus?
Tipp: woher weiß free() denn eigentlich, wieviele Bytes da freigegeben
werden sollen? Kriegt doch schließlich nur einen simplen zeiger ohne
weitere Längenangabe übergeben.
Michael schrieb:> Noch jemand, der glaubt, malloc() käme ohne Verwaltungsdaten aus?
OT: Gibt es irgendwo eine schöne Beschreibung, was dort überhaupt intern
geschieht?
Naja, es gibt jede Menge verschiedene Implementierungsmöglichkeiten.
Einfache Beispiele:
Du kannst eine Bitmap haben, die pro Speicherblock fester Größe ein Bit
an Verwaltungsdaten hat. Belegte Blöcke führen zu gesetztem Bit.
Schöner Effekt: Das Vereinigen freier benachbarter Blöcke geschieht
automatisch und kostenlos.
Du kannst diese Speicherblöcke auch in Baumstrukturen verwalten.
Du kannst variable Speicherblockgrößen haben, und dann in das Wort vor
dem Speicherblock eine Längenangabe packen (free() guckt dann an p-4
nach der Länge).
Du kannst...
Wenns dich interessiert, gibts zwei Wege:
(a) Uniskripte haben oft grobe Überblicke über Strategien. Entweder im
Betriebssystembereich, oder im Programmiersprachenbereich
(b) die mallocs der freien Betriebssysteme mal angucken. Die
BSD-Varianten und Linux wären erste Einstiegspunkte. Sehr bekannt und
oft verwendet ist auch jemalloc: http://www.canonware.com/jemalloc/
Michael schrieb:> Die Welt geht vor die Hunde schrieb:>> Sind die notwendigen>> Verwaltungsdaten nicht sinnlose Speicherverschwendung>> Noch jemand, der glaubt, malloc() käme ohne Verwaltungsdaten aus?>> Tipp: woher weiß free() denn eigentlich, wieviele Bytes da freigegeben> werden sollen? Kriegt doch schließlich nur einen simplen zeiger ohne> weitere Längenangabe übergeben.
Wer nutzt denn malloc() auf einem AVR? Da macht man schön alles
statisch. Das ist übersichtlich und reduziert den Speicherverbrauch auf
ein Minimun. Es geht doch darum, dass dieser Speicherverbrauch bei
LuaAVR per Default schon eingestellt ist und nicht darum wie sich das
dynamische Speichersystem von zwei Sprachen unterscheidet. Weil es
praktisch auf so einer Platform einfach nicht hin sinnvoll ist.
Fritz schrieb:> Es geht ja eben darum, die mistige Syntax von C und C++ zu verbessern,> so daß der Programmierer leichter und klarer ausdrücken kann, was er> will.
Dass die Syntax von C++ teilweise unnötig kompliziert ist, unterschreib
ich gerne. Aber die von C? Echt jetzt? Was soll an der so komplex sein?
TriHexagon schrieb:> Wer nutzt denn malloc() auf einem AVR?
Wenn du nur statischen Speicher verwendest, dann verwendest du eh keinen
GC.
Da wir über GC diskutieren, gehts zwingend auch um malloc und Konsorten.
TriHexagon schrieb:> Es geht doch darum, dass dieser Speicherverbrauch bei> LuaAVR per Default schon eingestellt ist und nicht darum wie sich das> dynamische Speichersystem von zwei Sprachen unterscheidet. Weil es> praktisch auf so einer Platform einfach nicht hin sinnvoll ist.
warum sollte das nicht sinnvoll sein? Das kommt doch schlussendlich auf
die Implementierungsart an. Wenn bei malloc() und Co. Verwaltungsdaten
nur dann anfallen, wenn man diese Befehle nutzt, hat man die Wahl und
somit gibt es gar kein Problem.
http://www.nongnu.org/avr-libc/user-manual/malloc.html
wobei mir einfällt: kann bei knappem Speicher und haufenweisem free()
von kleinen Speicherblöcken die Freelist in den Stack wachsen?
Bei luna-avr ist das laut Dokumentation ähnlich gelöst, wobei das hier
augenscheinlich als verkettete Liste verwaltet wird, es existiert keine
statische Tabelle (jedenfalls habe ich keinen Hinweis darauf gefunden).
http://avr.myluna.de/doku.php?id=de:speicherverwaltung
Jeder Speicherblock kann also auch mit einer intrinsischen Variable
verknüpft sein, beim Aufräumen des GC werden dann die Zeiger automatisch
angepasst. Da keine Liste existiert ist der heap hier komplett statisch
nutzbar ohne Speicherblockanforderungen. Täuscht das, oder sind 5 bytes
per Block dann aber schon etwas viel? Vor allem ist nicht beschrieben
wann die GarbageCollection durchgeführt wird, beim Freigeben?
Mandrosil schrieb:> http://www.nongnu.org/avr-libc/user-manual/malloc.html> wobei mir einfällt: kann bei knappem Speicher und haufenweisem free()> von kleinen Speicherblöcken die Freelist in den Stack wachsen?
Deine Sorge ist unbegründet, denn die die Freelist-Knoten werden in den
freien Speicherblöcken selber gespeichert. Voraussetzung dafür ist
natürlich, dass die freien Speicherblöcke mindestens 4 Byte groß sind (2
Bytes für die Größe und 2 Bytes für den Zeiger auf den nächten freien
Block). Deswegen wird bereits in malloc() dafür gesorgt, dass die
allozierten Blöcke inkl. der Größenangabe mindestens 4 Bytes groß sind,
d.h. sie enthalten mindestens 2 Bytes Nutzdaten. Bei malloc(1) wird
demzufolge 1 Byte verschenkt. Wegen eines einzelnen Bytes wird aber auch
kaum jemand die dynamische Speichverwaltung bemühen.
Yalu X. schrieb:> Wenn jemand von euch ebenfalls schon Erfahrungen mit diesen Sprachen> gesammelt hat, würde mich eure Meinung dazu interessieren.
Nun ja, Dein Beitrag ist ja nun auch schon etwas älter...
Zu Nim gibt es jetzt auch ein Buch -- genauer gesagt die ersten Kapitel.
Das erste ist wohl frei erhältlich, die ersten drei gegen Geld, der Rest
dann im laufe des Jahres. Momentan gibt es einen Rabattcode, damit
bekommt man die digitale Version für 20 Dollar. Das ist schon sehr fair
für die viele Arbeit, und der Author hat schon etwas auf dem Kasten. Ich
habe es mir gestern mal bestellt.
Neben Nim gibt es natürlich derzeit viele Interessante andere Sprachen,
Rust und Haskell hatten wir ja diskutiert, Crystal ist wohl auch
bekannt, der Hype hat aber in den letzten Monaten etwas nachgelassen.
Und Swift ist ja nun auch mehr oder weniger frei.
Um mal etwas konkrete Erfahrung mit Nim zu sammels habe ich in den
letzten Tagen mal "from Scratch" ein einfaches Schachspiel geschrieben,
mit GTK3 GUI und Figuren als Unicode Fonts. Das ging wirklich alles sehr
schnell und einfach, in Ruby hätte ich wohl länger gebraucht, in C erst
recht. Fazit: Ich werde mich weiter auf Nim konzentrieren, die Sprache
ist für mich der derzeit beste Kompromis. Rust und Haskell haben sicher
ihre Berechtigung, die werde ich auch weiter beobachten. Und Crystal
wohl auch, zumal es sehr stark Ruby ähnelt. Falls Du noch Nim
installiert hast, hier findest Du mein Schachspiel:
https://github.com/StefanSalewski/nim-chess Und hier das Bildchen dazu:
http://ssalewski.de/tmp/toychess.png
Hello World ;) schrieb:> Lisp hat seine> Tauglichkeit längst bei AutoCAD unter Beweis gestellt.
Ja damals als LISP noch schick war und man darin die Zukunft sah, zu der
eit ist auch das erste AutoCAD entstanden, deshalb steckt heute noch der
Zombie dort drinn, man kann aber längst in anderen Sprachen unter
AutoCAD entwickeln.
LISP ist praktisch tot, der letze kommerzielle Lispcompilerhersteller
ist schon seit Jahren dicht. LISP bzw. dessen verwandte akadmische
Spielzeugsprachen wie Haskell und Co dienen nur noch als Material- und
Ideenlager für andere Sprachen, siehe JavaScript in seinen aktuellen
Versionen und Bastarden davon um mal eine relevante Sprache mit
funktionalen Anteilen zu nennen. Nat. gibts immer wieder Versuche was
möglichst LISPartiges zu etablieren wie die Missgeburt namens Scala,
auch so eine Otterbrut aus dem Reich der Hochschulen, völlig verkorkst
mit noch kaputteren Bibliotheken als das Sprachdesign, aber mit einer
umso stärkeren Fanboitruppe. Ok der Hype von Scala ist inzwischen auch
vorbei und die Leute sind in der Realität angekommen, wie schon
dutzendfach beim xten Versuchen eine weitgehend funktionale Sprache zu
etablieren, das Zeug will in der Praxis einfach niemand, wenn dann nur
einzelne funktionale (damit ist das Programmierparadigma gemeint nicht
im sinne von 'praktisch nützlich' o.ä.) Anteile. Und wenn ihre
Funtkionalen Fanboischreihälse das Feature in der nächsten Release
durchgeboxt haben wie z.B. in Python fliegt es später wieder mangels
Verwendung still und leise bei der nächsten Relase wieder raus. LISP
bzw. funktionale Sprachen sind wie der Schweinezyklus, kommen alle paar
Jahre wieder in Form eines Hypes, weil eine neue Generation von Kindern
an den Hochschulen die coolness wiederentdecken und die
praxisuntauglichkeit nicht erfahren haben, eben mangels Praxis. Ausser
den typischen Lehrbuchbeispielen kennen sie nix, die sehen nat. alle
elegant und einfach aus.
Stefan S. schrieb:> Um mal etwas konkrete Erfahrung mit Nim zu sammels habe ich in den> letzten Tagen mal "from Scratch" ein einfaches Schachspiel geschrieben,> mit GTK3 GUI und Figuren als Unicode Fonts.
Coole Sache! Hab's natürlich gleich mal ausprobiert :)
Leider hat das Programm nicht auf Anhieb gebaut, weil da wohl die
int()-Funktion aus GTK3 mit der gleichnamigen von Nim clasht. Ein
1
import gtk3 except int
in board.nim behebt das Problem aber.
Gemessen an der Quellcodegröße (engine.nim) und der ziemlich kurzen
Bedenkzeit spielt das Programm erstaunlich gut. Auch das GUI (board.nim)
ist knackig kurz. Was vielleicht noch ein Bisschen fehlt, ist eine
Erkennung, wann das Spiel zu Ende ist ;-)
Zwiebelrostbratenausgasung schrieb:> LISP ist praktisch tot, der letze kommerzielle Lispcompilerhersteller> ist schon seit Jahren dicht.
Falsch vermutet. Es gibt mindestens noch drei Lisp-Compiler für Geld,
die noch aktiv weiterentwickelt werden, davon zwei Klassiker und ein
Newcomer für Mobilgeräte:
Allegro Common Lisp: http://franz.com/products/allegro-common-lisp/
LispWorks: http://www.lispworks.com/products/lispworks.html
mocl: https://wukix.com/mocl
Dazu kommen noch ein paar Lisp-Compiler (z.B. von Scieneer und Corman),
die nicht mehr groß weiterentwickelt zu werden scheinen, aber nach wie
vor von deren Herstellern verkauft werden.
> LISP bzw. dessen verwandte akadmische Spielzeugsprachen wie Haskell> und Co […]> Nat. gibts immer wieder Versuche was möglichst LISPartiges zu> etablieren wie die Missgeburt namens Scala […]
Für dich ist wohl jede Programmiersprache, die du nicht kennst,
Lisp-artig :)
> Ok der Hype von Scala ist inzwischen auch vorbei> LISP bzw. funktionale Sprachen sind wie der Schweinezyklus, kommen> alle paar Jahre wieder in Form eines Hypes
Von welchen Hypes sprichst du? Habe ich da etwas verpasst?
Nein, da gibt es (zum Glück) weder Hypes noch Schweinezyklen. Die
funktionale Programmierung entwickelt sich ganz leise und stetig weiter,
ähnlich wie das lange Zeit bei der objektorientierten Programmierung der
Fall war, nur noch langsamer. Irgendwann wird der Tag kommen, an dem die
ganze Welt funktional programmiert, ohne sich dessen bewusst zu sein :)
Meines Erachtens nach ist C (nicht C++) das einzige was wirklich etwas
taugt, zumindest für performante und hardwarenahe Sachen. C# mag ja gut
sein um Klicki-Bunti zu machen. Aber auch der Brocken wie Java etc. ist
einfach nur ein versuch es allen recht zu machen. Klar Java ist
plattformunabhängig, aber dafür auch in gewissen Sachen nicht wirklich
performant, insbesondere dann, wenn ein Java-Programm geladen wird und
vorher noch nichts mit Java zur Systemlaufzeit gestartet wurde. Da wird
erstmal ein riesen Brocken an Software geladen noch bevor die
eigentliche Anwendung loslegen kann. Plain C mit Winapi etc. ist
schneller als alles andere (wenn man natürlich programmieren kann),
dumme nutzen fertig C#/.net Libs und die verzeichen auch dummen, dass
sie nicht programmieren können und bleiben nahezu gleich schnell.
Diese ganze Objektorientiuierung mag für den ein oder anderen - insb.
für Softies, die von der Hardware, die den Code ausführt keine Ahnung
haben - ein Segen sein, aber in Wirklichkeit ist es doch nur ein Mittel
um Softies auch mal die Möglichkeit zu geben sich geistig austoben zu
können.
Das einzig tolle an C++ finde ich die Polymorphie, alles andere ist
unnötig und trägt nur zur Unübersichtlichkeit des Codes bei. Sicherlich
ist sowas auch einer der Gründe warum selbst für popelige Software 1 GB
Festplattenspeicher, 2 GB RAM und ein DualCore benötigt wird.
Yalu X. schrieb:> Coole Sache! Hab's natürlich gleich mal ausprobiert :)>> Leider hat das Programm nicht auf Anhieb gebaut, weil da wohl die> int()-Funktion aus GTK3 mit der gleichnamigen von Nim clasht.
Hallo Yalu,
das überascht mich etwas. In der Tat gibt es in gtk3.nim
1
proc int*(settings: PrintSettings;
2
key: cstring): gint {.
3
importc: "gtk_print_settings_get_int", libgtk.}
aber das sollte ja kein Problem sein, auf Grund der Parameter.
Und einige andere Leute haben das Programm auch schon ausprobiert,
soweit ich weiss ohne dieses Problem. Hast Du Nim 0.13 ? Aber gut, Du
hast es ja beheben können. Ja, ein paar Erweiterungen werde ich wohl
irgendwann mal einbauen. Ursprünglich hatte ich das Programm eigentlich
nur für mich geschrieben, um etwas mehr praktische Übung mit Nim zu
erlangen und um meine GTK3-Bindings etwas zu testen. Ich war wirklich
überascht, wie schnell man mit Nim doch Software schreiben kann -- bei
Programmen länger als einige hundert Zeilen wohl schneller als mit
Python oder Ruby. Die statische Typisierung und die Compiler-Meldungen
sind schon hilfreich.
board.nim(65, 22) Error: type mismatch: got (gdouble)
6
but expected one of:
7
gtk3.int(settings: PrintSettings, key: cstring)
8
gobject.int(value: GValue)
Das ist schon etwas komisch: Der Compiler erkennt zwar, dass gtk3.int
und gobject.int typmäßig nicht passen, aber auf die Idee, stattdessen
einfach die int-Funktion von Nim zu nehmen, kommt er scheinbar nicht.
Falls doch noch jemand Interesse an Nim hat: Das Buch "Nim in Action"
gibt es heute nochmals zum halben Preis, also die EPub und PDF-Version
für ca. 20 Dollar. Der Rabatt-Code ist im Nim Forum angegeben. (Wobei,
der Sinn dieser Rabatt-Aktionen erschliesst sich mir nicht, damit hatte
sich doch schon ein Baumarkt ruiniert.)
W.S. schrieb:> Die Welt braucht nicht noch einen Vorbrenner für C - kurzum, das Ganze> ist Murks. Weder effizient, noch elegant.
Nö. Der Bedarf ist schon da, und neben C gibt es ja auch JS und
experimentell LLVM als Backend. Und C wurde schon mit Bedacht gewählt --
die Nachteile sind bekannt, die Vorteile überwiegen aber.
Aber es gibt natürlich auch noch einige andere interessante moderne
Sprachen.
Stefan S. schrieb:> Der Bedarf ist schon da
Wo bitte?
Also mein finaler Komentar: igittigit. Wenn ich C schreiben will, dann
kann ich das direkt tun, ohne solche finsteren Vorbrenner. Ich denke mit
Schaudern an A.Dunkels Proto-Threads und Co.
Hätten diese Leute doch man bloß ihren Entwicklerschweiß in was
handfesteres gesteckt, wie z.B. ein ordentlich optimierendes Pascal für
den Cortex.
W.S.
W.S. schrieb:> Also mein finaler Komentar: igittigit. Wenn ich C schreiben will, dann> kann ich das direkt tun, ohne solche finsteren Vorbrenner.
Was ist denn so schlecht daran, als Native-Code-Compiler einen bewährten
C-Compiler mit all seinen Optimierungsfähigkeiten zu nutzen, dass du
dich gleich in zwei Beiträgen darüber echauffieren musst? Man muss den
C-Zwischencode ja nicht anschauen.
Ja, diese beiden Kommentare des Herrn W.S. sind schon sehr schwach...
Die Nachteile von C Zwischencode sind bekannt. So kann man die echten
Low-Level Elemente der Hardware, die C nicht kennt, nicht wirklich gut
ausnutzen. Dies betrifft etwa Exceptions oder das Erkennen von
ganzahligen Überläufen bei unsigned int Arithmetik. Und für gute
Effizienz muss es möglich sein, die Ausgangssprache gut in C abzubilden.
Debugging ist durch den C Zwischencode wohl auch etwas erschwert --
wobei anderersets kann man sich so auch den C Code ansehen.
Vorteile: Es gibt auf fast jedem System einen C-Compiler, meist sogar
hoch optimierende C-Compiler. Damit kann die Ausgangssprache dann
prinzipiell dort eingesetzt werden. Weiter hat man sehr gute
Kompatibilität zu all den C Bibliotheken, oder man kann Software
wahlweise auch in Form des C Zwischencodes ausliefern, der Nutzer
benötigt dann nur einen C Compiler.
LLVM ist wie erwähnt auch eine (spätere) Option.
Na ja, Yalu weiss das eh besser als ich, und den Herr WS wird es nicht
wirklich interessieren. Wundert mich eigentlich etwas, denn Nim hat mit
Pascal/Delphi doch einige Ähnlichkeiten.
Stefan Salewski schrieb:> Wundert mich eigentlich etwas, denn Nim hat mit> Pascal/Delphi doch einige Ähnlichkeiten.
Wie bitte?
Etwa so, wie KDE zu Windows?
OK, Basteln ist Hobbysache und niemand fragt einen, womit man seine
Freizeit verbringt. Insofern ist das wurscht.
Yalu X. schrieb:> Was ist denn so schlecht daran, als Native-Code-Compiler einen bewährten> C-Compiler mit all seinen Optimierungsfähigkeiten zu nutzen
Ach Yalu, die Sage vom Sisyphus oder wie der Kerl mit dem Stein geheißen
haben mag, kennst du ja wohl. Mich dauert es eben immer wieder, wenn
Leute ihre Zeit und Kraft in solches Zeugs vergeuden. Es ist so
unsäglich sinnlos, denn niemand wird damit irgend etwas wirklich
Sinnvolles anstellen können/wollen.
Genau das ist der Punkt. Wir sollten uns auf "Hobby" einigen, denn da
fragt keiner nach dem Sinn vom Bierkorkensammeln usw.
Aber eigentlich hab ich das ja bereits ganz explizit geschrieben - also
warum fragst du da nochmal hinterher?
W.S.
W.S. schrieb:> Aber eigentlich hab ich das ja bereits ganz explizit geschrieben - also> warum fragst du da nochmal hinterher?
Vermutlich hat er gelesen, dass Beschäftigungstherapie für Choleriker
nur anzuraten ist.
W.S. schrieb:> Wir sollten uns auf "Hobby" einigen, denn da> fragt keiner nach dem Sinn vom Bierkorkensammeln usw.
Wir brauchen uns darüber nicht zu einigen, siehe Thread-Titel.
> Aber eigentlich hab ich das ja bereits ganz explizit geschrieben - also> warum fragst du da nochmal hinterher?
Ja, ich habe das schon gelesen: Dich stört, dass der "Vorbrenner"
"finster" ist. Nebenbei habe ich noch erfahren, dass du kein Freund von
A. Dunkels Protothreads bist (was auch immer das mit Nim zu tun haben
mag) ;-)
W.S. schrieb:> Stefan Salewski schrieb:>> Wundert mich eigentlich etwas, denn Nim hat mit>> Pascal/Delphi doch einige Ähnlichkeiten.>> Wie bitte?
Um ehrlich zu sein, sehe ich auch nicht viele Ähnlichkeiten zwischen den
beiden Sprachen, weder syntaktisch noch semantisch.
Delphi hält halt auf Grund seiner Abstammung noch an der aus den 50er
Jahren stammenden Algol-Syntax fest. Das wäre nicht weiter schlimm, wenn
nicht auch der ganze Rest so altbacken daher käme. Das ist auch kein
Wunder, da Delphi im Wesentlichen aus dem Pascal-Sprachkern aus den 70er
Jahren besteht, der durch etwas Nineties-Style-OOP aufgepeppt wurde. Da
hat Nim, das ohne irgendwelche Altlasten völlig neu konzipiert wurde,
schon deutlich mehr zu bieten.
Aber ich schätze, du bist unter den Programmierern das, was unter den
Autofahrern der Morgan¹-Freak ist, der auch nicht in ein Auto neuerer
Bauart (d.h. ohne ein Gerippe aus Eschenholz) steigen würde :)
W.S. schrieb:> Hätten diese Leute doch man bloß ihren Entwicklerschweiß in was> handfesteres gesteckt, wie z.B. ein ordentlich optimierendes Pascal für> den Cortex.
Ich meine, sowohl Delphi als auch Free Pascal gäbe es auch für Cortexe,
kenne allerdings ihren Reifegrad aber nicht.
————————————
¹) Wobei ein Morgan im Gegensatz zu Pascal/Delphi immerhin einen extrem
hohen Coolness-Faktor hat.
Yalu X. schrieb:> Um ehrlich zu sein, sehe ich auch nicht viele Ähnlichkeiten zwischen den> beiden Sprachen, weder syntaktisch noch semantisch.
Nim FAQ:
What have been the major influences in the language's design?
The language borrows heavily from (in order of impact): Modula 3,
Delphi, Ada, C++, Python, Lisp, Oberon.
Nun ja, ich kann mich an Pascal nur dunkel errinnnern, eher schon an
Modula3 und Oberon. Bei Delphi habe ich nur mal einigen Leuten über die
Schulter geguckt.
Was mir so einfiel: keine {} für Blöcke, "var i: int", const und type
sections, proc() und func(), ptr und ref statt dem * von C, and und or
ausgeschrieben statt && und ||
Stefan Salewski schrieb:> Modula3
Ach Tippfehler. Modula-2 meinte ich, Modula-3 kenne ich nur vom Namen.
Und sonst, inc() und dec() gibt es, oder etwa bei strings wird die Länge
explizit gespeichert.
Aber sonst hat sich bei den modernen Sprachen natürlich viel getan,
Iteratoren, Templates, hygenic Macros, Interfaces (derzeit eher Concepts
bei Nim), Konstrukte für parallele Verarbeitung. Gut, einiges davon hat
Delphi wohl auch mitlerweile.
W.S. schrieb:> Ich denke mit Schaudern an A.Dunkels Proto-Threads und Co.
Ja, ich erinnere mich an diesen Thread. Liegt glaube ich so 1 - 2 Jahre
zurück. Dabei ging es um Sinn und Zweck von RTOS. Und Du hattest
vehement die Ansicht vertreten, dass ein Main-Loop, in der man Flags
abfraegt, voll ausreichend sei. Als ich dann noch Protothreads in die
Diskussion einwarf ...
In all den Jahren habe ich in diesem Forum eines gelernt: wenn W.S.
etwas ablehnt, herabsetzt oder gar ausrastet, dann lohnt es sich für
mich, wenn ich mir dies etwas naeher anschaue. :)
Yalu X. schrieb:> Nebenbei habe ich noch erfahren, dass du kein Freund von> A. Dunkels Protothreads bist (was auch immer das mit Nim zu tun haben> mag) ;-)
Was es mit Nim zu tun hat?
Ich könnte jetzt schreiben: ist dasselbe.
Aber konkret: es ist beides Vorbrenner-Akrobatik.
Bei Dunkel eben Präprozessor-Akrobatik und bei Nim eben
Prä-Umsetzer-Akrobatik oder wie man das nennen sollte.
Ich hätte da eigentlich einen nicht wirklich stubenreinen Ausdruck für
beides. Aber es ist schon bemerkenswert, womit manche Leute ihre
Freizeit ausfüllen.
W.S.
W.S. schrieb:> Prä-Umsetzer-Akrobatik oder wie man das nennen sollte.
Es gab da neulich im Nim Forum bzw. IRC einen Troll, der fest davon
überzeugt war, Nim wäre kein wirklicher Compiler, weil er nicht direkt
Maschiencode erzeugt. Wer mag kann das gerne so sehen.
W.S. schrieb:> Aber es ist schon bemerkenswert, womit manche Leute ihre Freizeit ausfüllen.
Also mit RTOS und Protothreads fülle ich nicht meine Freizeit aus,
sondern meine Arbeitszeit; und somit meinen Geldbeutel.
Was die Freizeit anbelangt: Wegen Deinen negativen Aeusserungen zu Rust
muss ich jetzt in meiner knappen Freizeit mich damit beschaeftigen :(
Mehmet K. schrieb:> In all den Jahren habe ich in diesem Forum eines gelernt: wenn W.S.> etwas ablehnt, herabsetzt oder gar ausrastet, dann lohnt es sich für> mich, wenn ich mir dies etwas naeher anschaue. :)Mehmet K. schrieb:> Was die Freizeit anbelangt: Wegen Deinen negativen Aeusserungen zu Rust> muss ich jetzt in meiner knappen Freizeit mich damit beschaeftigen :(
So gesehen musst du dich mit allem beschäftigen, was nicht Delphi ist.
Oje, da hast du noch einiges vor dir ;-)
Yalu X. schrieb:> So gesehen musst du dich mit allem beschäftigen, was nicht Delphi ist.> Oje, da hast du noch einiges vor dir ;-)
Ne, ne! Ich pick' mir nur die Rosinen raus :)
Yalu X. schrieb:> Oje, da hast du noch einiges vor dir
Naja, Assembler kann er also schon mal auslassen. Eigentlich C auch. Da
bleibt aber ne Menge Firlefanz übrig.
Also los, ihr Beiden.
Die nächste interaktive GUI-App zum Flash-Programmieren für nen STM32
programmiert einer von euch in Rust und der andere in Nim. Und dann
präsentiert eure Ergebnisse hier bei Projekte&Code. Gelle?
W.S.
W.S. schrieb:> Die nächste interaktive GUI-App zum Flash-Programmieren für nen STM32> programmiert einer von euch in Rust und der andere in Nim. Und dann> präsentiert eure Ergebnisse hier bei Projekte&Code. Gelle?
GUI-Programmierung? Pfui-Deifel =8-o
Die Programmiersprache, in der mir GUI-Programmierung Spaß macht, die
muss leider erst noch erfunden werden ;-)
Und da man ein Flash-Tool typischerweise von Make oder einem anderen
Build-Tool aufruft, ist hier ein GUI sowieso eher ein Hindernis als eine
Hilfe.
Da stecke ich meinen Entwicklerschweiß lieber in etwas Handfesteres – um
es mit deinen Worten auszudrücken :)
Yalu X. schrieb:> Die Programmiersprache, in der mir GUI-Programmierung Spaß macht, die> muss leider erst noch erfunden werden ;-)
Ja leider. Die GUI-Unterstützung ist für die meisten interessanten
modernen Sprachen nicht gerade toll. Ausnahmen wären wohl Swift auf OSX
oder Dart und Kotlin für Web bzw. Android -- habe ich mir aber alles
noch nicht angesehen. In den letzten Wochen hatte ich mal einen kleinen
Nim Editor mit GTK3 gemacht -- geht zwar ganz gut, aber die ware Freude
ist das nicht.
http://ssalewski.de/tmp/NEd.pnghttps://github.com/ngtk3/NEd
Also mit XAML lassen sich schon vernünftige GUIs schmerzfrei erstellen
meiner Meinung nach.
Oder eben Web GUIs mit HTML und CSS, das geht auch ganz gut.