Live data from Hacker News

Generics in C without void* or macros – enabled by psychec

github.com

61–70 of 74 posts

Re: Generics in C without void* or macros – enabled by psychec

#61
post #50

Earlier quoted context omitted.

Pretty much anything involving constructors that fail.

It's easy to not write constructors that can fail. The major conveniences like templates, RAII, overloading, algorithms, lambdas, virtual functions, etc. work fine without exceptions.

It's doable to write constructors that don't throw exceptions; writing constructors that can't fail is not possible for a large fraction of the useful space of constructors.

If your constructors fail without throwing an exception, much of the usefulness of RAII goes away.

Re: Generics in C without void* or macros – enabled by psychec

#62
post #47

Earlier quoted context omitted.

One of the reasons C++ is so complicated is that you don't pay for the features that you don't use. If you wanted generics in C, you can easily use C++ without any of those other features (baggage, if you will) and not pay for it. Heck, you could define a few macros and make it impossible to use any baggage features you don't like. I've used C++ in a pretty tight embedded environment and it was great.

> I've used C++ in a pretty tight embedded environment and it was great. I'd love to hear some details. I'm always looking for C++ stories that didn't end in disaster and what the people did that worked.

I've done similar. The Microsoft Band UI was written in C++. No templates or other advanced features, compiler was stuck on 2003 standard. We had templates but used the trick of implementing them in a .cpp file and declaring all the instanciations of them we'd ever use at the bottom of the same file. Had to write our own to guarantee 0 allocs.

It is quite do-able. Lots of static declarations, basically write C with classes. V-tables ended up being non-trivial in size, but what can you do, GUIs and all that. Possibly the best (only?) good use of inheritance hierarchies.

256KB memory, the UI only had 60KB or so available for it IIRC. We also had a scratch pad available over a super slow bus of a couple megs, but it couldn't be used too much or we'd drop frames and we loved our 30fps v-sync'd performance.

Re: Generics in C without void* or macros – enabled by psychec

#63
post #52

I don't really understand what the point of all this is, and why anyone would consider using this in a real-world application they're developing. There's already a C-like language which lets you write type-safe generic programs: it's called C++! And if for some reason you really want or need to restrict yourself to using C language features (almost) exclusively, you can disable RTTI, exceptions, and use a technique t…

Generics != templates

Good point!

Re: Generics in C without void* or macros – enabled by psychec

#64
post #44
post #2

You should never typedef a pointer to an object. That’s common knowledge amongst experienced C developers and an immediate red flag, even for myself normally welcoming of anything built with Haskell.

I agree that it's something you shouldn't do, but that's just an opinion. Many C programmers are fine with it.

Yeah it's not like something 'bad' is going to happen.

I typedef function pointers when they get too verbose. Otherwise not. But it's not the mole hill I'd choose to die on either.

Re: Generics in C without void* or macros – enabled by psychec

#65
post #46

Earlier quoted context omitted.

I also think it is rather strange for many projects to continue with C, esp for large projects, where c++ offers much conveniences to the programmer. IIRC gcc only recently started allowing c++ in it's source, and I wonder if emacs allows it still in it's source.

Exceptions are a major point of contention. Most of the conveniences C++ offers to the programmer are not possible without exceptions, and non-local transfer of control is not just a huge departure from C, it's one that is hard to gradually transition to.

[deleted]

Re: Generics in C without void* or macros – enabled by psychec

#66
post #61

Earlier quoted context omitted.

It's easy to not write constructors that can fail. The major conveniences like templates, RAII, overloading, algorithms, lambdas, virtual functions, etc. work fine without exceptions.

It's doable to write constructors that don't throw exceptions; writing constructors that can't fail is not possible for a large fraction of the useful space of constructors. If your constructors fail without throwing an exception, much of the usefulness of RAII goes away.

The traditional approach would be to have an empty state that the object can be put into, ie. classic two-step initialization. This isn't usually too hard since you often need an empty state you can put that kind of object into when it's moved from anyway. Another one is to have a private constructor called from a static function returning a std::expected.

How would that make the usefulness of RAII go away?

Re: Generics in C without void* or macros – enabled by psychec

#67
post #2

You should never typedef a pointer to an object. That’s common knowledge amongst experienced C developers and an immediate red flag, even for myself normally welcoming of anything built with Haskell.

You should never hide a pointer to a type with a typedef.

Re: Generics in C without void* or macros – enabled by psychec

#68

Type generic expressions [1] already exist in C11. You can do this without a special compiler front-end if you need it, you would just need to define each variant by hand. These are supported in GCC and Clang with the -std=c11 flag. [1]: http://www.robertgamble.net/2012/01/c11-generic-selections.h...

I developed these ideas a bit further with the use of XX macros, which allow you to make a set of functions generic across some list of types. There can be real performance wins to this over void*: https://abissell.com/2014/01/16/c11s-_generic-keyword-macro-...

That looks handy. I got bored one day and built a fluent interface: http://flukus.github.io/fluent-interfaces-for-c.html

Re: Generics in C without void* or macros – enabled by psychec

#69
post #61

Earlier quoted context omitted.

It's doable to write constructors that don't throw exceptions; writing constructors that can't fail is not possible for a large fraction of the useful space of constructors. If your constructors fail without throwing an exception, much of the usefulness of RAII goes away.

The traditional approach would be to have an empty state that the object can be put into, ie. classic two-step initialization. This isn't usually too hard since you often need an empty state you can put that kind of object into when it's moved from anyway. Another one is to have a private constructor called from a static function returning a std::expected . How would that make the usefulness of RAII go away?

The whole point of RAII is that the scope of the variable is identical to the liveness of the resource. Two step initialization makes that no longer true.

Re: Generics in C without void* or macros – enabled by psychec

#70
post #69

Earlier quoted context omitted.

The traditional approach would be to have an empty state that the object can be put into, ie. classic two-step initialization. This isn't usually too hard since you often need an empty state you can put that kind of object into when it's moved from anyway. Another one is to have a private constructor called from a static function returning a std::expected . How would that make the usefulness of RAII go away?

The whole point of RAII is that the scope of the variable is identical to the liveness of the resource. Two step initialization makes that no longer true.

That's not quite right since (1) it's about object lifetime, not variable scope (think of the elements of a vector), and (2) the liveness of a resource is not generally identical to the lifetime of any object because of things like two-step initialization or moves.

    std::vector v; // v's lifetime begins
    // currently owns nothing, exactly as in two-step initialization
    v = other_vector; // resource #1 becomes live
    v = std::move(another_vector); // resource #1 dies, resource #2 becomes live
    return std::move(v); // resource #2 now owned by returned object, will outlive v
    // v's lifetime ends
I'd say RAII is more about making sure every resource always has an owner and that when an object dies, all the resources it owned are cleaned-up. And that works fine with two-step initialization.
Post reply on HN