Meine Nim-Entwicklungserfahrung


Hallo Habr!


Seit geraumer Zeit schreibe ich mein Spiel-Framework - ein solches Lieblingsprojekt für die Seele. Und da Sie für die Seele etwas auswählen müssen, das Ihnen gefällt (und in diesem Fall das, worüber Sie gerne schreiben), fiel meine Wahl auf nim. In diesem Artikel möchte ich speziell über nim sprechen, über seine Funktionen, Vor- und Nachteile, und das Thema Gamedev bestimmt nur den Kontext meiner Erfahrung - welche Aufgaben ich gelöst habe, welche Schwierigkeiten aufgetreten sind.


Es war einmal, als das Gras grüner und der Himmel sauberer war, traf ich nim. Nein, nicht so. Es war einmal, ich wollte Spiele entwickeln, um mein coolstes Spiel zu schreiben - ich denke, viele haben das durchgemacht. In jenen Tagen tauchten Unity und Unreal Engine gerade erst in der Anhörung auf und waren noch nicht frei. Ich habe sie nicht benutzt, nicht so sehr wegen der Gier, sondern wegen des Wunsches, alles selbst zu schreiben, um eine Spielwelt von Grund auf neu zu erschaffen der erste Null Byte. Ja, für eine lange Zeit, ja, es ist schwierig, aber der Prozess selbst bringt Freude - aber was braucht man noch für das Glück?


Mit Straustrup und Qt bewaffnet, trank ich zum Besten Scheiße, weil ich erstens nicht zu den 10 Menschen auf der Welt gehörte, die C ++ gut kannten, und zweitens steckten die Pluspunkte aktiv Stöcke in meine Räder. Ich sehe keinen Grund zu wiederholen, was Platoff bereits bemerkenswert für mich geschrieben hat:


Wie ich die beste Programmiersprache der Welt gefunden habe. Teil 1
Wie ich die beste Programmiersprache der Welt gefunden habe. Teil 2
Wie ich die beste Programmiersprache der Welt gefunden habe. Yo Teil (2.72)


Dies ist eine verrückte Begeisterung, wenn Sie Code frei schreiben, fast ohne nachzudenken, ohne vor jedem Start auf den Core-Dump zu warten, wenn Funktionen direkt vor unseren Augen hinzugefügt werden, jetzt können wir es tun, und jetzt ist es so, sagen Sie mir bitte, welchen Unterschied es für mich macht Ich habe keine Vorlagen, wenn ich sie nicht verpasst habe. Produktivität ist das Hauptziel des Programmierers, der Dinge tut, und die einzige Aufgabe des Tools, das er verwendet.

Bei der Arbeit mit C ++ habe ich ständig darüber nachgedacht, wie ich schreiben soll, was ich will, und nicht, was ich schreiben soll. Also wechselte ich zu nim. Die Geschichte ist vorbei, lassen Sie mich meine Erfahrungen nach einigen Jahren bei nim mit Ihnen teilen.


Allgemeine Informationen für diejenigen, die nicht Bescheid wissen


  • Open Source Compiler (MIT), entwickelt von Enthusiasten. Der Schöpfer der Sprache ist Andreas Rumpf (Araq). Der zweite Entwickler ist Dominik Picheta (dom96), der das Buch Nim in Aktion geschrieben hat . Außerdem hat Status vor einiger Zeit begonnen, die Entwicklung der Sprache zu sponsern, sodass nim zwei weitere Vollzeitentwickler hat. Zusätzlich zu ihnen werden natürlich andere Leute dazu beitragen.
  • Version 1.0 wurde kürzlich veröffentlicht , was bedeutet, dass die Sprache stabil ist und "brechende Änderungen" nicht mehr erwartet werden. Wenn Sie zuvor die instabile Version nicht verwenden wollten, weil Updates die Anwendung beschädigen könnten, ist es jetzt an der Zeit, nim in Ihren Projekten auszuprobieren.
  • Nim kompiliert (oder transponiert) in C, C ++ (die weiter in nativen Code kompiliert werden) oder JS (mit einigen Einschränkungen). Dementsprechend stehen Ihnen mit Hilfe von FFI alle vorhandenen Bibliotheken für C und C ++ zur Verfügung. Wenn es auf nim kein notwendiges Paket gibt, suchen Sie nach s oder pluses.
  • Die nächstgelegenen Sprachen sind Python (nach Syntax auf den ersten Blick) und D (nach Funktionalität) - IMHO

Die Dokumentation


Das ist eigentlich schlecht. Die Probleme:


  1. Die Dokumentation ist auf verschiedene Quellen verteilt
  2. Die Dokumentation Scheiße beschreibt nicht alle Funktionen der Sprache vollständig
  3. Die Dokumentation ist manchmal zu kurz.

Beispiel: Wenn Sie Multithread-Anwendungen schreiben möchten, gibt es viele Kerne, aber nirgendwo hin.
Hier ist der offizielle Dokumentationsabschnitt zu Streams . Nein, Sie sehen, Threads sind ein separater Hauptteil der Sprache, deren Funktion Sie beim Kompilieren sogar in das --threads:on . Dort gibt es gemeinsam genutzten oder threadlokalen Heap, abhängig vom Garbage Collector, alle Arten von gemeinsam genutztem Speicher und Sperren, Thread-Sicherheit, spezielle gemeinsam genutzte Module und die Hölle weiß was noch. Woher wusste ich das alles? Das ist richtig, aus dem Buch nim in Aktion, dem Forum, dem Stapelüberlauf, dem Fernseher und dem Nachbarn im Allgemeinen von überall, aber nicht aus der offiziellen Dokumentation.


Oder es gibt eine sogenannte. "Notation machen" - funktioniert sehr gut, wenn Vorlagen usw. verwendet werden, im Allgemeinen überall dort, wo Sie einen Rückruf oder nur einen Codeblock übergeben müssen. Wo kann ich darüber lesen? Ja, im Handbuch für experimentelle Funktionen .


Stimmen Sie zu, das Sammeln von Informationen zu verschiedenen nicht informativen Quellen ist immer noch ein Vergnügen. Wenn Sie in nim schreiben, müssen Sie es tun.


Im Forum und in Github-Fragen gab es Vorschläge zur Verbesserung der Dokumentation, aber die Dinge gingen nicht voran. Es scheint mir, dass eine Art harte Hand fehlt, die sagt: "Alles, die Gemeinschaft, nimm die Schaufeln und geh, um diesen Haufen ... genialer, verstreuter Textstücke zu harken."


Zum Glück habe ich meine eigenen getroffen und präsentiere Ihnen die Liste der Nim-Champions


Die Dokumentation


  • Tutorial 1 , Tutorial 2 - beginnen Sie mit ihnen
  • Nim in Aktion ist ein erklärendes Buch, das viele Aspekte der Sprache wirklich gut erklärt, manchmal viel besser als von. Dokumentation
  • Nim Handbuch - eigentlich ein Handbuch - fast alles ist beschrieben, aber nein
  • Nim experimentelles Handbuch - warum nicht die Dokumentation auf einer separaten Seite fortsetzen?
  • Der Index - Links zu allem werden hier gesammelt, dh im Allgemeinen alles, was in nim zu finden ist. Wenn Sie in den Tutorials und im Handbuch nicht das gefunden haben, was Sie benötigen, finden Sie es definitiv im Index.

Lektionen und Tutorials


  • Nim-Grundlagen - die Grundlagen für Anfänger, komplexe Themen, die nicht behandelt werden
  • Nim Days - kleine Projekte (Live-Beispiele)
  • Rosetta Code - es ist sehr cool, die Lösung derselben Aufgaben auf verschiedenen PL zu vergleichen, einschließlich nim
  • Exercism.io - hier können Sie "nim path" gehen und Aufgaben erledigen
  • Nim mit gutem Beispiel

