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

I think that at least for standard C and certainly for C++, the type system is meant to be nominal. Unnamed structures are better understood as having a unique but unnameable type. Anonymous structures are just weird and probably better understood as being just a syntactic aggregation without any type level connotation (C++ doesn't have anonymous structures; it does have anonymous unions though).


I agree it's mostly nominal, but anonymous structs using structural typing semantics are incredibly useful. Consider for instance this general function pointer macro [1], which you can use with any number of arguments like so:

    fn(int, char, double) f = &functionMatchingSignature;
and which you can invoke with just:

    double d = f.call(arg0, arg1);
and it type checks correctly and ensure the correct argument types are applied. Way better than the typical, double(*f)(int, char). You can go even further and implement full closures in C11, curried and non-curried, and it's mostly all type safe using anonymous structs (see the rest if the repo for the work in progress).

[1] https://github.com/naasking/cclosures/blob/typed-clo/closure...


I appreciate any form of clever preprocessor abuse, but I fail to see how the above, by itself, is an improvement to the fn pointer declaration syntax and why do you need the unnamed (not anonymous btw) struct. Couldn't you make the macro espand to a function pointer instead of one wrapped in a struct? Is it because you want to manipulate all such function pointers under some sort of static polymorphism and you require a uniformly named field?


Every other value declaration in C is <type> <name>, but function pointer values are different because the name to which its bound is right in the middle of the type. I understand the historical reasons, but it's unnecessarily obtuse, and this fixes that. Declarations of function pointer values are now just like any other value.

The macro can't expand to a raw function pointer type without including the name to which it's bound in the macro arguments, once again introducing this obtuseness. Even worse actually, because the bound name is now indistinguishable from the types, where the ordinary syntax, while noisy, clearly distinguishes names from types.

This style also matches the closure declaration style, ie. clo(T0, T1, ...), thus providing a seemless transition from function pointer values to actual function values which can carry environments.


Oh, right, now I get it. Another option is for the macro to define a separate function type typedef (properly mangled with the line number) for the function type and then use it to define a pointer to it.


> Another option is for the macro to define a separate function type typedef (properly mangled with the line number) for the function type and then use it to define a pointer to it.

Yes, but this requires forward declarations of the function type, which seems unnecessary. I can now just write:

    void sort(int* vals, int vcnt, fn(int, int, int) compare);
    int* filter(int* vals, int vcnt, fn(int, bool) clause, int* rcnt);
without any forward declarations, and it's still immediately obvious what's going on. This approach makes C semantically a little more like a functional language without sacrificing a single thing people love about C (I hope).




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

Search: