Hacker News new | ask | show | jobs
by loup-vaillant 5447 days ago
I have to challenge some of your points:

2. Just use 2 languages, like C + Lua. or C + anything-higher-level-than-Java. As a "language", such a combination is easily simpler than C++, and the high level part is way cleaner. My point is, don't use one complex tool when 2 simpler one can do.

On a side note, you should think about what OOP, templates, and "meta-programming" are good for. Most of the time, naked lambdas and closures solves OOP's problems in simpler ways. Templates solve parametric polymorphism (or "genericity"), and meta-programming is just a buzzword, as far as C++ is concerned. (When it is not a buzzword, the systems behind are so huge than I wonder if it's worth the effort, see the Boost library.)

3. That one sounds like a lot of work. A high-level and efficient abstraction has to be build from a fairly low level. Efficient memory management for instance, will probably be more complicated than the straightforward (but copy-ridden) RAII scheme.

6. Properly thought out type systems enforce better, and in a simpler way. See Haskell for instance. And even if your high level language is very permissive (Lua, Lisp…), you could still write a custom preprocessor. Not too daunting, as long as the syntax you pre-process isn't C++'s.

1 comments

What do you mean when you say RAII is copy-ridden?
It's this thing about each object being responsible for the memory allocation of the data it points to:

  // Untested code, I hope I didn't miss anything
  class Foo {
  public:
    Foo(const Bar& b) : b(new Bar(b)) {}
    Foo(const Foo& f) : b(new Bar(*(f.b))) {}
    Foo& operator=(const Foo& f) { b = new Bar(*(f.b));
                                   return *this; }
    ~Foo()throw() { delete b; }
    // other methods
  private:
    Bar* b;
  }
std::auto_ptr<> let you keep your default destructor:

  class Foo {
  public:
    Foo(const Bar& b) : b(new Bar(b)) {}
    Foo(const Foo& f) : b(new Bar(*(f.b))) {}
    Foo& operator=(const Foo& f) { b = new Bar(*(f.b));
                                   return *this; }
    // default destructor
    // other methods
  private:
    std::auto_ptr<Bar> b;
  }
Or you could do away with pointers altogether (not always applicable, and it may fill up your stack too):

  class Foo {
  public:
    Foo(const Bar& b) : b(b) {}
    // default copy constructor, operator=, and destructor
    // other methods
  private:
    Bar b;
  }
So, whenever you need another instance of Foo, it will create another instance of Bar, which may create another instance of Baz… you get the idea. It is quite simple to do, and guarantees the absence of memory leaks, even in the presence of exceptions. But it copies a lot of data. C++ 0x move semantics will make it a little better, but it won't completely eliminate the problem.

Actually, copy is the essence of RAII. Rather than saying "hey, your piece of data is interesting, let me hook it" and later complain when the fish broke your line (dangling pointer), RAII says instead "hey, your piece of data is interesting, let me have a copy" so you are sure to keep your data safe, and the other is sure to be able to safely destroy its own copy at any time.

On a side note, you could avoid copying Bar instances by using Boost's shared pointers or a garbage collector. But it will only be practical if Bar is immutable. I am also told that there are other memory management schemes, which can be very efficient, but tend to be complex and error prone.