Hilfe


  • IRC ist der Hauptlebensraum ... der Nimmer?, Der auf Discord und Gitter ausgestrahlt wird . Ich habe IRC noch nie benutzt (und benutze es immer noch nicht). Im Allgemeinen ist dies eine sehr seltsame Wahl. Es gibt immer noch Taubenpost für ihn ... okay, Scherz.
  • Nim-Forum Die Funktionen des Forums sind minimal, aber 1) hier finden Sie die Antwort 2) hier können Sie eine Frage stellen, wenn Punkt 1 nicht funktioniert hat 3) die Wahrscheinlichkeit einer Antwort beträgt mehr als 50% 4) die Sprachentwickler sitzen im Forum und antworten aktiv. Das Forum ist übrigens in nim geschrieben und daher gibt es keine Funktionalität
  • Nim-Telegrammgruppe - Es ist möglich, eine Frage zu stellen und keine Antwort zu erhalten.
  • Es gibt auch eine russische Telegrammgruppe. Wenn Sie es satt haben und nichts davon hören möchten, sollten Sie dorthin gehen :) (teilweise ein Witz)

Spielplatz


  • Nim-Spielplatz - hier können Sie das Programm auf nim direkt im Browser ausführen
  • Nim Docker Cross-Compiling - hier können Sie lesen, wie Sie ein Docker-Image starten und das Programm für verschiedene Plattformen kompilieren.

Pakete


  • nimble.directory - Hier sind alle veröffentlichten Pakete aufgeführt, die über den nimble-Paketmanager installiert werden können.
  • Kuratierte Liste von Paketen - eine Liste von mehr oder weniger Live-Paketen, die von Enthusiasten zusammengestellt wurden

Wechseln Sie von anderen Sprachen zu nim



Was magst du?


Es macht keinen Sinn, alle Funktionen der Sprache aufzulisten, aber hier sind einige Funktionen:


Fraktale Komplexität


Nim bietet Ihnen ein "Fraktal der Komplexität". Sie können Code auf hoher Ebene schreiben. Sie können mit rohen Zeigern stoßen und jeden attempt to read from nil genießen attempt to read from nil . Sie können den C-Code einbetten. Sie können Einfügungen in Assembler schreiben. Sie können Prozeduren schreiben (statischer Versand). Nicht genug - es gibt "Methoden" (dynamischer Versand). Noch? Es gibt Generika und es gibt Generika, die Funktionen nachahmen. Es gibt Vorlagen - einen Ersatzmechanismus, aber nicht so erbrechen wie in C ++ (gibt es hier Makros - ist es nur ein Textersatz oder ist es etwas schlauer?). Letztendlich gibt es Makros - es ist wie IDDQD, sie aktivieren den Gott-Modus und ermöglichen es Ihnen, direkt mit AST zu arbeiten und Teile des Syntaxbaums buchstäblich zu ersetzen oder die Sprache selbst zu erweitern, wie Sie möchten.
Das heißt, auf einer "hohen" Ebene können Sie Höllenwörter und Trauer schreiben, um es nicht zu wissen, aber niemand verbietet Ihnen, Betrug jeglicher Komplexität auszuführen.


Entwicklungsgeschwindigkeit


Die Lernkurve ist keine Kurve. Das ist direkt. Durch die Installation von nim starten Sie in der ersten Minute Ihre erste Hallo-Welt und am ersten Tag schreiben Sie ein einfaches Dienstprogramm. Aber in ein paar Monaten müssen Sie etwas lernen. Ich habe zum Beispiel mit Prozeduren begonnen, dann brauchte ich Methoden. Nach einer Weile waren Generika für mich sehr nützlich. Kürzlich entdeckte ich Vorlagen in ihrer vollen Schönheit und gleichzeitig berührte ich überhaupt keine Makros. Im Vergleich zu demselben Rost oder C ++ ist das Zusammenführen mit nim viel einfacher.


Paketverwaltung


Es gibt einen Paketmanager namens nimble, der Pakete installieren, deinstallieren, erstellen und Abhängigkeiten laden kann. Wenn Sie Ihr Paket (= Projekt) erstellen, können Sie verschiedene Aufgaben in nimble schreiben (mit nimscript, einer Teilmenge von nim, die auf einer VM ausgeführt wird), z. B. Dokumentation erstellen, Tests ausführen, Assets kopieren usw. Mit Nimble werden nicht nur die erforderlichen Abhängigkeiten festgelegt, sondern Sie können auch die Arbeitsumgebung für Ihr Projekt konfigurieren. Das heißt, flink ist grob gesagt CMake, das nicht von Perversen, sondern von normalen Menschen geschrieben wurde.


Lesbarkeit und Ausdruckskraft


Äußerlich ist nim Python mit Typanmerkungen sehr ähnlich, obwohl nim überhaupt kein Python ist. Pythonisten müssen dynamisches Tippen, Vererbung, Dekorateure und andere Freuden vergessen und ihr Denken im Allgemeinen neu strukturieren. Versuchen Sie nicht, Ihre Python-Erfahrung auf nim zu übertragen, da der Unterschied zu groß ist. Zuerst möchte ich wirklich heterogene Sammlungen und Mixins mit Dekorateuren. aber dann gewöhnt man sich irgendwie daran, in Not zu leben :)


Hier ist ein Beispiel für ein NIM-Programm:


  type NumberGenerator = object of Service # this service just generates some numbers NumberMessage = object of Message number: int proc run(self: NumberGenerator) = if not waitAvailable("calculator"): echo "Calculator is unavailable, shutting down" return for number in 0..<10: echo &"Sending number {number}" (ref NumberMessage)(number: number).send("calculator") 

Modularität


Alles ist in Module unterteilt, die Sie nach Belieben importieren können - um nur bestimmte Zeichen oder alle außer bestimmten oder alle oder keine zu importieren und den Benutzer zu zwingen, den vollständigen Pfad a la module.function() anzugeben und auch unter einem anderen Namen zu importieren. Natürlich ist all diese Vielfalt sehr nützlich als weiteres Argument in der Debatte " import mymodule Programmiersprache ist besser". import mymodule , in Ihrem Projekt werden Sie leise import mymodule schreiben und sich nicht an andere Optionen erinnern.


Syntax des Methodenaufrufs


Ein Funktionsaufruf kann auf verschiedene Arten aufgezeichnet werden:


  double(2) double 2 2.double() 2.double 

Einerseits schreibt jetzt jeder ... nach Belieben (und jeder mag es natürlich auf unterschiedliche Weise und sogar im Rahmen eines Projekts auf unterschiedliche Weise). Dann können aber alle Funktionen als Methodenaufruf geschrieben werden, was die Lesbarkeit erheblich verbessert. In Python kann es sein:


 list(set(some_list)) # -:   ,     map  filter     

Der gleiche Code in nim könnte logischer umgeschrieben werden:


 some_list.set.list #    

OOP


Obwohl OOP vorhanden ist, unterscheidet es sich in Pluspunkten und Python davon: Objekte und Methoden sind unterschiedliche Entitäten und können durchaus in verschiedenen Modulen vorhanden sein. Darüber hinaus können Sie Ihre Methoden für Basistypen wie int schreiben


  proc double(number: int): int = number * 2 echo $2.double() # prints "4" 

Auf der anderen Seite gibt es eine Kapselung in nim (die erste Regel des Moduls in nim ist, niemandem von Bezeichnern ohne Sternchen zu erzählen). Hier ist ein Beispiel für ein Standardmodul:


 # sharedtables.nim type SharedTable*[A, B] = object ## generic hash SharedTable data: KeyValuePairSeq[A, B] counter, dataLen: int lock: Lock 

Der Typ SharedTable* ist mit einem Sternchen gekennzeichnet. SharedTable* bedeutet, dass er in anderen Modulen "sichtbar" ist und importiert werden kann. Aber hier sind data , counter und lock private Mitglieder, und sharedtables.nim ist von außen nicht zugänglich. Dies hat mich sehr gefreut, als ich mich entschied, einige zusätzliche Funktionen für den SharedTable Typ wie len oder hasKey zu schreiben, und feststellte, dass ich weder auf counter noch auf data zugreifen konnte. Die einzige Möglichkeit, SharedTable zu "erweitern", bestand darin, Ihre zu schreiben mit bl


Im Allgemeinen wird die Vererbung viel seltener verwendet als in derselben Python (aus persönlicher Erfahrung), da es Methodenaufrufsyntax (siehe oben) und Objektvarianten (siehe unten) gibt. Der Nim-Pfad ist eher Komposition als Vererbung. Ähnlich verhält es sich mit Polymorphismus: In nim gibt es Methoden, die in Nachfolgeklassen überschrieben werden können, dies muss jedoch bei der Kompilierung mit dem --multimethods:on explizit angegeben werden. Das heißt, standardmäßig funktionieren Methoden nicht, was die Arbeit ohne sie leicht fördert.


Ausführung zur Kompilierungszeit


Const - die Fähigkeit, etwas in der Kompilierungsphase zu berechnen und in die resultierende Binärdatei zu "nähen". Es ist cool und bequem. Im Allgemeinen hat nim eine spezielle Beziehung zur "Kompilierungszeit", es gibt sogar ein when Schlüsselwort - es ist wie if , aber der Vergleich befindet sich in der Kompilierungsphase. Sie können so etwas schreiben


  when defined(SDL_VIDEO_DRIVER_WINDOWS): import windows ## oldwinapi lib elif defined(SDL_VIDEO_DRIVER_X11): import x11/x, x11/xlib ## x11 lib 

Dies ist sehr praktisch, obwohl es Einschränkungen gibt, was Sie in der Kompilierungsphase tun können (z. B. können Sie keine FFI-Aufrufe tätigen).


Referenztyp


Ref-Typ - ein Analogon von shared_ptr in C ++, um das sich der Garbage Collector kümmert. Sie können den Müllsammler aber auch selbst anrufen, wenn es für Sie günstig ist. Oder Sie können verschiedene Optionen für Garbage Collectors ausprobieren. Oder Sie können den Garbage Collector ausschalten und reguläre Zeiger verwenden.


Wenn Sie keine Rohzeiger und FFI verwenden, ist es im Idealfall unwahrscheinlich, dass Segmentierungsfehler auftreten. In der Praxis bisher nirgendwo ohne FFI.


Lambdas


Es gibt anonyme Prozeduren (auch bekannt als Lambdas in Python), aber im Gegensatz zu Python in anonymen Prozeduren können Sie mehrere Anweisungen verwenden:


 someProc(callback=proc(a: int) -> int = var b = 5*a; result = a) 

Ausnahmen


Es gibt Ausnahmen, deren raise ValueError('bad value') sehr unpraktisch ist: Python raise ValueError('bad value') , Nim raise newException(ValueError, "bad value") . Nichts Ungewöhnlicheres - versuchen Sie es, außer schließlich ist alles wie alle anderen. Ich freue mich als Befürworter von Ausnahmen, nicht von Fehlercodes. Übrigens können Sie für Funktionen angeben, welche Ausnahmen sie auslösen können, und der Compiler überprüft dies:


 proc p(what: bool) {.raises: [IOError, OSError].} = if what: raise newException(IOError, "IO") else: raise newException(OSError, "OS") 

Generika


Generika sind sehr ausdrucksstark, zum Beispiel können Sie die möglichen Typen einschränken


 proc onlyIntOrString[T: int|string](x, y: T) = discard #  int  string 

Und Sie können einen Typ im Allgemeinen als Parameter übergeben - es sieht aus wie eine gewöhnliche Funktion, aber tatsächlich eine generische:


 proc p(a: typedesc; b: a) = discard # is roughly the same as: proc p[T](a: typedesc[T]; b: T) = discard # hence this is a valid call: p(int, 4) # as parameter 'a' requires a type, but 'b' requires a value. 

Vorlagen


Vorlagen sind so etwas wie Makros in C ++, die nur korrekt erstellt wurden :) - Sie können sicher ganze Codeblöcke in Vorlagen übertragen und denken nicht, dass durch Ersetzen etwas im äußeren Code ruiniert wird (aber Sie können es wieder , um es durcheinander zu bringen, wenn Sie es wirklich brauchen).


Hier ist eine Beispiel- app Vorlage, die abhängig vom Wert der Variablen einen der Codeblöcke aufruft:


 template app*(serverCode: untyped, clientCode: untyped) = # ... case mode of client: clientCode of server: serverCode else: discard 

Mit do ich ganze Blöcke an die Vorlage übergeben, zum Beispiel:


 app do: # serverCode echo "I'm server" serverProc() do: # clientCode echo "I'm client" clientProc() 

Interaktive Shell


Wenn Sie schnell etwas testen müssen, dh die Möglichkeit, den "Interpreter" oder die "Nim-Shell" aufzurufen (als ob Sie python ohne Parameter ausführen würden). Verwenden Sie dazu den Befehl nim secret oder laden Sie das inim- Paket herunter.


Ffi


FFI - die Möglichkeit, mit Bibliotheken von Drittanbietern in C / C ++ zu interagieren. Um eine externe Bibliothek zu verwenden, müssen Sie leider einen Wrapper schreiben, der erklärt, woher und was importiert werden soll. Zum Beispiel:


 {.link: "/usr/lib/libOgreMain.so".} type ManualObjectSection* {.importcpp: "Ogre::ManualObject::ManualObjectSection", bycopy.} = object 

Es gibt Tools, die diesen Prozess halbautomatisch machen:



Was mag ich nicht


Schwierigkeit


Zu viele Dinge. Die Sprache wurde als minimalistisch konzipiert, aber jetzt ist sie sehr weit von der Wahrheit entfernt. Warum haben wir zum Beispiel eine Code-Neuordnung bekommen ?!


Redundanz


Viel Scheiße: system.addInt - "Konvertiert eine Ganzzahl in ihre Zeichenfolgendarstellung und hängt sie an das Ergebnis an". Es scheint mir, dass dies eine sehr praktische Funktion ist, die ich in jedem Projekt verwende. Hier ist eine weitere interessante: fileExists and existFile ( https://forum.nim-lang.org/t/3636 )


Keine Vereinigung


"Es gibt nur einen Weg, etwas zu tun" - überhaupt keinen:


  • Methodenaufrufsyntax - Schreiben Sie einen Funktionsaufruf nach Ihren Wünschen
  • fmt vs &
  • camelCase und underscore_notation
  • dies und das (Spoiler: es ist das gleiche)
  • Funktion vs Prozedur vs Vorlage

Bugs (keine TASCHEN!)


Es gibt Fehler, ungefähr 1400 . Oder gehen Sie einfach ins Forum - sie finden ständig einige Fehler.


Stabilität


Zusätzlich zum vorherigen Absatz impliziert v1 Stabilität, richtig? Und hier fliegt der Schöpfer der Araq-Sprache ins Forum und sagt: "Leute, ich habe hier einen anderen (sechsten) Müllsammler, es ist cooler, schneller, jünger, gibt dir gemeinsamen Speicher für Threads (ha ha, und davor hast du gelitten und." gebrauchte Krücken), laden Sie den Entwicklungszweig herunter und versuchen Sie es. " Und all diese "Wow, wie cool! Und was bedeutet das für bloße Sterbliche? Müssen wir jetzt den gesamten Code erneut ändern?" Es scheint nicht so, also aktualisiere ich nim, --gc:arc einen neuen Garbage Collector aus --gc:arc und mein Programm stürzt irgendwo beim Kompilieren von C ++ - Code ab (d. H. Nicht in nim, sondern in gcc):


 /usr/lib/nim/system.nim:274:77: error: 'union pthread_cond_t' has no member named 'abi' 274 | result = x 

Großartig! Anstatt neuen Code zu schreiben, muss ich jetzt den alten reparieren. War es nicht das, wovor ich rannte, als ich mich für nim entschied?


Schön zu wissen, dass ich nicht alleine bin


Methoden und Multithreading


