Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Which is why I'm seriously tempted to add a simple template system on top of C (it has already been done, by the way), then implement containers on top of that.

With that, I get the power without the rabbit hole.



Wouldn't it just be simpler to fuse off the part of your linker that handles vtables? IIRC That'll kill every C++ feature that's objectionable to someone who likes the idea of 'C with templates'

Unless you want a truly simple C template system, in which case aren't the C11 type sensitive macros sufficient?


> C11 type sensitive macros

Hey, that sounds cool. Do you have a link? A quick search doesn't seem to work.

The vtables on the other hand I will steer clear from. Closures are way more useful than class based polymorphism. Combine it with parametric polymorphism (templates), and you won't need to subclass anything ever again —okay, I'm exaggerating a little.


Look for the "_Generic" keyword.

On that topic, it is possible to do cool things with macros with GCC extensions. A simple example of generic macros was discussed about a week ago: https://news.ycombinator.com/item?id=7896280


Thanks. Doesn't look like that's enough for my purposes, though.


It's called _Generic (which should be easier to Google), but the fact that you have to modify the macro wherever you want to use it with a new type severely limits its usefulness.


Type erased closures are strictly less useful than subtype polymorphism + virtual functions (another form of type erasure) as the latter allows you to share data among an entire interface.


Closures are simpler, and therefore less cumbersome for 90% of the use cases. I prefer this compromise over the other.

Also, I'm not sure I get this "type erasure" business. In ML languages, there is no such erasure. I guess you need this erasure because the language doesn't support parametric polymorphism to begin with? I'm thinking about Java, which hacked generics after the fact, and maintained backward compatibility through type erasure.

In C++, there are few type erasures. Generally, when we want a function to receive a closure, we write it like this (minus dark corner I have missed):

  template <typename T, typename E>
  for_each(T functor, vector<E>);
No base class in sight there, just lots of duplicated object code. (Which is better is left as an exercise to the reader.)


Aren't std::functions effectively using something like vtables though?


std::function looks like a regular template class (like any container). And It doesn't look like we should subclass it. So, unless I'm missing something, there is no vtable.


std::function is usually implemented using subtype polymorphism internally.


Okay…

By the way, why do we need std::function at all? Every time I saw it, it was to work around some dark corner of C++ type system or template dark magic.


Because function pointers in C++ carry no state. Given:

    class A { void foo(); };
    A a;
There is no such construct that lets you store a call to foo specialized for the instance 'a':

    ??? thing = a.foo; // doesn't exist
The only option in C++ is to take the address of the member function:

    &A::foo
But even this is not sufficient as it is equivalent to:

    void (*)(A * __this)
That is, the "this" pointer is not stored. Along comes mem_fun:

    struct mem_fun{ A *a; void(A::*ptr)(); };
Now you can store a call to foo for the instance a:

    mem_fun fun;
    fun.a = &a;
    fun.ptr = &A::foo;
Adding an operator() to mem_fun lets you treat a mem_fun instance as a function:

    void operator()(){ a->*ptr(); }

    ...
    fun()
Now, lets say you need to store this as a generic "callback". Well, how would you do that? Sure, you can store mem_fun instances but what about just plain function pointers? Now you can't store them. In comes std::function. With a little bit of VERY simple to understand magic, you can do:

    std::function<void()> foo = fun; // mem_fun
    std::function<void()> foo2 = global_fun; // simple member pointer


Most programming languages implicitly type erase closures, C++ does not. Type erasure can come at the cost of heap allocation and indirect function calls. If you need type erasure in C++ you can put any callable type inside std::function.


Is it because everyone was thrown by the syntax of function pointers (for no good reason, other than they never encountered them)?


This is how C++ started. See cfront. http://en.m.wikipedia.org/wiki/Cfront




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

Search: