A Eulogy for Objective-C (2015)
academy.realm.io
academy.realm.io
I had to choose, and knew little technically about either. But Stepstone wanted royalties for developing a clone of ObjectiveC. I contacted AT&T's lawyer (William Ryan) who said I didn't need a license to develop a clone of C++. I asked if I could call it "C++" and he said sure. He laughed, and thanked me, saying I was the only one who ever bothered to ask.
So C++ it was, and Zortech C++ came out in 1988 (the first native C++ compiler for DOS, and arguably at all. g++ was out, but as a beta.)
The action for programming at the time was on DOS, and C++ pretty much exploded with the availability of an inexpensive, fast, native compiler for DOS. The comp.lang.c++ traffic grew by leaps and bounds, and comp.lang.objectivec faded away.
Reminds me of discussing music piracy with my musician friends, all of whom fervently wanted to be sufficiently popular to actually HAVE people pirate their stuff!
(Not the piracy part, the "you really want people to listen to you, first" part...) :-)
(also i wonder if Stepstone had a leg to stand on regarding implementing a clone of Objective C... you couldn't call it Objective C as i guess they had a trademark over it, but what else would they license?)
So if anyone has any recommendations of oo in c projects i could checkout I would appreciate it.
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.
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_initial...
C++20 will get a fairly limited subset of the C99's designated init though.
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?
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.
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/p032...
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.
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 ;)
All the old ObjC stuff still works, though, there's nothing stopping you using it. I released an app recently that was 50/50 ObjC/Swift (for a few weird reasons) recently and it's really painless in comparison to some other modern stacks.
While Apple has released a Swift only framework, its very much in alpha state.
Objective-C will live on strongly for another 5 years, and even in its twilight after that will continue going on.
I'll be writing in it until I die haha.
[apple4ever setGraveStone: @"here lies apple4ever" setBirthYear: 1950 setDeathYear: 2050];
Right now, there are applications that you can only build in Swift and some you can only build in Objective-C.
The closure syntax also relates to C compatibility. Because the Clang blocks extension isn't an extension to Objective-C, but to C. The syntax matches C's function pointer syntax, just replacing the * with ^. ^ was chosen because (A) it has no unary form in C, and (B) it can't be overloaded in C++.
As someone with the unusual distinction of learning to code with ObjC, I found the syntax super helpful as a newbie.
Everything looked distinct (e.g. in other languages blocks might only differ from hashmaps by their context), everything was verbose as if explained to a child (Thing *thing = [Thing thingByConvertingOtherThing: otherThing];) and so on.
This person has no taste. I don't need to read any more.
(I'm kidding. To each their own, but I do hate Obj-C)