5 ms·
Yep, I love objective-c, sure with a few syntax frustrations: ([[]]). I don't do any apple work anymore, but I'd love to be able to use named parameters, and it
by monkeycantype 7y ago
Yep, I love objective-c, sure with a few syntax frustrations: ([[]]). I don't do any apple work anymore, but I'd love to be able to use named parameters, and it's message passing in plain c. Every couple of years I waste an enjoyable few days on exploring github looking at hobby project to bring smalltalk features to c.
So if anyone has any recommendations of oo in c projects i could checkout I would appreciate it.
- CoolGuySteve 7y agoSimilar to how the posix API works with struct arguments for extensibility reasons, in C++ you can pass structs by reference with named arguments and init them in place, like: void dothing(const dothingArgs& args); ... dothing({ .arg1 = 1, .arg2 = someOtherThing }); Register colouring should make it run the same as regular args for the most part in optimized builds. This has two benefits: 1) Changing the order of the struct args won't introduce ordering bugs like with function signatures. 2) Default arguments are more explicit and there's less chance of breakage as the argument list grows over time and gets more default values, as tends to happen. And 2 drawbacks: 1) Passing complex types as arguments without copying can be tricky. 2) The compiler errors don't tell you specifically which arguments are broken, at least in g++. This one sucks the most imo.
- saagarjha 7y agoIs this a C++ feature or an extension borrowed from C?
- CoolGuySteve 7y agoIt's part of C++20 but is an extension borrowed from C in most C++11 compilers. I've been able to do it in g++ for at least 7 years now. The combination of type inference, pass by reference, and aggregate initialization shown here is only possible in C++, I think. https://en.cppreference.com/w/cpp/language/aggregate_initialization https://en.cppreference.com/w/cpp/language/aggregate_initial...
- saagarjha 7y agoOoh, it nice to see that it's been officially added!
- alexhutcheson 7y agoNote that what's been added is a subset of the C99 behavior - there are a bunch of things that work in C99, but are not allowed (and might introduce undefined behavior) in C++20. See the "Design Decisions" section of this document for a summary of differences: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0329r0.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p032...
- flohofwoe 7y agoThe C99 designated initialization (where you give member names in the initialization) AFAIK only works in clang when compiled in C++ mode, gcc and MSVC doesn't appear to support it. C++20 will get a fairly limited subset of the C99's designated init though.
- voldacar 7y agoForgive what may be a dumb question (I'm not a C++ user), but why should dothing() accept a reference to struct? Why is this better than just making it accept a struct like void dothing(const dothingArgs args); and then just passing it an anonymous struct that only briefly sits on the stack when you call dothing({ .arg1 = 1, .arg2 = someOtherThing }); A reference would make sense if you already have a struct sitting somewhere else in your program, but if you're putting together the struct at the time you call the function, wouldn't it make more sense to just pass by value?
- codesushi42 7y agoBecause otherwise the struct will be copied when the function is called. Though your question is kind of getting at r-values and move semantics, which is a solution to prevent copying the temp value both when calling the function and in its execution. You can read about it because it will take too long to explain it here.
- voldacar 7y agoThanks, I'll read about that
- alexhutcheson 7y agoFYI - designated initializers in C++20 require that the designators appear in the same order as the field declarations in the struct or class[1]. If the designators aren't in the same order as they appear in the struct declaration, the behavior of the designated initializer statement is undefined. Note that this is different from C - C99 supports a broader variety of designated initializers than C++20 - there's a table in the document I linked. Because of this, the statement "Changing the order of the struct args won't introduce ordering bugs like with function signatures" is actually not true - I know from experience that clang will sometimes just silently leave the struct uninitialized, which could lead to nasty bugs. The behavior can also vary between optimized and debug builds, so it might not surface when you run your unit tests, etc. I believe that once C++20 is standardized both compilers will probably introduce warnings or errors to let you know when you've unintentionally initialized fields out of order, but for right now the feature is a landmine and I wouldn't recommend using it. [1] http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0329r0.pdf http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p032...
- CoolGuySteve 7y agog++ gives an error if you do things out of order. But what I meant is that this is still better than a regular function signature. ie: int f(int a, int b) changed to f(int b, int a) works but the arguments will be wrong if the call site doesn't change. f({ .a = 1, .b = 2}) will fail at the call site when the struct is changed to expect f({ .b = 2, .a = 1}) But yes, while ideally the order of declaration wouldn't matter, C++ is going the other way, being extremely strict about initialization order to avoid complex constructor errors. I wish POD types would be treated differently for those warnings/errors.
- alexhutcheson 7y agoMakes sense - I misunderstood what you meant by order. It’s good to know that g++ gives you an error if the designator are out of order - thanks for pointing that out.
- bitwize 7y agoA number of early attempts at OO in C, like BOOPSI on Amiga and Xt Intrinsics on Unix, used varargs to pass a list of tag-value pairs to functions and methods, allowing for both named parameters and initialization lists for complex objects.
- flohofwoe 7y agoIn C99 you can sort-of get named optional parameters via designated-initialization, e.g. if a function takes a a struct "person_t" by value you can write: my_func((person_t){ .name = "John Doe", .age = 33 }); ...by-pointer also works: my_func(&(person_t){ .name = "John Doe", .age = 33 }); Any struct items which are not assigned a value will be zero-initialized (I wish it would be possible to define default-values in the struct declaration though). I question the value of bringing OO principles into plain C though ;)