Ich habe meine „Weisheit“, so nenne ich es gerne, aus vielen verschiedenen Quellen: Familie, Freunde, Filme, … Ich bezeichne es oft auch als „nutzloses Wissen“. Damit kann ich auch leben. Und am interessantesten wird es, wenn es um Dinge geht, die nicht (vollständig) unter unserer Kontrolle liegen. Meinungen werden dann mehr und mehr zu Reflexionen davon, wie wir diese Dinge sehen, und nicht, wie sie sind. Nun, Meinungen sind immer so, aber in diesen Fällen wird dies immer schön deutlicher. Nehmen wir zum Beispiel unsere Jobs, wir lieben sie, wir hassen sie, wir brauchen sie. Wenn ich das Ganze aus der akademischen Perspektive betrachte, dann denke ich zuerst an eine Skala (basierend auf meiner nutzlosen Weisheit):

Das obere Ende ist für mich durch ein Zitat von Konfuzius definiert. Tatsächlich habe ich es das letzte Mal gehört, als meine Schwester es mir von Kermit dem Frosch auf Instagram vorgelesen hat.

„Wähle einen Job, den du liebst, und du wirst nie einen Tag in deinem Leben arbeiten müssen.“

Und für das untere Ende, das gar nicht so negativ ist, habe ich ein Zitat aus „Der Teufel trägt Prada“ gewählt:

„Jobs, die die Miete zahlen.“

Nun, das ist nicht Konfuzius, aber es trifft sicherlich was wir oft fühlen.

Offensichtlich ist es eine offene Skala von 1 – Liebe bis 0 – Miete, und darüber hinaus an beiden Enden. Und, es gibt sicherlich so etwas wie „Das war’s. Hier ist meine Kündigung. Fickt euch alle.“, aber ich hoffe ehrlich, dass dieser Wert nicht sehr oft gebraucht wird. Setzen wir den mal auf -1.

So, da habt ihr’s. Eine schöne Skala zwischen Liebe und Hass zu unsere Jobs.

Wenn Sie einen dieser Tage haben, an dem Sie sich nahe an der Null oder sogar im negativen Bereich fühlen, dann versuchen Sie sich an einen früheren Tag zu erinnern, an dem Sie nahe an der Eins waren. Haben Sie es? Bleiben Sie dran. Ihr Ziel für die Arbeit ist es, dass diese Tage zählen! Und mehr von diesen Tagen zu haben als von den anderen. Und, für die anderen Tage, vergessen Sie auch Ihr Leben außerhalb Ihres Jobs nicht!

Einer der Besten von Xkcd aller Zeiten:

Fortunately, the charging one has been solved now that we’ve all standardized on mini-USB. Or is it micro-USB? Shit.

Irgendwie konnte ich GetOpt noch nie leiden. GFlags überzeugt mich in einigen Aspekten auch nicht. Ist aber besser als selber irgendeinen CmdLine-Parser zusammenzustecken.

Ich habe mich bei dem Nuget-Paket auf die statische, thread-sicher Library beschränkt. Wenn ihr eine andere Variante braucht, dann könnt ihr natürlich gerne die AppVeyor-Artefakte herunterladen. Da sind praktisch alle dabei.

Wie üblich, Paket-Code ist frei: https://bitbucket.org/sgrottel_nuget/gflags_nuget

Die Community für native Libraries in Nugets scheint mir nicht sonderlich aktiv. Ich vermute die meisten Leute benutzen cmake, und müssen daher irgendeine zusätzliche Methode für die Paketverwaltung auf ihren Betriebssystemen nutzen, oder so. Wasweisich. Ich mag Nuget. Daher, ohne große Umschweife: hier ist mein neues Nuget-Paket für die LibYAML.

Und, wie üblich, der Paket-Code ist frei verfügbar: https://bitbucket.org/sgrottel_nuget/libyaml-nuget

Dieser Artikel is nur auf Englisch verfügbar.

Yes, I am still using AntTweakBar. As you might know, the development of AntTweakBar is discontinued. At some point in the future, I will switch. Currently, I consider imgui the best successor. But I haven’t had time to look into imgui. So, when I resurrected an old small tool of mine, it still used ATB, and I did not want to recode all of this. But out of „because-I-can,“ I decided  to update all dependencies to their newest versions. As a result the ATB integration with GLFW 3 did not work any longer. A couple of callback functions where changed between GLFW 2 and GLFW 3. I ended up rewriting my glue code between those two libraries.

Here it is, if any of you ever come across the same issue. First the callbacks:

