Showing posts with label software engineering. Show all posts
Showing posts with label software engineering. Show all posts

Wednesday, 9 November 2022

Why Qt containers? And do we ❤️ them?

I have read the following post titled  "I ❤️ Qt containers! :)" on the Qt Development mailing list and found it extremely interesting. It is written by Volker Hilsheimer, the current chief maintainer of the Qt project, and elaborates on some design principles Qt libraries are using. The post was was written as a response to more general question of why isn't Qt switching to standard C++ library containers.

I hope nobody gets offended that I repost it here - I do it because not everyone can read the archives. I'd also like to be able to find it for myself in case I'd like to ponder on Qt containers and their design.

So happy reading (emphasizings and formattings are all mine):

" .... Historically, STL implementations were unusable and unreliable for cross platform development (we supported HP-UX, AIX, SGI, Sun back in those days), and generally incomplete (only a few associative containers pre-C++11). So, 30 or 20 years ago, or perhaps up to C++11 and until we could drop commercial Unix systems as irrelevant (esp for Nokia’s plans; although no idea about the quality of the STL for Symbian C++), the STL wasn’t really much of an option.

However, this is a more fundamental question about what we try to achieve with Qt. Qt has never tried to be a C++ library that follows the design principals of the std library. In many cases, we don’t even care that much about the single responsibility principle (hello, QWidget). Qt container classes have always been more than a dumb storage of data on top of which algorithms operate. QString is a very rich class with tons of functionality, specific to text handling. std::string is a sequence of characters. Working with QString vs std::string to deal with user-provided text input requires rather completely different mindsets.

Our core competence of designing intuitive APIs does not exclude container classes. That’s why with Qt containers, we can write
if (list.contains(value)) {
    // ...
}
rather than
if (std::find(list.begin(), list.end(), value) != list.end()) {
    // ...
}
Perhaps it makes me an inferior C++ developer, but I rather prefer the former. Well, std::map got a contains(), and std::string a starts_with() in C++ 20, only 25 years late(r).

Indeed, sometimes that convenience means that our users, and we ourselves, can do something silly like:
if (map.contains(key)) {
    value = map.value(key);
    // do stuff with value
}
Convenience is no excuse for us as developers of Qt to be sloppy. It is also no excuse for ignoring the new features we get into our toolbox when we move to C++ 20 or 23. But that C++ 20 finally introduces std::map::contains (but not std::vector::contains…), or adds std::span, is also no excuse for us to toss our own designs out of the window, and to demand that all Qt users must embrace the STL instead.

One of Qt’s goals has always been to make C++ accessible for people that come from other languages, with a programming model that is not rooted in how the C++ standard library does things. That programming language used to be Java - hence our Java-style iterators in Qt containers. Today, people perhaps rather learn programming with Python in school. There will always be more people that have learned programming with other languages, than those that have carefully studied the C++ standard and the impact of various constructs in Compiler Explorer. We must make it easy for the former, while also enabling the latter.

And there are the practical reasons why I don’t want to replace QList with std::vector and QHash with std::unordered_map: we store our data structures in the d-pointer, and we want to stay flexbile wrt the actual stored type. So copy-elision and return-value-optimization don't buy us much: we need to return copies of containers from our property getters. Not const references to containers, and not temporary lists that can be moved out. So we do need reference counting.

For the here and now, and the last 25 years of Qt and C++, it’s not helpful to argue that we will soon be able to return a type-erased span and get rid of “horrible and inefficient” APIs returning owning containers. std::span is a new tool, opening up new opportunities; the expressiveness of e.g. C++ ranges might even make it much easier for someone coming from e.g. Python to use Qt, while allowing us to write much more efficient code. So we do need to consider how we name and design our APIs today so that we can add new APIs to unlock that power in the future. And we need to keep looking for ways to improve what we have - with extra awareness of what potential changes mean for our users and co-contributors.

Those improvements cannot require that we force everyone to change significant amounts of existing code, all the time; or that they have to regularly unlearn established Qt patterns; or that they have to live without the convenience. Yes, I’m biased, but I honestly don’t see any universe where a Qt without our implicitly shared, owning, old-fashioned containers, and instead with only STL containers and programming paradigms, would have been as easy, or as much fun, to use.

Volker
" 
Summing up

As it was already said elsewhere, "Qt is known  for making C++ easy and accessible"! You might say it's C++ for the people.  Maybe it's for that reason that C++ didn't go the way of Haskell despite Commitee's best efforts? ๐Ÿ˜


A screenshot (I forgot from which presentation...)

PS: I didn't remove anything from the original post for the sake of completeness


Friday, 31 December 2021

Beauty in Software Design (and Programming)


Recently I repeatedly heard the phrases "beautiful"/"not beautiful" used to describe and grade a software design, a bugfix or a piece of existing code. 

Personally, I didn't like it at all, as it seemed somehow simplistic, but I told to myself: be humble, don't judge, think before you speak... But then, out of the blue, I realized what disturbed me in that phrase! Let me present my argument.


Why didn't I like the "beauty" argument? Because it's too easy, too general and too unspecific.

Software design, as an engineering effort, is an exercise in finding a right tradeoff between different vectors: performance and code readability, code quality and release deadlines, programming effort and importance of a feature, etc.

When we just fall back to the "beauty" criterion we are just ignoring the more complex reality behind our code. I'd even go as far and venture to say that it is the sign of an immature engineer.  

Let me cite from a blog post*:
"- Mature engineers make their trade-offs explicit when making judgements and decisions."
Let me state it again - we are not looking for beauty when programming, we are trying to survive in a world full of trade-offs. And a mature engineer won't try to ignore that and lock himself up in an ivory tower. Let me cite from a blog post again*:
"The tl;dr on trade-offs is that everyone cuts corners, in every project. Immature engineers discover them in hindsight, disgusted. Mature engineers spell them out at the onset of a project, accept them and recognize them as part of good engineering."
Mammoths?

Have you seen the mammoths? They weren't beautiful**, not by any means! But they were optimally adapted to thrive in their habitat!


Here is one - should we reject him in a code review because of his ugliness?

Mathematics?

What about beauty in mathematics***? Isn't programming "mathematics done with other means"

Isn't there the old adage among mathematicians that "if it's not beautiful, than it's probably wrong"? And des it apply to programming (via the argument that programming is "mathematics done with other means")? 

Well, my response to that is: mathematics is pure, in the sense that it doesn't have to make any trade-offs. 

Besides, I can't see much beauty in modern advanced mathematic like, for example, in proof of Fermat's theorem. Rather than that, it's just complicated and tedious. Looks like the low hanging fruit in mathematics has been already picked... 

Update

A recent tweet expresses much the same sentiment:
--

** as a classic polish rock songtext stated (credits where credit is due!)

*** "there is some cold beauty in mathematics..." as Bertrand Russel said


My talk about the Emma architectural pattern


When working for one of my clients I learned about Emma (or rather EMMA :-) pattern and it got me quite intrigued. As far as I know, it's never been published anywhere, and frankly, there aren't many publications about embedded systems architecture anyway.

In the meanwhile, Burkhard Stuber from Embedded Use gave a talk about Hexagonal Architecture* pattern and argued in his newsletter that:
"In my talk at Meeting Embedded 2021, I argue that the Hexagonal Architecture should be the standard architecture for UI applications on embedded devices. As software and system architects we should never have to justify why we use the Hexagonal Architecture. In contrast, the people, who don't want to use Hexagonal Architecture, should justify their opinion." 
However, at the time of this talk, these ideas werent yet communicated, but at the moment I still think that even for UI-based applications on embedded devices EMMA could also be an option!

The EMMA architecture was successfully used in embedded devices at my client's, it follows an interesting idea and it wasn't published outside of the company before. So I secured an OK from my client and presented it for the general public!

The Talk

As they gave me permission to blog and speak about it, I gave a presentation on EMMA at the emBO++ 2021** conference:
The general TOC of the talk looks like this:
  • General intro about architecture patterns 
    - and also about embedded software architectures

  • Motivations and trade-offs
    - the motivation for an the trade-offs taken in the EMMA pattern

  • Overview of EMMA 
     - its layers, the various conventions it imposes on developers, the standard project structure
     - the basic control flow
     - the startup phase

  • Use Case 1
    - Bootloader on a Device Control MCU

  • Use Case 2
    - Target Tests for a Device

  • Use Case 3
    - Qt GUI on Yocto Linux and iMX-6

EMMA Architecture

And here it is, the short, non-formal description of Emma architecture pattern.

The name of the pattern is an acronym of:
  • – event-driven (asynchronous events for communication)
  • – multi-layered (layering to organize the )
  • – multi-threaded (i.e. threading has to follow guidelines)
  • – autonomous (i.e. minimal interfaces)
The motivation of the pattern is to avoid designs like this:


which, unfortunately, tend to spring to life in many programming projects!

The inspiration for the pattern comes from the ISO's seven layer model of a networking stack:


We can clearly see, that there are analogies between networking stack decomposition and embedded architecture layers! This is what got me interesten in first pplace

When to use EMMA? The original design argues that it is good for: 
  • Low-power 8-bit MCUs
  • Cortex M0-M4 class, 32-bit MCUs (e.g. STM32F4xx), RTOS, C
But in a recent project we also used it for:
  • Cortex A class, Linux, C++, Qt, UI
I'd say that it can be naturally extended to UI-driven embedded devices, where the A7 (Application) layer isn't a message loop but a Qt-based UI!

Thus it can be seen as an alternative to Hexagonal Architecture*, offering the one benefit, that it follows the more widely known Layered Architecture pattern!

---

  

** emBO++ 2021 | the embedded c++ conference in Bochum, 25.-27.03.2021

Saturday, 26 September 2020

Lippincott Pattern


1. Intro

In one of my recent C++ projects I spotted some giant macro named HANDLE_ALL_EXCEPTIONS() (or so), immediately noted how ugly it was and that a better solution to that problem exists. 

My coworkers at the then-customer were nice and open minded people so they didn't bridle at that, on the contrary, they were eager to change it and asked for advice. I simply said that they should google for the "Lippincot Pattern" and thought the matter were settled.

To my surprise my buddy returned reporting that there's nothing like that on the Internets! As to remedy that sore state of affairs I decided to make a short write-up of that really cool technique.

2. On Naming

An astute reader might have noticed that the whole problem is an artificial one: there is some (admittedly still too little!) information on the "Lippincot function" out there*. And Jason Turner (aka @lefticus) made an entire episode of C++ Weekly about it. So why I'm insisting on a different name?

Well, to be honest, it's mainly because I learned it by this name! Sadly, I cannot find any article on the web, so I cannot present you with any proof, but I assure it that it is true. Has anybody besides me heard of this technique under the name Lippincott Pattern instead of Lippincott Function? Please leave a comment if you did, I'm really curious about it!

But besides of my inability to change my habits there indeed is a genuine argument for that name. I mean, it is a known technique solving a common programming problem and that's the definition of a programming pattern if I'm not mistaken! And it's of no importance if we are using a function or a set of classes to solve the problem.

And of course, it sounds much better, and, without a doubt this, counts as a third reason. ๐Ÿ™‚

As we are in a section called "On Naming" you might ask why this technique is called Lippincott function/pattern? Elementary, Dear Watson - it's beacuse it was invented by Lisa Lippincott, a well-known programmer and (as of recent) a C++ committee member with a faible for maths:
3. The Pattern

But enough of the idle banter, and ad rem! I maybe should have mentioned that this technique is also sometimes called "Exception Dispatcher". Now you probably can already imagine how it works.
   try
   {
      throw;  
   }
   catch (const MyNetworkException& ex)
   {
      MY_LOG_ERROR(tags::Networking, QString("Exception occurred: ") + ex.what());
   }
   catch (const std::exception & ex)
   {
      MY_LOG_ERROR(tags::Networking, QString("Unexpected exception occurred: ") + ex.what());
   }
   catch (...)
   {
      MY_LOG_ERROR(tags::Networking, "Unknown exception occurred.");
   }
As you see, we rethrow the current exception (notice that we assume we are in an exception handler!!!) and can write reusable exception handling logic without macros! We use it simply like this:
   try
   {
      a_function_that_may_throw();  
   }
   catch (...)
   {
      traceException(); // Lippincott!
   }
   
Here we just log the error and do nothing, but we could as well translate exceptions in error codes, as it is shown in the already mentioned blogpost*, and then use it like this;
   try
   {
      a_function_that_may_throw();  
   }
   catch (...)
   {
      return translateExceptionToErrno(); // Lippincott!
   }
