LWN.net Logo

Day: GNOME OS

Day: GNOME OS

Posted Aug 8, 2012 18:30 UTC (Wed) by mathstuf (subscriber, #69389)
In reply to: Day: GNOME OS by juliank
Parent article: Day: GNOME OS

As someone who likes coding guarantees with the language rather than logic (Haskell is nice in this regard, but I'm still mainly doing C++), C can't help in many places. Sure, there are ways to enforce things socially with code reviews and such, but it's time consuming to check stuff when I can have the compiler do most of that work for me. C-style casting is also no substitute for static_cast and dynamic_cast.

I do agree that C++ has warts (mainly where they tried to be compatible with C…and didn't quite make it[1]). Not specifying an ABI was silly (an FFI would have been much better). Common stuff is finally in the standard (much is also just boost:: -> std:: moves, so migration once we support C++11 more widely is largely just a rename in a bunch of typedefs in the codebase).

As for build times, yes, it's higher, but I don't really notice that much of a practical difference and what difference there is is well worth the extra safety the code has. It also helps to put most of the heavy Boost template magic in its own source file helps to minimize rebuilding of that file (e.g., the Boost.Spirit grammar in its own file (getting flex/bison working on Windows is *lots* of fun…I'll take Boost TYVM)).

[1]A fun one:

struct A { A(int) { /* … */ } int a; };
typedef float B;
int main(int argc, char**) { A a = (A)argc; B b = (B)argc; }

The A ctor gets called here where B is a C-style cast.


(Log in to post comments)

Day: GNOME OS

Posted Aug 8, 2012 20:20 UTC (Wed) by nix (subscriber, #2304) [Link]

I don't see how that's an incompatibility with C. struct A has a constructor, so it's not a POD type and can clearly not exist in C at all.

I'd not call implicitly calling constructors on casts to be much of a wart: if you didn't call the constructor, you'd end up with a non-initialized object and break things. The only alternative (as implemented if you declare the constructor explicit) is to ban a cast in that situation entirely, which means you make the casts to A and B look different merely because one is a POD type and the other is not, which is an implementation detail which the users of the types should not have to know.

Implicit conversions *are* full of horrible warts (such as the crudeness of the no-implicit-conversion-chains rule and *everything* about the syntax of 'operator random-typename'), but this is not one of them.

Day: GNOME OS

Posted Aug 8, 2012 20:30 UTC (Wed) by mathstuf (subscriber, #69389) [Link]

It's not a compatibility with C issue, but it happens because C++ tried to be fully C compatible. If you're doing C casts in a template or something, it acts differently based on whether the template type is POD or not. If C++ had just said "we don't support C casts" this wouldn't be an issue. Plus, if you do rely on C casts for some (C++ POD) struct for some reason, you need to document the struct that it needs to stay a POD struct.

I really would have liked 'implicit' to be the keyword rather than 'explicit' as well, but alas…

Day: GNOME OS

Posted Aug 8, 2012 23:01 UTC (Wed) by nix (subscriber, #2304) [Link]

I think everybody agrees with you on that last point (and perhaps similarly for 'virtual', though changing that to 'nonvirtual' would violate the 'you don't pay for what you don't use' principle, so perhaps not), but such is the backward-compatibility burden...

Day: GNOME OS

Posted Aug 8, 2012 23:47 UTC (Wed) by mathstuf (subscriber, #69389) [Link]

Not sure I feel the same about virtual because of the "only pay for what you use" principle. Another thing: something like a 'delayed const' (similar to 'final' in Java IINM) so that you can modify a variable and then 'constify' it so that it doesn't change after that point (something the compiler could enforce rather than assignment to a const& and relying on people to not use the pre-const& variable after).

Day: GNOME OS

Posted Aug 10, 2012 7:49 UTC (Fri) by nix (subscriber, #2304) [Link]

The 'delayed const' sounds like a finer-grained 'mutable'.

(But don't mention Java. Java's lack of constness is *awful*. More than once I have introduced horrible bugs because I accidentally modified a hash key due to the silent aliasing and lack of const of java.util.Map -- meanwhile such bugs never ever happen in the STL, not due to its nifty space-age genericity, but simply because its data structures copy the types handed into them, and won't give you something back that shouldn't be modified without a const on it. For that matter I have written data structures in poor old crude C with the same 'always copy, use const' rules as the STL, and *they* never suffered from this either.)

Day: GNOME OS

Posted Aug 10, 2012 8:10 UTC (Fri) by jezuch (subscriber, #52988) [Link]

> But don't mention Java. Java's lack of constness is *awful*.

Yes, that's one of the very few features that I truly miss in Java. There are workarounds like defensive copies and immutable wrappers but they're no fun.

Day: GNOME OS

Posted Aug 10, 2012 17:42 UTC (Fri) by mathstuf (subscriber, #69389) [Link]

Also typedefs. I hated using Strings for everything and 5 parameters all of String to Android APIs means having to look up what the order is. At least the ordering is consistent where I used it (unlike, e.g., PHP)

Day: GNOME OS

Posted Aug 10, 2012 10:57 UTC (Fri) by jwakely (subscriber, #60262) [Link]

If C++ hadn't supported C casts (or had used a FFI for C interop, as you suggested above) it would never have achieved the success it enjoys today, which only happened by building on C's popularity and success. C compatibility is sometimes a millstone around the neck of C++ now, but without it this discussion probably wouldn't even be happening.

Without supporting C-style casts you couldn't write something as simple as this and have it be valid in both C and C++:

  int* p = (int*)malloc(n*sizeof(int));
It's the right design for a C-style cast to invoke a user-defined conversion if one exists, for the reasons nix gives. Why would you want to use C-style casts in templates anyway? Code in templates doesn't need to be C-compatible. You can't cast between arbitrary POD types anyway, in C or C++. Can you give an example that shows what you mean?

Day: GNOME OS

Posted Aug 10, 2012 11:09 UTC (Fri) by hummassa (subscriber, #307) [Link]

You can't c-cast from a POD type to another, but you can c-cast from a pointer-to-any-type to another (even if you have to cast to void* in the middle).

Day: GNOME OS

Posted Aug 10, 2012 11:18 UTC (Fri) by jwakely (subscriber, #60262) [Link]

Was mathstuf's statement "it acts differently based on whether the template type is POD or not" talking about casting pointers?

Day: GNOME OS

Posted Aug 10, 2012 14:59 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

You can always do:
>int *p = reinterpret_cast<int*>(malloc(n*sizeof(int))

Day: GNOME OS

Posted Aug 10, 2012 15:51 UTC (Fri) by jwakely (subscriber, #60262) [Link]

How would that be valid C?

Day: GNOME OS

Posted Aug 10, 2012 16:54 UTC (Fri) by Cyberax (✭ supporter ✭, #52523) [Link]

It's not, and that's the point. C++ could have avoided lots of warts caused by C-compatibility without losing in functionality.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds