Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
Posted Jun 2, 2011 9:44 UTC (Thu) by Cyberax (✭ supporter ✭, #52523)In reply to: Object-oriented design patterns in the kernel, part 1 by juliank
Parent article: Object-oriented design patterns in the kernel, part 1
In C you _have_ to manually ref/unref things (and get hard-to-detect errors when you unbalance them). In C++ one just uses shared_ptr (or one of other smart pointers) to do it _automatically_ - it's not possible to unbalance shared_ptr (at least without trying hard to do it).
That's not a workaround - that's a feature, and a wonderfully nice feature at that. A couple of lines in C++ can easily replace 5-10 lines in C.
Also, why would you suppress default constructors? They work just fine, even with shared_ptrs.
Posted Jun 2, 2011 9:58 UTC (Thu)
by juliank (guest, #45896)
[Link] (12 responses)
Another problem is ABI stability. It might be possible to get some more stability by suppressing anything default and allowing only pointers to objects to be taken. The safer option is to use d-pointers in the classes, but this is all very complicated compared to declaring an incomplete type in C.
Posted Jun 2, 2011 10:08 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (11 responses)
Why? A class should not be constricting its users, unless it's necessary. If your class should be used ONLY with refcounting, then intrusive_ptr is a better solution. C++ is just fine with refcounting, just learn to use C++ correctly.
ABI stability is about on the same level as in C. Just use incomplete classes, they work EXACTLY like in C.
Posted Jun 2, 2011 10:16 UTC (Thu)
by juliank (guest, #45896)
[Link] (10 responses)
> If your class should be used ONLY with refcounting,
> C++ is just fine with refcounting, just learn to use C++ correctly.
> ABI stability is about on the same level as in C.
Posted Jun 2, 2011 10:26 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (9 responses)
>C++ just does not allow me to do this in a sane way, so it's already disqualified for long-term library projects.
Please, stop spreading FUD.
>> If your class should be used ONLY with refcounting,
Can you point me where reference counting is described in the C99 Standard?
>If you like std::shared_ptr<MyObject> everywhere, then yes, it works. But it looks like an ugly peace of shit when compared to a reference counting C library.
Why would you need it? If you want an opaque interface, then do it exactly like in C. If you want a _sane_ interface then provide full type definitions and let user to decide what to use (shared_ptr, auto_ptr, etc.) and/or provide built-in refcounters and generic AddRef/Release functions.
>Call a method on an incomplete class.
You can't call a method of an incomplete class (duh, it's _INCOMPLETE_). But you can pass it as a parameter to a function/method. Just like in C.
Posted Jun 2, 2011 11:12 UTC (Thu)
by juliank (guest, #45896)
[Link] (8 responses)
Posted Jun 2, 2011 13:19 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (4 responses)
Then there is COM. There are COM-interfaces in Windows which are stable since _1993_ (the ones that deal with OLE) and that's kinda hard to beat. And COM maps directly into C++, COM-interfaces are just pure C++ classes. AddRef/Release can be managed using smart pointers and QueryInterface is dynamic_cast<> reimplemented manually.
Yes, designing stable C++ interfaces requires some forethought. But pure C interfaces require no less forethought.
Posted Jun 2, 2011 20:14 UTC (Thu)
by pr1268 (guest, #24648)
[Link] (3 responses)
I had asked that my earlier post not be construed as an attempt to start a language war, and, guess what? We now have a language war. Sigh. At least this one has been fairly tame. If there's anything nice about the above discussion, it's that I've learned a lot about exception-handling programming. Thanks! ;-)
Posted Jun 2, 2011 22:24 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (1 responses)
Posted Jun 3, 2011 8:10 UTC (Fri)
by marcH (subscriber, #57642)
[Link]
Posted Jun 9, 2011 16:29 UTC (Thu)
by jd (guest, #26381)
[Link]
Posted Jun 2, 2011 21:46 UTC (Thu)
by cmccabe (guest, #60281)
[Link] (2 responses)
I'm pretty sure private fields are not part of the ABI in Java, either. Your jar files will continue to work when someone changes private fields in a different jar. It's a nice feature and a lot of modern programming languages have it.
And as you noted, C has it as well. Private stuff stays private in C (as opposed to C++.)
C.
Posted Jun 2, 2011 23:45 UTC (Thu)
by Cyberax (✭ supporter ✭, #52523)
[Link] (1 responses)
There's a nice description here: http://wiki.eclipse.org/Evolving_Java-based_APIs_2
The fact that Java bytecode is essentially a lightly-parsed source code helps immensely.
Posted Jun 8, 2011 19:22 UTC (Wed)
by marcH (subscriber, #57642)
[Link]
You cannot have your cake and eat it.
Object-oriented design patterns in the kernel, part 1
> They work just fine, even with shared_ptrs.
You may want to restrict users to use only shared_ptr, in order to have a controlled way to reference things. Reference counting just feels completely unnatural in C++.
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
A user should never know the size of an object, unless it's necessary. C++ just does not allow me to do this in a sane way, so it's already disqualified for long-term library projects.
> then intrusive_ptr is a better solution
Not part of C++.
If you like std::shared_ptr<MyObject> everywhere, then yes, it works. But it looks like an ugly peace of shit when compared to a reference counting C library.
> Just use incomplete classes, they work EXACTLY like in C.
Call a method on an incomplete class.
Object-oriented design patterns in the kernel, part 1
Why?? Opaque object pointers are nice for some parts of ABI, but internally they are rarely required.
C++ allows to do it EXACTLY like in C. You just use forward declarations. C++ won't allow you to use copy constructor unless you have full class definition, so no difference here as well.
>> then intrusive_ptr is a better solution
>Not part of C++.
Pass an incomplete structure by value in C.
> Why?? Opaque object pointers are nice for some parts of ABI,
> but internally they are rarely required.
In user space code, at least 99% of all ABI should be opaque. There should be no inline code (and thus no templates), no complete types, the only things there should be are functions and incomplete types.
Everything else is going to fail. Even in Qt, where they try harder to avoid such problems, we still have an ABI that only lasts 4 years (Qt3) or is expected to last 6 years (Qt4). In other parts of the world, we have ABI breaks in every minor release (V8), or all few months (APT).
C ABIs in contrast can last much longer, as evident by the fact that GLib 2 was released in 2002, and did not have any ABI break yet. Of course, there are also bad C ABIs, such as Python's, which are allowed to break with every release, but C makes it much easier to create a consistent long-term-stable ABI than C++.
> You can't call a method of an incomplete class
> (duh, it's _INCOMPLETE_). But you can pass it
> as a parameter to a function/method. Just like
> in C.
But then you're in C world again, and have no advantage of using C++.
In C, the struct can be incomplete, yet I can call functions on it which can be virtual (methods) and other functions, all using one common interface, via functions, such as the following two, defined in the my_object.c.
Object-oriented design patterns in the kernel, part 1
struct MyObject {
int some_internal_int_field;
void (*method_a)(MyObject *o);
};
int my_object_function_a(MyObject *o)
{
return o->some_internal_int_field;
}
void my_object_method_a(MyObject *o)
{
o->method_a(o);
}
The external world only sees the header file:
typedef struct MyObject MyObject;
int my_object_function_a(MyObject *o)
void my_object_method_a(MyObject *o)
The language coming closest to the optimum is Vala. Private fields are not part of an objects ABI, neither is (for callees) whether a method is virtual or not.
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1
> part of an objects ABI, neither is (for callees) whether a method is
> virtual or not.
Object-oriented design patterns in the kernel, part 1
Object-oriented design patterns in the kernel, part 1