[nanomsg] Re: C++11 binding

  • From: Michael Powell <mwpowellhtx@xxxxxxxxx>
  • To: nanomsg@xxxxxxxxxxxxx
  • Date: Sat, 3 May 2014 10:07:41 -0500

On Sat, May 3, 2014 at 5:59 AM, Paul Colomiets <paul@xxxxxxxxxxxxxx> wrote:
> Hi Peter,
>
>> I wonder if someone has tried to _implement_ nanomsg with C++11.
>
> You should probably read:
> http://250bpm.com/blog:4
> http://250bpm.com/blog:8

These are common excuses why folks flat out reject C++; much less
reconsider their position when adopting language advances in C++11
such as functional programming, lambdas, initializer lists, and so on.

The fact is, when you do ABC expect ABC-issues to creep in; doesn't
matter if you mode of delivery is C, C++, Python, Java, or C#.
Personally, I'd rather know something was wrong with an exception than
allow a corruption to slowly creep in with a failed C memory
reference, type thing.

Re: a couple of points in the blog:

* handle_error() vs. throw std::exception() (or throw std::string(),
or throw (int)1, for that matter). First off, in C++, yeah I know; C++
allows you to throw anything. Other languages are more precise.
However, there's nothing stopping anyone from using "pure" C-isms in
C++ code. You have to be aware of your compiler; however, C builds
just fine in most C++ compilers.

* ctor initialization. Take advantage of member initializers. Do be
aware that virtualized methods do not work "as expected" in base
classes, if class initialization is what you're aiming for. If
necessary you can identify local method(s) to help with that; it's a
matter of style and personal preference.

* dtors vs. "terminated state". Again, matter of personal preference.
I'll use the .NET IDisposable as an example. dtor or IDisposable
instances are useful in a scope; typically in a using clause: Dispose
is called automatically, so their lifetime is limited. On the other
hand, you may have a pool of connection instances whose lifetime is
persistent for the session; one "state" is connected, disconnected,
etc. This is a completely separate concern from the lifetime of the
instance.

* pointer management. In a confined scope, it is usually unnecessary.
Additionally, use references whenever possible; const or otherwise.
It's like passing pointers but without the nasty dereferencing.

* When it is necessary, I strongly consider smart pointers; at least
unique pointer, possible shared pointer when appropriate. The
referencing counting and this kind of thing is going to happen in some
manner if I roll my own memory management utils anyway; why not let
the implementation handle it for me (do be aware of implementations).
Or a third party lib that I trust if I do not have confidence in the
implementation; or roll my own smart pointers if I absolutely want to.

As the author stated, there's no silver bullet; in my own words,
there's no magic pill that will cure your ills. Adopt ABC, expect
ABC-isms. For personal style, I am an object bigot, but not so much
that I am unwilling to consider every option available to me.

I have also grown to appreciate SOLID principles; especially when it
comes to composing apps, decoupling concerns, injecting handlers in a
functional way when I need to. I find that the solutions are better
organized, the necessary abstractions scale and perform quite
admirably, and are more maintainable (not perfect, just more; a
software developer's shangri-la, so to speak).

> --
> Paul
>

Other related posts: