Hacker News new | past | comments | ask | show | jobs | submit login

The boilerplate gives you additional type safety compared to C.

If you want the same type safety as C, which is basically none, then you can write it as:

    // foo.hpp
    struct Foo {
      static Foo* make();

      void method();
    };

    // foo.cpp
    struct FooImp : Foo {
      std::string something;
    };

    Foo* Foo::make() {
      return new FooImp();
    }

    void Foo::something() {
      ...
    }
And yes it's rare because nowadays most C++ developers stick as much to value semantics as possible rather than reference semantics, but this approach was very common in the early 2000s, especially when writing Windows COM components.

Nowadays if you want ABI stability, you'd use PIMPL. Qt is probably the biggest library that uses this approach to preserve ABI.




I don't think it's fair to say that C has no type safety. To recap, I had:

  typedef struct foo Foo;

  extern Foo* foo_create();

  extern const char* foo_getStringOrSomething(Foo* foo);
The only valid way to get a Foo (or a Foo ptr) is by calling foo_create(). Inside foo_getStringOrSomething(), the pointer is definitely the correct type unless the caller has done something naughty.

Of course there are a few caveats. First, the Foo could have been deleted, so you have a use-after-free. That's a biggie for sure! Likewise the caller could pass NULL, but that's easily checked at runtime. Those are part of the nature of C, but they're not "no type safety".

You can also cast an arbitrary pointer to Foo*, but that's equally possibly in C++.


A comment like "basically none" should not be taken literally. It is intended to indicate that the difference between the C++ approach and the C approach is that the C++ approach gives you a great deal of type safety to the point that the C approach looks downright error prone.

The C++ approach of sticking to value semantics doesn't involve any of the issues you get working with pointers, like lifetime issues, null pointer checks, invalid casts, forgetting to properly deallocate it, for example you have a foo_create but you didn't provide the corresponding foo_delete. Do I delete it using free, which could potentially lead to memory leaks? The type system gives me no indication of how I am supposed to properly deallocate your foo.

You don't like boilerplate, fair enough it's annoying to write, but is boilerplate in the implementation worse than having to burden every user of your class by prefixing every single function name with foo_?

The C++ approach allows you to treat the class like any other built in type, so you can give it a copy and assignment operator, or give it move semantics.

So no it's not literally true that C has absolutely zero type safety. It is true that compared to the C++ approach it is incredibly error prone.

While older C++ code is rampant with pointers, references, and runtime polymorphism, best practices when writing modern C++ code is to stick to value types, abstain from exposing pointers in your APIs, prefer type-checked parametric polymorphism over object oriented programming.

If anything, the worst parts of C++, including your point about being able to perform an invalid cast, is inherited from C. C++ casts, for example, do not allow arbitrary pointers to be cast to each other.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: