Ich bin auf dieses Nuget gestoßen, weil ich WPF-UI-Anwendungen geschrieben habe und einen Folder-Picker brauchte. Irgendwer im Internet schlug vor, die WinForms-Dialoge zu verwenden. Ich hasse es irgendwie, zwei Frameworks zu verwenden. Und dann brachte jemand anderes das Nuget WindowsAPICodePack.Shell ins Spiel, mit seinen Klassen der Windows Common Dialogs, einschließlich der Möglichkeit zur Auswahl von Ordnern im File-Öffnen-Dialogfenster.

Also fing ich an, das Nuget zu benutzen. Irgendwann wies mich ein Freund darauf hin, dass das Nuget-Paket gar nicht wie ein offizielles Microsoft-Paket aussah, sondern wie ein Repackage, das irgendjemand gemacht hatte. Das brachte mich zum Nachdenken. Ich unterstelle niemandem böse Absichten, aber ich fand es sehr, sehr seltsam. Das offizielle Paket war . Und es gibt eine ganze Reihe von Paketen mit seltsamen Namen:

Ich mag das nicht. Selbst wenn keiner der Autoren böse Absichten hegt, gefällt mir das nicht, denn es riecht nach Betrug, Phishing und Schwachstellen. Tut mir leid, aber nein.

Also, wo ist das offizielle Paket? Es scheint verschwunden zu sein, deshalb gibt es die Repackages von Community-Mitgliedern. Warum ist es verschwunden? Keine Ahnung. Vielleicht wurde es bei einer halbautomatischen Bereinigung erwischt, da es verwaist war. Jemand behauptet es wäre Microsoft.Windows.SDK.Contracts ersetzt worden.

Letztendlich habe ich den Code in meinen Projekten ersetzt, indem ich entweder doch den WinForms-Dialog verwendet oder eine sehr kleine P/Invoke-Wrapper-Klasse geschrieben habe, die die Win32-API-Funktion direkt aufruft. Wen es interessiert, der kann sie sich gerne anschauen:

https://github.com/sgrottel/open-here/commit/9de68198e35f0f6dec9386372cc71bada54c2f5b

Die Moral von der Geschichte ist, dass ein Nuget-Paket nur so gut ist wie die Menschen, die es pflegen. Und ich meine Menschen, nicht Organisationen. Denn am Ende kommt es darauf an, ob eine einzelne Person dahinter steht und ihr Bestes geben will oder nicht.

[This article is only available in English. Sorry.]

Git has this cursed function to fuck up your files by doing unspeakable things to your line endings.

For example, from Githubs Documentation on Line Endings:

On Windows, you simply pass true to the configuration. For example:

$ git config –global core.autocrlf true

Please, never never never never never never never never never never never never do this!

THERE IS NO REASON TO DO IT!

Git is here to keep track of our files, NOT TO CHANGE OUR FILES IN ANY WAY.

So, please, just, never never never never never never never never never never never never do this! Leave my file endings alone!

Heute habe ich eine neue Version meines Checkouts-Overview-Tools veröffentlicht.

Version 1.1 bringt neue Funktionen, Verbesserung des Scannens der Festplatten zum Finden neuer Repository-Checkouts und die Möglichkeit beim Update von Entry-Status-Informationen auch ein git fetch durchzuführen.

Ein paar kleinere Verbesserungen der Benutzeroberfläche erzeugen ein konsistenteres Aussehen.

Ladet den neue Release von Github herunter: Release Feature Release v1.1 – Better Disk Scanning and Git Fetch · sgrottel/checkouts-overview (github.com)

Heute stelle ich euch das Tool Checkouts Overview vor.

https://github.com/sgrottel/checkouts-overview
https://go.grottel.net/checkouts-overview

Was? Warum? Weil mir dieses kleine Tool hilft.

In meinem privaten Setup habe ich eine Menge kleinerer Repos ausgecheckt, mit denen ich nur hin und wieder arbeite. Außerdem habe ich mehrere Repos, die einige Textdokumente und deren Historie verwalten. Manche dieser Repos werden mit Servern synchronisiert, die nur gelegentlich online sind, teils um Strom zu sparen, teils aufgrund von VPN- und Netzwerkverbindungsgeschichten. Und so verliere ich oft den Überblick über den Status der Synchronisierung dieser verschiedenen Repos.

Ist alles eingecheckt? — Meistens, ja. Wenn meine Änderungen schon vollständig war.

Ist alles gepusht? — vielleicht.

Sind Branches aktiv? — keine Ahnung.

Ihr braucht diese Anwendung vielleicht nicht, wenn Ihr einen besser strukturierten Arbeitsablauf habt als ich. Meiner ist chaotisch, also brauche ich die Hilfe eines Tools, dieses Tools.

Wenn Ihr interessiert seid, findet Ihr weitere Informationen im Github-Repository der App.

Hinweis: Und was das Icon der App angeht, es geht um (Repository-)Klone, richtig.

[:en]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);

[:]

[:de]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.[:en]Some while ago, two of my colleagues were putting effort into our main code base and build system, to migrate to Visual Studio 2017, and the C++17 standard. Admirable and sensible. Of course, that was reason enough for another colleague of mine and myself to joke around about downgrading our code base to C++03 or C++98 or maybe even downright to C. Don’t worry, we all four were laughing. (Or were we?)

At that time, my joke-buddy pointed me to a blog post by aras-p about Modern C++ Lamentations. Read it! It’s worth it. And don’t go, “that’s maybe in gaming industry. Doesn’t apply to my work.” Well, I am not working in gaming industry. You know what: It does apply to my work pretty much 100%.

In my opinion, “modern” C++ is too complex, too bloated, too much of a poser for “look I can do cool code”, and misses the point of solving problems.

[…] 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”.

Many language features are valid, other as just “cool.” Now, of course, I understand, that different people will find different parts of the language good. There are some aspects, however, which are objectively bad. Look at compile times and debug times mentioned in this article. At least those make a very valid point.

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.

I have been a hobby programmer in school; was a part time programmer while being a student of software engineering; made my Ph.D. in computer science on computer graphics and visualization, while writing a large-scale modular, high-performance visualization software; worked as senior software developer in a company; and I am now manager of a team of software engineers. I think it is valid to say, I have been programming almost my whole life. I still try to do some minor improvements or bug fixes, even as a manager. Most likely me team is thinking I should stop messing in “their code.” I won’t. My point is:

I have been programming almost my whole life. And I did it in more than a dozen different programming languages. (While writing this I counted 15, not including scripting languages. But most likely I forgot some.) Given this experience, let me say this:

C++ is not the best programming language. In modern C++ not everything has improved.

Please! Start (again) thinking “How do I solve this problem,” and not “How do I solve this problem with variadic templates wrapped in lambdas with ranges because they are so cool.”

While I was lecturing at the university on C++ for computer graphics, clear as daylight, you can see the different types of uprising programmers. And there is this specific sub-type of “programming artists.” Programmers, who think their source code is art and above and beyond trivial programs others do. I will not comment on those any further. But I noticed, in the field where C++ is used, especially so-called modern C++, those guys are seen pretty often! Sad.

As a closing note: Nowadays, when I start a project and think about which programming language(s) to use, C++ is not on the top of the list anymore.[:]