Standardmäßig sind die Flags für Multimethoden und Threads deaktiviert - das werden Sie nicht 2019 2020 eine Multithread-Anwendung mit übergeordneten Methoden schreiben ?! Und wie großartig ist es, wenn Ihre Bibliothek ohne Berücksichtigung der Flows erstellt wurde und der Benutzer sie dann einschaltete ... Oh ja, es gibt wunderbare Pragmas {.inheritable.} Und {.base.} Für die Vererbung, damit Ihr Code nicht zu präzise ist.


Objektvarianten


Sie können die Vererbung vermeiden, indem Sie das sogenannte verwenden Objektvarianten:


 type CoordinateSystem = enum csCar, # Cartesian csCyl, # Cylindrical Coordinates = object case cs: CoordinateSystem: # cs is the coordinate discriminator of csCar: x: float y: float z: float of csCyl: r: float phi: float k: float 

Abhängig vom Wert von cs stehen Ihnen entweder x-, y-, z-Felder oder r, phi und k zur Verfügung.


Was sind die Nachteile?
Erstens ist der Speicher für die "größte Option" reserviert - damit er garantiert in den für das Objekt zugewiesenen Speicher passt.
Zweitens ist die Vererbung noch flexibler - Sie können jederzeit einen Nachkommen erstellen und weitere Felder hinzufügen, und in der Objektvariante werden alle Felder in einem Abschnitt starr definiert.
Drittens macht es am meisten wütend, dass Sie Felder in verschiedenen Typen nicht „wiederverwenden“ können:


 type # The 3 notations refer to the same 3-D entity, and some coordinates are shared CoordinateSystem = enum csCar, # Cartesian (x,y,z) csCyl, # Cylindrical (r,φ,z) Coordinates = object case cs: CoordinateSystem: # cs is the coordinate discriminator of csCar: x: float y: float z: float # z already defined here of csCyl: r: float phi: float z: float # fails to compile due to redefinition of z 

Notation machen


Nur um zu zitieren :


  • Mit Klammern tun ist ein anonymer Prozess
  • Ohne Klammern auskommen ist nur ein Codeblock
    Ein Ausdruck bedeutet verschiedene Dinge ¯_ (ツ) _ / ¯

Wann zu verwenden


Wir haben also Funktionen, Prozeduren, Generika, Multimethoden, Vorlagen und Makros. Wann ist es besser, eine Vorlage zu verwenden, und wann ist eine Prozedur? Vorlage oder generisch? Funktion oder Vorgehensweise? Was ist also mit Makros? Ich denke, Sie verstehen den Punkt.


Benutzerdefiniertes Pragma


Es gibt Dekoratoren in Python, die sogar auf Klassen oder Funktionen angewendet werden können.
Dafür gibt es in nim Pragmas. Und hier ist was:


  • Sie können Ihr eigenes Pragma schreiben, das die Prozedur schmückt:
     proc fib(n : int) : int {.cached.} = # do smth 
  • Sie können kein eigenes Pragma schreiben, das den Typ (= Klasse) schmückt.

Flink


Was tot ist, kann nicht sterben. In flinken, eine Reihe von Projekten, die seit langem nicht mehr aktualisiert wurden (und in nim ist es wie der Tod) - und sie werden nicht entfernt. Niemand folgt dem. Es ist klar, Abwärtskompatibilität: "Sie können das Paket nicht einfach von der Rübe nehmen und entfernen", aber trotzdem ... Okay, danke, zumindest nicht wie npm.


Undichte Abstraktion