static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
{
#ifdef HAS_ANTTWEAK_BAR
  if (action == GLFW_PRESS || action == GLFW_REPEAT)
  {
    int twMod = 0;
    bool ctrl;
    if (mods & GLFW_MOD_SHIFT) twMod |= TW_KMOD_SHIFT;
    if (ctrl = (mods & GLFW_MOD_CONTROL)) twMod |= TW_KMOD_CTRL;
    if (mods & GLFW_MOD_ALT) twMod |= TW_KMOD_ALT;

    int twKey = 0;
    switch (key)
    {
    case GLFW_KEY_BACKSPACE: twKey = TW_KEY_BACKSPACE; break;
    case GLFW_KEY_TAB: twKey = TW_KEY_TAB; break;
    //case GLFW_KEY_???: twKey = TW_KEY_CLEAR; break;
    case GLFW_KEY_ENTER: twKey = TW_KEY_RETURN; break;
    case GLFW_KEY_PAUSE: twKey = TW_KEY_PAUSE; break;
    case GLFW_KEY_ESCAPE: twKey = TW_KEY_ESCAPE; break;
    case GLFW_KEY_SPACE: twKey = TW_KEY_SPACE; break;
    case GLFW_KEY_DELETE: twKey = TW_KEY_DELETE; break;
    case GLFW_KEY_UP: twKey = TW_KEY_UP; break;
    case GLFW_KEY_DOWN: twKey = TW_KEY_DOWN; break;
    case GLFW_KEY_RIGHT: twKey = TW_KEY_RIGHT; break;
    case GLFW_KEY_LEFT: twKey = TW_KEY_LEFT; break;
    case GLFW_KEY_INSERT: twKey = TW_KEY_INSERT; break;
    case GLFW_KEY_HOME: twKey = TW_KEY_HOME; break;
    case GLFW_KEY_END: twKey = TW_KEY_END; break;
    case GLFW_KEY_PAGE_UP: twKey = TW_KEY_PAGE_UP; break;
    case GLFW_KEY_PAGE_DOWN: twKey = TW_KEY_PAGE_DOWN; break;
    case GLFW_KEY_F1: twKey = TW_KEY_F1; break;
    case GLFW_KEY_F2: twKey = TW_KEY_F2; break;
    case GLFW_KEY_F3: twKey = TW_KEY_F3; break;
    case GLFW_KEY_F4: twKey = TW_KEY_F4; break;
    case GLFW_KEY_F5: twKey = TW_KEY_F5; break;
    case GLFW_KEY_F6: twKey = TW_KEY_F6; break;
    case GLFW_KEY_F7: twKey = TW_KEY_F7; break;
    case GLFW_KEY_F8: twKey = TW_KEY_F8; break;
    case GLFW_KEY_F9: twKey = TW_KEY_F9; break;
    case GLFW_KEY_F10: twKey = TW_KEY_F10; break;
    case GLFW_KEY_F11: twKey = TW_KEY_F11; break;
    case GLFW_KEY_F12: twKey = TW_KEY_F12; break;
    case GLFW_KEY_F13: twKey = TW_KEY_F13; break;
    case GLFW_KEY_F14: twKey = TW_KEY_F14; break;
    case GLFW_KEY_F15: twKey = TW_KEY_F15; break;
    }
    if (twKey == 0 && ctrl && key < 128)
    {
      twKey = key;
    }
    if (twKey != 0)
    {
      if (::TwKeyPressed(twKey, twMod)) return;
    }
  }
#endif
}

static void charCallback(GLFWwindow* window, unsigned int key)
{
#ifdef HAS_ANTTWEAK_BAR
  if (::TwKeyPressed(key, 0)) return;
#endif
}

static void mousebuttonCallback(GLFWwindow* window, int button, int action, int mods)
{
#ifdef HAS_ANTTWEAK_BAR
  if (::TwEventMouseButtonGLFW(button, action)) return;
#endif
}

static void mousePosCallback(GLFWwindow* window, double xpos, double ypos)
{
#ifdef HAS_ANTTWEAK_BAR
  if (::TwEventMousePosGLFW((int)xpos, (int)ypos)) return;
#endif
}

static void mouseScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
#ifdef HAS_ANTTWEAK_BAR
  static double pos = 0;
  pos += yoffset;
  if (::TwEventMouseWheelGLFW((int)pos)) return;
#endif
}

static void resizeCallback(GLFWwindow* window, int width, int height)
{
#ifdef HAS_ANTTWEAK_BAR
  ::TwWindowSize(width, height);
#endif
}

Of course, you can omit the #ifdefs if you don’t care. Add your own codes to the functions after ATB has been handled.

Then, it’s just your typical initialization of GLFW callbacks:

::glfwSetKeyCallback(window, keyCallback);
::glfwSetCharCallback(window, charCallback);
::glfwSetMouseButtonCallback(window, mousebuttonCallback);
::glfwSetCursorPosCallback(window, mousePosCallback);
::glfwSetScrollCallback(window, mouseScrollCallback);
::glfwSetWindowSizeCallback(window, resizeCallback);