However, that's not all - we can also here more complex logic. Let us have a look at this exception handler function from my recent HTTP project**:
  int CasablancaRestClient::handleException() const
  {
    QString errText;
    int errorCode;

    try
    {
      throw; // Lippincott pattern 
    }
    catch (const web::http::http_exception& e) 
    {
      // probably TCP conn. error!
      //  - notify conn. status change, trigger HTTP fallback if needed
      return HandleHttpError(e);
    }
    catch (const web::uri_exception& e)
    {
      QWriteLocker guard(&_serverAliveLock);

      if (!_serverAlive)
      {
        // probalbly server's URL not yet set
        errorCode = EC_NO_CONNECTION;
      }
      else
      {
        errText = tr("Internal error, bad URL: %1.").arg(e.what());
        errorCode = EC_BAD_URL;
      }
    }
    catch (const web::json::json_exception& e)
    {
      errText = tr("Internal error, bad JSON data: %1.").arg(e.what());
      errorCode = EC_JSON_FORMAT;
    }
    catch (const std::exception& e)
    {
      errText = tr("Internal error, reason: %1.").arg(e.what());
      errorCode = EC_INTERNAL;
    }
    catch (...)
    {
      errText = tr("Internal error in CCasablancaRestClientComp!!!!");
      errorCode = EC_INTERNAL;
    }

    WIN_DEBUG_CLIENT_ERR(errText.ToStdString());

    // send the error to GUI context
    emit connectionErrorMessage(errText);
  
    return errorCode;
  }
We see, we are just doing the basic translation from exception types to error codes, but also initiate a reconnection or fallback to a non-secure connection in some cases!

I was using it in following manner:
  try
  {
    sendHttpRequest(uri, data, headers);
    return EC_OK;
  }
  catch (...)
  {
    return handleException(); // Lippincott!
  }  
The beauty of this lies in its conciseness - no copy-pasted code, no macros, just a natural function call somehow obliterating the ugliness of the try-catch blocks.

4. "Modern" Lippincott variants

What we have seen above was the plain, basic, C++98-esque usage. But C++ wouldn't be itself, if we couldn't complicate things in name of progress and fashionable gimmicks ๐Ÿ˜‡.

Just have a look at this code taken from the already mentioned article*:
  foo_Result lippincott()
  try
  {
     try
     {
        if (std::exception_ptr eptr = std::current_exception())
        {
           std::rethrow_exception(eptr);
        }
        else
        {
           return FOO_UNKNOWN;
        }
     }
     catch (const MyException1&)
     {
        return FOO_ERROR1;
     }
     catch (const MyException2&)
     {
        return FOO_ERROR2;
     }
     catch (...)
     {
        return FOO_UNKNOWN;
     }
  }
  catch (...)
  {
     return FOO_UNKNOWN;
  }
First irritating thing here is the function-scope try block. C++ allows you to wrap function body in a try/catch clause like this:
  ErrCode getSomeData()
  try
  {
     // do sth....
  }
  catch (...)
  {
    return PANIC_ERR;
  }
What is the purpose of this fature, you might ask? As cppreference.com states:
"The primary purpose of function-try-blocks is to respond to an exception thrown from the member initializer list in a constructor by logging and rethrowing, modifying the exception object and rethrowing, throwing a different exception instead, or terminating the program"
So there aren't any corner cases to justify its usage, and our example we already handle exceptions inside of the function  OK, now we can shed this syntax noise off. The second oddness is the usage of std::current_exception() and std::rethrow_exception() - what it is for? 

When you call std::current_exception() from within your function you can chek if there currently is an exception being handled and if it returns a nullptr then there is no exception active. Thus in the discussed code, we, in a somehow paranoid manner, are making sure that the exception dispatching function was called from the exception context - so to say implementing a "safe Lippincott" pattern. But ask yourself - would a programmer use a Lippincott function outside of a catch() block?  Well, maybe.

However, not all modern features are bad - far from that! Look at this elegant technique that uses lambdas:
  extern "C" errno_t my_amazing_c_function()
  {
    return translateException(
[&]{ // ... C++ code that may throw ... }); }
Here we wrap code that may throw in a lambda and pass it to a  generalized exception translation function which can be implemented like that:
  template<typename Callable>
    ErrorCode translateException(Callable&& f)
  {
    try
    {
      f();
      return NO_ERR;
     }
     catch (...)
     {
      return translateExceptionToErrno(); // Lippincott!
     }
  }
Cool, innit?

P.S.: "Ceterum censeo exceptiones delendam sunt..." - M. Portius Cato

--

* for example here: http://cppsecrets.blogspot.com/2013/12/using-lippincott-function-for.html plus many mentions of this article on Stack Overflow.

** Look up the Casablanca post: http://ib-krajewski.blogspot.com/2015/09/casablanca-c-rest-framework-one-year.html

Tuesday, 18 August 2020

A study in bad naming


Recently, while working for one of my clients on someone other's code I spotted the following definitions of members in some class:

What's that???!!!  Can you see it? Are you as much shocked as I was on its first sight? You are not? OK, I will explain my abomination - every declaration had to be commented! And that's not enough - the comments are essential in understanding the purpose of each member!

Why I do not like it, you might ask? Well, I'm lazy and commenting each declaration seems like too much work... You might ask 'why?' again - well, if I would like to add some definition to this code, I'd have to write a comment as well in order to maintain the (arguably flawed) coding style! I'm only a service provider for my client and wouldn't like to break this code's look and feel.

As you might know I'm not a friend of the newfangled "no comments" politics, but this is an example where we could definitevely use some of it. But why's that so bad again? It's because you could fix the example code with careful usage of naming* and it's even not that difficult! 

Let's have a go at it:
  /* State m_state => */ State m_dateValidity;
here we don't have to include "state" in the name, as it is already stated as the domain of the variable.
  /* QAction* m_action => */ QAction* m_datePickerPopupAction;
Here, however, we somehow inconsistently included "Action" in the member's name mainly because of my vague gut feeling. In this instance we could indeed try to improve the naming by considering shortening it, maybe even to m_datePickerAction;
  /* QDate m_date => */ QDate m_parsedDate;
A no-brainer.
  /* QStringList m_parseFormats => */ QStringList m_dateParsingFormats;
Another one!
  /* bool m_twoYearIsPast => */ bool m_treat2DigitYearsAsPast;
Here we could try to make the name a little better - maybe m_twoDigitYearsInThePast
  /* QDate m_minDate => */ QDate m_earliestDate;
As minimum and maximum are't commonly used with dates.
  /* QDate m_maxDate => */ QDate m_latestDate;
Idem.
  /* bool m_justFocused => */ bool m_focusReceived; // used for workaround ABC... 
Here I see the only place where a comment is needed.

So, what do you say? It wasn't even that difficult. Arguably the result isn't perfect but it's a lot better than the original. Maybe it's even good enough? 

So watch your names, they are important - because code readibility is important!

--
* As they say -"there are only 2 hard problem in comp. sci. - cache invalidation and naming things"...

Saturday, 4 April 2020

My answer to a young programmer


You maybe know that I offer C++ mentoring via Twitter (DMs are open!) and, as it happened, someone approached me and wanted to be mentored. So I asked him for his questions and then wrote some responses, which ended up to to be qute long... Then the idea to share what I wrote in this blog - maybe someonw will find it interesing.

Without much ado, to the questions.

1. Questions

I first asked about the goals. Thes answers are probably in line with many young programmers want:
1. I just need to be able to solve programming problems and strong myself in
this part, to be qualified for big tech companies interviews like Google,
Microsoft and Amazon. 
2. No the programming language doesn't matter for me, I know the basics of C, C++ and Python but I just want to be a problem solver and think like a programmer 
3.  I just want to understand the theory behind Algorithms and Data Structure
Then also came a list of resources that one finds on the internet using uncle Google. I won't show them here, as thea are quoted in the response.

2 The Response

Here's my response, in full, without any later editing:
Hi Xyz!

I had a look at your references:

>Courses:

>Algorithms and Data structures by Revi
>https://youtube.com/playlist?list=PLEbnTDJUr_IeHYw_sfBOJ6gk5pie0yP-0

Here we have much complexity theory but little of algos - only basic sorting methods.

>Algorithms by Abdul Bari
>https://youtube.com/playlist?list=PLDN4rrl48XKpZkf03iYFl-O29szjTrs_O

Don't know what to think about it's TOC - maybe too academic (too much about recurrences) but also covers a broad range of themes you'll need. So-so.

>MIT 6.006 Introduction to Algorithms
>https://youtube.com/playlist?list=PLUl4u3cNGP61Oq3tWYp6V_F-5jb5L2iHb
Had a look the TOC and liked it! If you can grasp these themes, you'll have good working knowledge of Comp.Sci.

>Books:

>Data Structures and Program Design in C by Robert L. Kruse
>https://goodreads.com/book/show/27846.Data_Structures_and_Program_Design_in_C
Looks like it's pretty old. Probably outdated, looks like waste of time.

>Introduction to Algorithms By Thomas H. Cormen
>https://mitpress.mit.edu/books/introduction-algorithms-third-edition

This is a classic, maybe a little heavy on the academic side, but a good reference to check what the options are. For an algorithms book the "The Algorithm Design Manual" by Steven Skiena is a much lighter read I'd recommed!

>Think Like a Programmer by V. Anton Spraul
>https://goodreads.com/book/show/13590009-think-like-a-programmer

I don't know this one. Had a look at the TOC and it can be OK or even good. It has a couple of programming problems but the title seems to be kind of a clickbait. Notheless. maybe it's good.

>Practice:

>https://hackerrank.com

Don't know this one (sorry) and couldn't check it out, as it requires a login. Back in the day Google recommended topcoder.com for testing your problem-solving skills in competitions, but I don't know the current status of it.

>https://leetcode.com

Don't know this one (sorry), but it looks somehow inetersting at first glance. You have specific questions for Google, Facebook, etc. Could be worth it.

And responses:

>I just need to be able to solve programming problems and strong myself in this part, to be qualified for big tech companies interviews like Google, Microsoft and Amazon.

A classic book for that is "Cracking the Coding Interview" by Gyle Laakmann McDowell - but it's a real tome! "Programming Interviews Exposed" by J. Morgan et. all was a lighte read. "Algorithms for Intreviews" by A. Aziz & A. Prakesh has many tough problems, but the solutions aren't that well explained - a challenge!

>Q1: No the programming language doesn't matter for me, I know the basics of C, C++ and Python but I just want to be a problem solver and think like a programmer

To be a (real) problem solver you need some deep knowledge in at leas one OO-langauge! Programmers think in patterns, you have to learn them by solving programming problems! On a little higher level, you'll need at least cursory knowledge in design patterns - look at the 4 Amigos book!

>Q2: I just want to understand the theory behind Algorithms and Data Structure

You'll have to undertstand the O-notation at least and to be able to estimate the O-complexity of your algoriths. The Master theorem is not really needed though. You have at least to understand NP-complete complexity class (NP=P?). You'll have to be able to estimate run time of an algorithm - which algos would need thousands of years to complete?

Regards,
Marek
3. Summing Up

Hopefully some young programmer(s) will find it helpful!

Trip Report Qt Word Summit, Berlin, 5-6 November 2019


You've probably noticed that I'm not a hell of a conference goer, didn't you? The last conference I attended was the first "Meeting C++" conference in 2014, at that time still taking place in Neuss, Rhineland* instead of the worldly and hipster Berlin.

I tried to go to the two consecutive Meeting C++ conferences in Berlin, but I was both times unable to do it, so eventually I gave up and called it a day on this idea.

But because recently I got somehow more seriously involved with the Qt framework** I thought, hey, why not just go to this one Qt conference*** in Berlin and visit some of my people there as well? No sooner thought than done. And now, three months something later, another idea struck me - why not write up some impressions? So let us go over things I came to remember most vividly.

Of course you could start moaning that it is much toooo late for a trip report, but better late than sorry, so let us begin!

1. Lars Knoll's talk

Lars Knoll, the CTO of the Qt Company was giving a talk on general directions for the future Qt 6 development and it was rather interesting. You can check it out here (PDF), but basically QML will be reworked to be a typed programming language, Javascript will be only optional and graphics will support not only OpenGL but also newer APIs like Vulcan, Metal or Direct3D 12. All that's very interesting, but what struck me the most was the following slide:


As it seems Qt is predominantly used on Windows! That's kind of surprising, taking into account that all the books and articles you read always assume Linux as a platform! I personally did a lot of Qt work on Windows and couldn't ever understand that.

This slide gave me a nice, fuzzy feeling, because my decision to write my Qt book from a point of view of a Windows developer was a right one!

Other books always describe the tooling you can use on Linux, but this doesn't help me on Windows, because most of that tooling (open source) doesn't exist there. So writing of the Chapter 2 (Profiling and Profilers) was a kind of a discovery journey - how can I make open source tooling run and correctly work on Windows?

2. Keynotes

As much as I don't like keynotes - normally they are rather full of business-y bla bla - but one slide of the Natalie Nahai's presentation really impressed me, I mean this one:
You can see the change of the vibes of a webpage from the left (boring, lots of distractions, unusable!) to right (cool, clear, using 1-click donation buttons). Nice! And it really happened during Obama's campaign.

3. Caliatys hydrogen mobility talk

This one was also a keynote (or I think so...) but the CTO of the company has shown us the slide containing a decision table they used for choosing the Qt framework as a platform for mobile development. The application in question should run on both iPhone and Android device. After the recent switch of Dropbox away from a commonn C++ codebase for both platforms you would maybe expect that C++ isn't good for mobile.

See their reasons for choosing Qt in the pic below:


The cloud connector had to be written separately for each platform, apart from this Qt provided for platform-independence!

4. QML on Microcontrollers

I already said, that the new QML will be a compiled, statically typed language in Qt 6. Already today, we can have a foretaste of the future with Qt Quick Ultralite (Qt QUL) that can be run on MCUs (microcontrollers) - a feat in itself, as up to this day Qt and QML needed a much more beefy processors to be run onto! There were quite a few talks centering around that theme, because it seems to be the future of Qt.

Qt Quick Ultralite is thus basically a subset of QML which can be compiled to C++ and run on bare metal (or an RTOS). This is also a direction in which QML will be going in Qt 6. I was pleasently surprised to learn, that Qt QUL was developed by the Qt Company in cooperation with a polish enterprise that ported it to many MCUs (see the picture below ๐Ÿ‘‡).


As it's my native country, I couldn't help but to be very pleased. Good job Poland! ๐Ÿ˜

5. People and stories

As it goes, I stumbled upon 2 of my old clients at the conference! I tool the opportunity and asked them about how my old projects fared after I left. We had quite good chats and I wanted to talk to them on the next day also, but - you won't believe it - I couldn't spot them anymore! The conference is a pretty big event with masses of people and finding someone is rather matter of luck.

I also could (and was honored to) meet some, i.e. two ๐Ÿ™‚, Qt-involved people, I only knew from Twitter, in the real world. As I expected. they turned out to be very nice indeed! Plus I also wound up talking to people in the queue to the canteen and at the exhibitor stands - I even could ask Qt's CTO a question face-to-face after his talk.

Now let us proceed to the "stories" part of this section:

One of my customers I met at the venue told me a nice story right form the threnches, They had a beast of a performance problem with the embedded device in my old project (accidentally same project as in the perf. story 6.4 in the book**), namely, after a day being powered on, the device started to slow down up to a total grind - the UI became totally unresponsive and you had to reboot it. What is your guess for the reason of that?

Yes, you are right, a memory leak.

But you'll never guess what couse it! When displaying the time of the day, on every update (i.e. every second) the displayed string was changed and then restyled using CSS styles. As it turned out, there was a bug in the Qt version we used and restyling leaked memory at that place! How could you possibly find that?!?!, I asked, quite shocked. Well, it was accomplished by the old and proven method of pinching off parts of the programm until the problem disappears. A kind of "divide and conquer" of debugging. The solution? Quite a pragmatic one - just don't use styling in the updates. Unfortunaltely, I forgot to ask how's the look and feel of the widget now.

Want another story? Here we go - I met 2 guys in the queue in the canteen and chattet with them for quite a long time. At the evening, I went out with my Berlin people to their favourite craft beer bar in the neighbourhood. After a couple of pints I catched a glimple of some guy at the counter and had to ask myself - do I know that guy? No, impossible, only locals frequent this bar... But after a couple of further glimpses I just had to settle that and chatted up the guy and his friend. Guess what - they were the exact people I met at the conference. Then we had one more chat and I even could pitch my book** to them! Moral - everybody can google, there isn't such a thing like a hidden gem or an insider-only venue. ๐Ÿ˜”

6. Merchandise

Of course I also got some merchandise:
  • a Qt sticker set ๐Ÿ“—,
  • a T-shirt and a lanyard keychain from Qt ๐Ÿ‘‰,
  • sleeping mask (Batman style!) ๐Ÿฆ‡, also from Qt,
  • some small stickers from exhibitor companies 
But not that much I'd expect. There was a raffle where you could win a cool drone (sponsored by one of the exhibitors), but this time I was kinda outta luck.

7. Summing up

You tell me - do you think it was a good conference? The main lecture hall was very impressive in any case. An you could see the Berlin TV-tower right out of the window.

---
* early supporter! ๐Ÿ™‹

** see this book: https://www.packtpub.com/application-development/hands-high-performance-programming-qt-5

*** i.e. to the Qt World Summit conference. BTW, here are all QtWS-2019 videos to watch: https://resources.qt.io/qt-world-summit-2019

Monday, 6 August 2018

Scripting my Vim Editor


As an inveterate vim user the first thing (or one of the first things) I'd do when starting a new project under Windows is installing vim to use it for searching, grapping and editing logfiles when I'm bugfixing. Or just a to use it as a general viewer for all sorts of files.

Typically I'd set up my toolbar buttons (for vim 7.4) like that:
"" Caution: Needs 18x18 bitmaps in "C:\Program Files (x86)\Vim\vim73\bitmaps" !!!
:amenu ToolBar.-SEP- :
:tmenu ToolBar.tabedit Open new tab (mrkkrj)
:amenu ToolBar.tabedit :tabedit<cr>

:tmenu ToolBar.darklight Switch color themes (mrkkrj)
:amenu ToolBar.darklight :colo zellner<cr>
:tmenu ToolBar.lightdark Switch color themes (mrkkrj)
:amenu ToolBar.lightdark :colo torte<cr>

:tmenu ToolBar.smallfont Smaller font (mrkkrj)
:amenu ToolBar.smallfont :set guifont=Lucida_Console:h9<cr>
:tmenu ToolBar.bigfont Bigger font (mrkkrj)
:amenu ToolBar.bigfont :set guifont=Lucida_Console:h10<c>
This gives me my standard button toolbar with buttons for switching fonts and and colors from big to small and from dark to light, plus a button for opening new tabs:


Somehow this was always enough, beacuse I just used my default dark scheme  plus one more dark and an alternative light one. As you know the colors depend on the monitir you are using and the room you are sitting in, so in my new project I wanted to toggle through several schemes and font sizes before I settle down with my favorite. Thus I introduced following functions:
:tmenu ToolBar.darklight Switch color themes (mrkkrj)
:amenu ToolBar.darklight :call ToggleLightScheme()<cr>
:tmenu ToolBar.lightdark Switch color themes (mrkkrj)
:amenu ToolBar.lightdark :call ToggleDarkScheme()<cr>

:tmenu ToolBar.smallfont Smaller font (mrkkrj)
:amenu ToolBar.smallfont :set guifont=Lucida_Console:h9<cr>
:tmenu ToolBar.bigfont Bigger font (mrkkrj)
:amenu ToolBar.bigfont :call ToggleBigFontSize()<c>
Next thing is to write the actual functions to toggle between dark and light color schemes. What I did was toggling between 2 light and 2 dark color schemes like that:
:function ToggleDarkScheme()
:  if exists('g:colors_name')
:    if g:colors_name == 'evening'
:      colo darkblue
:    else
:      colo evening
:  endif
:  else
:      colo evening
:  endif
:endfunction

:function ToggleLightScheme()
:  if exists('g:colors_name')
:    if g:colors_name == 'zellner'
:      colo delek
:    else
:      colo zellner
:  endif
:  else
:      colo delek
:  endif
:endfunction
Toggling of fonts had to be done a little different, because there's no global variable that vim would set when fonts are changing like the g:colors_name above. So I had to introduce my own: g:guifonts_name:
let g:guifonts_name = 'Lucida_Console:h10'

:function ToggleBigFontSize()
:    if g:guifonts_name == 'Lucida_Console:h10'
:      set guifont=Lucida_Console:h12
:      let g:guifonts_name = 'Lucida_Console:h12'
:    else
:      set guifont=Lucida_Console:h10
:      let g:guifonts_name = 'Lucida_Console:h10'
:  endif
:endfunction
Admittedly this is not a pretty and general solution: if I needed more colors or fonts I'd have to add more ugly if-else clauses. The ceneral soultion would be of course  to create a local array of color schemes and cycle through it like it is shown here*. But "form follows function..." and "use before reuse..." ๐Ÿ˜‰ - and frankly, I didn't have time for that, vimscript's syntax** is pretty weird.

--
* "Switch Color Schemes" in Vim Tips Wiki: http://vim.wikia.com/wiki/Switch_color_schemes

** There some good intros you can use to deepen your knowledge of vim scripting:

Tuesday, 6 December 2016

Two interesting quirks of C++ uniform initialization


We all know and love the new C++11's uniform initialization feature (aka curly braces initialization), and, to be frank, there is much to warrant this love, like:

with structs
  struct X { bool x{false}; int i; ...};
  X x = { true, 100, ... };
  X x{ true, 100, ... };
with arrays:
  struct Y { int arr[3], bool b, ...};
  Y y{ {0,1,2}, false, ... };
  int* intArray = new int[3]{1, ,2, 3};
with library classes:
  std::vector<int> a = { 1, 2, 4 }; // yesss! At last!
  QMap<QString, QVector<int>> a = { {"0x111", { 1, 1, 1} }, {"0x100", { 1, 0, 0} } };
and you can enable it for you own classes as well, writing a constructor taking std::initializer_list as argument (example missing, but you know what I mean...)!

because it's universal, you can use it for types too:
  int i{1};
  int j{};
but it's a bit redundant here, as we already could do:
  int i(1);
  int j(0); // not j()! I never used () but assumed it to be the default initialized int :(
but there are 2 additional goodies packed into that, as I learned recently, namely:

1. The first one
this is an old problem: unexpectedly, the compiler will consider this:
  TimeKeeper time_keeper();
not to be an object instantiation but a function definition! Here TimeKeeper is a class (reused) from the Wikipedia article:
  class TimeKeeper {
    public:
      TimeKeeper();
      int get_time();
  };
This the compiler will balk at:
  int t = time_keeper.get_time();
But thanks to uniform initialization not at this:
  TimeKeeper time_keeper1{};
  int t = time_keeper1.get_time();
OK, you are right, that's not the most vexing parse ๐Ÿ˜‰, but simply incorrect usage of the constructor! The most vexing parse requires a parameter to the constructor! But I made this error several times myself when blindly typing ahead...  none the less, the problem is the same, only with a parameter:
  TimeKeeper time_keeper(Timer());
Here is a function with taking a function(!) like Timer mkTimer() as single, unnamed (!) parameter. Vexing? Now correct that with a single stroke (or two):
  TimeKeeper time_keeper{Timer()};
Nice to know when you need a workaround for a vexing parse!

2. The second one
Here Bjarne himself explains that:
  int x = 7.3; // Ouch!
but
  int x0 {7.3}; // error: narrowing
  int x1 = {7.3}; // error: narrowing
Moreover, compiler will automatically check int sizes on initializing (in Bjarne's words again):
  char c1{7}; // OK: 7 is an int, but it fits in a char  
  char c2{77777}; // error: narrowing (assuming 8-bit chars)
That's nice.

Considered I am a traditionalist and like my code to look like a old, regular C++, but these features make a nice argument in favor of using curly braces instead of the normal ones! Will for sure consider that!


Tuesday, 29 March 2016

Empirical Results on the Static vs. Dynamic Debate?


You may know that I'm quite interested in the "Static vs. Dynamic Typing" controversy, and already even clearly declared my allegiance basing my decision on some pretty sloppy reasoning (if not largely on the gut feeling...).

But what about some hard facts, numbers, measurements and controlled experiments to decide the debate? Like the Leibnizian* "Calculemus!". Well, some good soul (@danluu) took the burden of this task and looked** at the best known papers, talks  and comparison studies. To what avail?

First there's a warning:
"If you look at the internet commentary on these studies, most of them are passed around to justify one viewpoint or another. The Prechelt study on dynamic vs. static, along with the follow-ups on Lisp are perennial favorites of dynamic language advocates, and github mining study has recently become trendy among functional programmers."
So apparently, there's little interest to find out the truth, only to defend convenient positions. But we are fearless seekers for the truth, and want to know what the results are. Unfortunately the classic studies, when examined in more detail reveal some serious methodological flaws, and the author could only conclude that:
"Other than cherry picking studies to confirm a long-held position, the most common response I’ve heard to these sorts of studies is that the effect isn’t quantifiable by a controlled experiment."
OK, pretty sobering, we still know nothing, it's all lies, damn lies and/or lacking statistical knowledge. But how come the theoretically superior static typing, and that by a simple argument - how can be more support from the compiler not be better than less support - do not bring any measurable improvements?

Lets reiterate the position taken by supporters of dynamic typing in words taken from a  talk at JavaZone:
If these academic computer scientists would get out more, they would soon discover an increasing incidence of software developed in languages such a Python, Ruby and Clojure which use dynamic, albeit strong, type systems. They would probably be surprised to find that much of this software—in spite of their well-founded type-theoretic hubris—actually works, and is indeed reliable out of all proportion to their expectations.
So it seems to work in real life, and the experimental studies cannot prove the contrary. But it also looks like someone is trying hard to ignore something, don't you think so?

But then I discovered a recent paper which proposed an new angle of attack!

While the old studies tried to measure the performance of programmers (and somehow failed to design a meaningful experiment) the authors of the new one pursued a more modest goal. They introduced random changes to program's code and then tried to compile and run it. In their words:
"Our study is based on a diverse corpus of programs written in several programming languages systematically perturbed using a mutation-based fuzz generator.
....
More importantly, our study also demonstrates the potential of comparative language fuzz testing for evaluating programming language designs."
We thus could have a possibility to compare programming languages in some way? Sounds promising! So what are the results?
"The results we obtained prove that languages with weak type systems are significantly likelier than languages that enforce strong typing to let fuzzed programs compile and run, and, in the end, produce erroneous results."
The exact results are maybe interesting***:

Ruby
   - compile: 54%
   - run       :  31%
 Python
   - compile: 43%
   - run       :  25% 
PHP
: (that poster child of bad language design!)
   - compile: 48%
   - run       :  41% 
Javascript

   - compile: 49%
   - run       :  23% 
Java

   - compile: 18%
   - run       :  15% 
Haskell

   - compile: 19,5%
   - run       :  18% 
C++

   - compile: 20,5%
   - run       :  12%

See, On the average, dynamically typed programs are twice as likely to be compiling/running wioth nonsensical source code. That's definitely SOME improvement, isn't it?

On the other side: they are testing programming languages' resiliency against typos - but wasn't that the exact reason for introduction of types in programming languages? So we know that typed languages are good in what they were invented for. But we knew that already.

Update: This blogpost sets up a different thesis: the difference between statically and dynamically typed languages isn't that important. Rather than that, the simplicity of the language design is decisive in order to avoid bugs! IMHO this argument is misguided, because what I wanted to know is, given two languages of "same complexity" (problems, problems, hot to measure that?) which is a better one - the one with or without static typing?

--
*  Nice little fact - Leibniz's program for mathematization of human knowledge was formulated in the following words:
"Actually, when controversies arise, the necessity of disputation between two philosophers would not be bigger than that between two computists. It would be enough for them to take the quills in their hands, to sit down at their abaci, and to say  (as if inviting each other in a friendly manner): Let's calculate! (Calculemus!)"
Unfortunately, this cannot be done (at least according to Turing) and flame wars still prevail.

 ** http://danluu.com/empirical-pl/ - "Static vs. Dynamic Languages: A Literature Review"

*** Caution: they are not exact, I read it out of a diagram!

Sunday, 29 November 2015

OCaml and Multithreading


As Doctor House said one day: "There was that philosopher Ocaml..." Stop, wrong start! Try again.

1. OCaml story

OK, some time ago, in a somehow better world, I became attracted to the OCaml language because of its speed, elegance, light syntax, algebraic data structures and automatic type inference (as you meanwhile might know, I'm a bit of a typing fan). I must admit, it was my first functional language, so maybe I'm a little sentimental about it. Later on I somehow didn't give it much love and affection, mostly because I got distracted by other, more fashionable languages like Clojure, F# and Haskell (shame on me!).

Nonetheless, although this one is rather an obscure language, one company has been using it big time to do some highly parallel, high-performance data processing. This company is Jane Street and they are a financial market player. The reason they chose OCaml were that the owners wanted to read every line of code performing financial transactions*:
"Early on, a couple of the most senior traders (including one of the founders) committed to reading every line of code that went into the core trading systems, before those systems went into production"
"In 2003, Jane Street began a rewrite of its core trading systems in Java. The rewrite was eventually abandoned, in part because the resulting code was too difficult to read and reason about—far more difficult, indeed, than the VBA that was being replaced."
 "The VBA code was written in a terse, straight-ahead style that was fairly easy to follow. But somehow when coding in Java we built up a nest of classes that left people scratching their heads when they wanted to understand..."
 "In 2005, emboldened by the success of the research group, Jane Street initiated another rewrite of its core trading systems, this time in OCaml."
So somehow the functional-style code was more readable than a pile of Java classes: can we put that to the superiority of functional languages in general or just to bad training of Java programmers? An open question.

OK, there are additional technical reasons as well: the type inference that makes the code concise (thus more readable) while retaining type safety. Additionally it's runtime performance is pretty good! A double win against for example Python.

2. Multithreading?

For a long time they remained the single serious industry user of which I knew, but recently also Facebook started using OCaml in their Hack and Flow language typing add-ons for PHP and Javascript implementations. Surprise! And a very nice one, my pet language got appreciated at last! Everything OK?

Not quite: when I listened to that presentation, I was surprised to learn that OCaml's mutlithreading support is pretty much completely broken. How can that be? Why didn't I notice that first place?



Well, after some more digging, I received this link from a fellow programmer. It makes it pretty clear to us all that OCaml designers were quite a nasty bunch of "multicore deniers":
"The goals of OCaml threads are (2) and (3) but not (1)"
Where (1) denotes "Parallelism on shared-memory multiprocessors"! And then:
"Shared-memory multiprocessors have never really "taken off", at least in the general public.  For large parallel computations, clusters (distributed-memory systems) are the norm. For desktop use, monoprocessors are plenty fast."
 "What about hyperthreading?  Well, I believe it's the last convulsive movement of SMP's corpse :-)"
Yes, they didn't like it, to say the least. But there's another reason as well: the GC implementation in OCaml is single-threaded and thus it could be made very fast, which was an important factor in OCaml's initial successes. But then this (ironically) proved detrimental to trying to make the language MT-safe**.

The only way to do parallel processing in OCaml is thus multiprocessing + message passing. As I learned Jane Street wrote the Parallel library to support that:
"Parallel is a library for spawning processes on a cluster of machines, and passing typed messages between them. The aim is to make using another processes as easy as possible. Parallel was built to take advantage of multicore computers in OCaml, which can't use threads for parallelism due to it's non reentrant runtime
The Facebook people went one step further: they
"...use the same model for multithreading: a specially mmap'd region shared between different fork'd processes, containing a shared, lockless hash table. "
Thus they have multithreading without threads - a couple of processes sharing the memory space (or a part of it), faking the SMP model! You must admit it's rather brilliant - you spare yourself all that serialization, deserialization, and message passing that normally shave off a significant part of the performance.

3. So why OCaml?

Apparently, despite the mutithreading disaster, companies find OCaml worth trying out. Why? I'd say the reasons are:

  1. It supports functional style (but it allows dirty tricks when they must be done)
  2. Has strong typing unlike Lisp, Python, etc.
  3. Not bound to Windows and .NET like F#
  4. Not Haskell, you'll be able to read and understand it.***

And finally, maybe this whole multithreading business isn't worth the hassle? Facebook clearly need it, but Jane Street don't. I remember having heard Yaron Minsky (of Jane Street) saying somewhere that parallel processing plus message passing is a much safer model that multithreading. And in finance you need that safety.

I can accept this argument in a more general setting as well, because the only reason we have threads are performance gains (OK, a deceptively "natural" programming model too). And if the performance of forking + message passing is sufficient, that's definitely a gain! Jane Street does some massive parallel processing in real time, so the performance seems to be not that bad after all...

Or maybe the fork+pass model is slower, but they are gaining on the excellent low-latency CG? Jon Harrop puts it like that:
"OCaml has a nice (~10ms) low latency GC and it is easy to optimise OCaml code for low latency. In contrast, the .NET GC is much more complicated and, therefore, harder to optimise for and, in my experience, has >10x higher latency. I suspect that would be a major drawback for Jane Street."
So before you port OCaml's GC to multicore, overcomplicating it and losing its excellent performance, maybe paying some price for the workarounds pays out better?

Having said that, there's recent work on improving the GC-performance even more, and even a new attempt on multicore OCaml. Maybe this time they will be successful. And be wary, not everyone likes OCaml, for some "OCAML sucks" - http://www.podval.org/~sds/ocaml-sucks.html!

Update: an impressive list of companies using OCaml: https://ocaml.org/learn/companies.html (via @jonharrop). So it's not only Jane Street and Facebook!
Update2: Facebook continues working on OCaml ecosystem - Reason, a "new interface to OCaml" ... "provides a new syntax and toolchain for editing, building, and sharing code". Plus Infer - the iOS/Android app checking tool!

--
* "OCaml for the masses" - http://queue.acm.org/detail.cfm?id=2038036

** "The rise and fall of OCaml" - http://flyingfrogblog.blogspot.co.uk/2010/08/rise-and-fall-of-ocaml.html

 ***  As someone said, Haskell was created to do research on Haskell (and OCaml was created to write theorem provers).


Thursday, 12 November 2015

Monads, who's afraid of Monads (and C++)?


Nowadays every programmer has heard of Monads, and either has a PhD in CS or is afraid of them (or both...). When I first heard of it (my university years are quite distant, and the category theory wasn't en vogue yet in that distant time) I though: "Monadology? Leibniz? WTF? Didn't Kant disprove that?"

Because writing a monad tutorial is sooo last decade, I will just reference one quite good, practical introduction to that stuff that is using Javascript (Javascript! => nice, no need to learn a new, unreadable & incomprehensible language first! ๐Ÿ˜€). I think it's <praise> practical enough to be useful, but then again not shirking back from maths in order to please the reader</praise>.

If you don't want to read it, and are smug enough to think that a 10.000 feet view is all you'll ever need, voila - there's a short summary:

Monads Summary

1. Functor

An object encapsulating a value, plus an interface (called "fmap" for historical reasons) taking some function to act on that value. Because of the immutability/pure functions stuff it doesn't change the contained value, of course, but produces a new functor instance.
            +------------+                                  +------------+
            |   value    |                                  |  newvalue  |
      f     |            |     fmap()                       |            |
  +-------> |   fmap()   |  +--------->  f(value) +-------> |   fmap()   |
            |            |                                  |            |
            +------------+                                  +------------+
Is the picture clear enough? OK, let's continue.

2. Monad

Is a Functor which has a "collapse" and "wrap" methods. Collapse (also called "join" in some contexts) will remove one level of the packaging added by the functor, "wrap" (also called "return") will remove it. Simple like that!
  +-------------------------------+                               
  |                               |                               
  |            +-------------+    |                 +------------+
  |            |             |    |       join      |            |
  |   value =  |    value    |    |   +---------->  |   value    |
  |            |             |    |                 |            |
  |            +-------------+    |                 +------------+
  |                               |                               
  +-------------------------------+                               

                         +------------+
               wrap      |            |
   value   +---------->  |   value    |
                         |            |
                         +------------+
Well not quite, the classic usage case** that made the whole concept famous, hinges on another method called "mbind" which allows us to apply several functions to the monadic value in a row, an emulation of imperative programming (imperative always means in this context "evil, evil") standard sequential flow of control. But wait a minute: isn't that simply "fmap" + "join"? Yeah, you guessed it, it is***.

Simple? Yes, I think so. Was it that complicated? No. So why all that fuss? Don't know, won't comment here, make your own mind.

But why should this be useful? Again, I don't want to write a monad tutorial here (it's so ...), read the Javascript  book, or maybe some general functional programming resources. Start with error handling and the Maybe type.

High level enough? If not, take on with this classic explanation: "Monad is just a monoid in category of endofunctors, what's the problem?"*. Here you'll need some category theory/maths, there's no mercy:

Another Summary

1. Endofunctor

A functor (see above) mapping values to values of the same type. On that level, functor is a mapping between categories, where a category is a set of values plus all the functions between the values. Thus our functor above maps values of type A to values of type B and functions A->A to functions B->B, respecting some common sense restrictions on its way.

You see, it's getting pretty messy quite quickly, but take it as a mathematical recreation and follow through.

2. Category of endofunctors

All endofunctors plus functions mapping one endofuctor (i.e. a functor, i.e a mapping from one "set" of object+mappings to another) to another.

3. Monoid in that category...

Monoid is a "set" of objects having a function A->A defined for them (usually called "m-append", you get it, basically a glorified string or array) plus a neutral element. Now just imagine that for the category of endofunctors, do some math, an you will see that all that gunk collapses to our old, trusty monad as described above.

Why so complicated? Well, that's maths (and mathematicians) for you. But don't despair, it's only a construction of a human mind, so everyone can get a grip of it. The question is only if that does feel like fun for you or not. In all cases, don't mythologize!

And That's It!

Now if you feel like that, you can try out this things in C++, there are a couple libraries implementing this stuff like thisthis or that. Simple, self-sufficient implementation is possible too! There was even a C++ language proposal for a monadic expected class to be used for error handling, so somehow this stuff is coming. Now as you are not intimidated anymore, go and try it!

But first read the Javascript online book to familiarize yourself with the concepts. And yes, you don't need to learn Haskell**** and then read Haskell books for that! So do not fear.

Maybe you'd even like to go further and investigate monadic parsers (because I like F# you'll get this link and this link), applicatives & applicative parsers (sorry no link here, didn't find anything which is simple enough) or free monads. Who knows, the sky is the limit now, an you do not fear anything! At least you can read the jargon without cold shivers running down your spine.

PS: Maths guys, please no hair-splitting, I didn't cross-checked it with MacLane & Avodey, just wrote it down as I remembered it. However notice the "set" usage ;) ...


Update: If you want to continue in a similar vein, that's an interesting page demythologizing func. prog. on its own: github.hemanth.functional-programming-jargon!

--
* famously attributed to Phillip Wadler, but it's rather a joke, as the real sentence was:
"All told, a monad in X is just a monoid in the category of endofunctors of X, with product × replaced by composition of endofunctors and unit set by the identity endofunctor."
** by..., you guessed it, Phil Wadler: "Monads for functional programming" (it's CS + FP but nonetheless quite readable, you may risk a try now when you fear nothing!)

*** in some contexts "point" and "flatMap" are used, the first for "wrap", the second for "fmap" + "collapse"

**** "I'm Haskell, the language of purebloods..." ๐Ÿ˜‰