Es gibt ein solches Gesetz der löchrigen Abstraktionen - Sie verwenden eine Art Abstraktion, aber früher oder später werden Sie ein „Loch“ darin finden, das Sie zu einer niedrigeren Ebene führt. Nim ist eine Abstraktion von C und C ++, und früher oder später werden Sie dort scheitern. Wetten, dass es dir dort nicht gefällt?


 Error: execution of an external compiler program 'g++ -c -w -w -fpermissive -pthread -I/usr/lib/nim -I/home/user/c4/systems/network -o /home/user/.cache/nim/enet_d/@m..@s..@s..@s..@s..@s..@s.nimble@spkgs@smsgpack4nim-0.3.0@smsgpack4nim.nim.cpp:6987:136: note: initializing argument 2 of 'void unpack_type__k2dhaoojunqoSwgmQ9bNNug(tyObject_MsgStreamcolonObjectType___kto5qgghQl207nm2KQZEDA*, NU&)' 6987 | N_LIB_PRIVATE N_NIMCALL(void, unpack_type__k2dhaoojunqoSwgmQ9bNNug)(tyObject_MsgStreamcolonObjectType___kto5qgghQl207nm2KQZEDA* s, NU& val) { nimfr_("unpack_type", "/home/user/.nimble/pkgs/msgpack4nim-0.3.0/msgpack4nim.nim"); | tyObject_MsgStreamcolonObjectType ___ kto5qgghQl207nm2KQZEDA * s, NU & val) {nimfr _ ( "unpack_type", "/home/user/.nimble/pkgs/msgpack4nim-0.3.0/msgpack4nim.nim"); Error: execution of an external compiler program 'g++ -c -w -w -fpermissive -pthread -I/usr/lib/nim -I/home/user/c4/systems/network -o /home/user/.cache/nim/enet_d/@m..@s..@s..@s..@s..@s..@s.nimble@spkgs@smsgpack4nim-0.3.0@smsgpack4nim.nim.cpp:6987:136: note: initializing argument 2 of 'void unpack_type__k2dhaoojunqoSwgmQ9bNNug(tyObject_MsgStreamcolonObjectType___kto5qgghQl207nm2KQZEDA*, NU&)' 6987 | N_LIB_PRIVATE N_NIMCALL(void, unpack_type__k2dhaoojunqoSwgmQ9bNNug)(tyObject_MsgStreamcolonObjectType___kto5qgghQl207nm2KQZEDA* s, NU& val) { nimfr_("unpack_type", "/home/user/.nimble/pkgs/msgpack4nim-0.3.0/msgpack4nim.nim"); | 

 /usr/bin/ld: /home/user/.cache/nim/enet_d/stdlib_dollars.nim.cpp.o: in function `dollar___uR9bMx2FZlD8AoPom9cVY9ctA(tyObject_ConnectMessage__e5GUVMJGtJeVjEZUTYbwnA*)': stdlib_dollars.nim.cpp:(.text+0x229): undefined reference to `resizeString(NimStringDesc*, long)' /usr/bin/ld: stdlib_dollars.nim.cpp:(.text+0x267): undefined reference to `resizeString(NimStringDesc*, long)' /usr/bin/ld: stdlib_dollars.nim.cpp:(.text+0x2a2): undefined reference to `resizeString(NimStringDesc*, long)' 

Also


Ich bin ein dummer Programmierer. Ich möchte nicht wissen, wie der GC funktioniert, was da ist und wie er verknüpft ist, wo er zwischengespeichert wird und wie Müll entfernt wird. Es ist wie bei einem Auto - im Prinzip weiß ich, wie es funktioniert, ein bisschen über die Achsvermessung, ein bisschen über das Getriebe, ich muss das Öl und das Zeug einfüllen, aber im Allgemeinen möchte ich mich nur hinsetzen und (und schnell) zur Party gehen. Eine Maschine ist kein Ziel, sondern ein Mittel zum Zweck. Wenn es kaputt geht, möchte ich nicht in die Motorhaube steigen, sondern es einfach zum Service bringen (in dem Sinne, dass ich das Problem auf dem Github öffne), und es wäre großartig, wenn sie es schnell beheben würden.


Nim sollte eine solche Maschine sein. Zum Teil wurde er, aber gleichzeitig, wenn ich mit diesem Auto die Autobahn entlang rase, fällt mein Rad ab und der Rückspiegel zeigt nach vorne. Ingenieure rennen hinter mir her und befestigen etwas im laufenden Betrieb ("jetzt ist Ihr Auto mit diesem neuen Spoiler noch schneller"), aber davon fällt der Kofferraum ab. Und weißt du was? Ich mag dieses Auto immer noch verdammt, weil dies das beste aller Autos ist, die ich gesehen habe.

Source: https://habr.com/ru/post/de462577/


All Articles