Even the powerful, tart Granny Smith cultivar is proving ineffective against new Gran-negative doctors.

Ja, albern. Aber ich hab so gelacht. Tatsächlich, während ich diesen Post hier schreibe und den Strip wieder lesen … ich kicher die ganze Zeit. Bescheuert. Und gleichzeitig vielleicht eine der bösesten Satiere seit langem.

Vor einiger Zeit haben zwei Kollegen etwas Zeit und Aufwand investiert um unsere Haupt-Code-Base und unsere Build-Chain auf Visual Studio 2017 und den C++17-Standard zu haben. Eine sinnvolle Aktion. Aber natürlich war das auch Grund genug, dass ein anderer Kollege und ich dann rumgewitzelt haben, dass wir unseren Code downgraden sollten, auf C++03, C++98, oder vielleicht sogar direkt auf C. Keine sorge, wir haben alle vier gut gelacht. Oder?

Zu der Zeit hat mich der Rumwitzel-Kollege auf einen Artikel von aras-p über „Modern C++ Lamentations“ aufmerksam gemacht. Lesen! Der ist gut. Und denkt nicht „das ist vielleicht in der Computerspieleindustrie so, trifft aber für mich nicht zu.“ Ich arbeite nicht in der Computerspieleindustrie, und auf meine Arbeit trifft das ganze Zeug ziemlich 100%ig zu.

Meiner Meinung nach ist  „modernes“ C++ zu komplex, zu aufgeblasen, zu angeberisch: „schaut her wie cool mein code ist“. Hier wird ganz das Ziel verfehlt, nämlich Probleme zu lösen.

[…] to me this feels like someone decided that “Perl is clearly too readable, but Brainfuck is too unreadable, let’s aim for somewhere in the middle”.

Viele neue Sprach-Features sind sinnvoll, andere sind vielleicht nur „cool“. Natürlich sieht das jeder anders und findet andere Aspekte sinnvoll. Es gibt aber Dinge die objektiv gesehen schlecht sind. Der Artikel von aras-p zeigt hier schön die Probleme von Compile Time und Debug Performance. Das sind berechtigte Gründe.

C++ compilation times have been a source of pain in every non-trivial-size codebase I’ve worked on. […] Yet it feels like the C++ community at large pretends that is not an issue, with each revision of the language putting even more stuff into header files, and even more stuff into templated code that has to live in header files.

In der Schule war ich Hobby-Programmierer; dann Student in Software Engineering und Teilzeit-Programmierer nebenher; dann habe ich meinen Doktortitel in Informatik gemacht, Schwerpunkt in Computergraphik und Visualisierung, und habe parallel eine großes modulare, high-performance Visualisierungssoftware geschrieben; dann war ich Senior Software Engineer in einer Firma mit einer recht großen Software; und jetzt bin ich Manager eines Teams von Software-Entwicklern. Ich denke ich kann sagen, ich hab die meiste Zeit meines Lebens programmiert. Ich mach immer noch Kleinigkeiten und kleine Bug fixes in unserem Code, selbst als Manager. Vermutlich denk sich mein Team, ich soll endlich die Finger von „ihrem Code“ lassen. Werde ich nicht. Aber, was ich sagen will:

Ich bin praktisch mein ganzes Leben schon Programmierer. Und dabei habe ich in weiter über einem Duzend verschiedener Sprachen gearbeitet (während dem Schreiben dieses Artikels kam ich auf 15, ohne Script-Sprachen. Aber wahrscheinlich hab ich auch welche vergessen.) Mit dieser Erfahrung nehme ich mir heraus zu sagen:

C++ ist nicht die beste Programmiersprache. Modernes C++ hat nicht alles besser gemacht.

Bitte! Fangt (wieder) an euch zu fragen „wie löse ich dieses Problem“, anstatt „wie löse ich dieses Problem mit variadic Templates in Lambdas mit Ranges, weil das alles so cool ist“.

Als ich an der Universität meine Vorlesung zu „C++ für Computergraphik“ gehalten habe, da konnte man die ganzen unterschiedlichen Typen der heranwachsenden Programmierer klar und deutlich sehen. Und das gibt es diese eine besondere Teilspezies der „Programmierkünstler“. Programmierer die ihren Code für Kunst halten, und über all diese gewöhnlichen Programme erhaben. Das werde ich jetzt erstmal nicht weiter kommentieren. Aber ich glaube festgestellt zu haben, dass diese Typen in Umgebungen wo C++ eingesetzt wird sehr häufig anzutreffen sind. Leider.

Als Abschlussbemerkung: Wenn ich heute ein neues Programmierprojekt starte, und ich darüber nach denke welche Programmiersprache(n) ich dafür einsetze, dann ist C++ nicht mehr oben auf der Liste.