Trying to use Gtk-rs made me see that lifetimes still need a bit of ergonomics improvements for any reasonable GUI programming in Rust. In fact some of the non-lexical lifetime improvements proposal are actually the exact problem I had related to callbacks handling.
By the way, interfaces in C++ are pure abstract classes, only with pure virtual methods, without any private data.
The only thing coming to my mind is Qt, but development of Qt Widgets has basically stopped in favor of Qt Quick, and for cross platform GUIs there's other options like Xamarin or Electron (not that I'd prefer either).
Xamarin uses C and C++ to bind the nice .NET code into the platforms they support.
Qt Quick is just the layout engine, many important parts of the stack keep being C++.
Apple's Metal shaders are C++14.
On Android Vulkan is only exposed to the NDK and SurfaceFlinger and hardware compositor are in C++.
Plus if you compare compare Rust with Objective-C, Swift, C#, Java, the productivity story regarding GUI programming doesn't get better than when comparing with C++, on the contrary.
Also, Qt Widgets isn't deprecated, it's just considered pretty much complete.
Well, this doesn't really influence the language programmers have to use to build applications, considering you can use C++, C#, VB.NET, or JavaScript to your heart's content.
Windows GDI is a C API, but not every application using it is written in C.
Yeah it will eventually get there, but it is a disservice to Rust to promote the language as it if was already possible today to do it, when most toolkits are still WIP and lifetimes aren't that friendly for the usual GUI coding patterns.
This will only lead to disillusion and shy away contributors that might otherwise enjoy using the language, if they understood the current state before diving in.
All of the new Windows 10 UI is C++ (using the UWP XAML framework, which is implemented in C++). The paper says metaclasses are a way to avoid language extensions like UWP's C++/Cx, which adds C# things like "interface" and "event" to C++.
Disclosure: I work at Microsoft.
Things went pretty silent there.
https://github.com/Microsoft/cppwinrt
https://msdn.microsoft.com/en-us/magazine/mt745094.aspx
"Teams within Microsoft are already starting to use C++/WinRT to build WinRT components for the OS itself."
My point was more about Blend, XAML tooling support and official integration into Visual Studio.
So, all the things that C++/CX has today, but C++/WinRT was still catching up when that information was made public.
C++ has pure virtual classes, as well as the pimpl idiom. Both decouple the class definition from the interface.
Yes, they have a theoretical runtime overhead. To get rid of that, you'd need a special "sizeof" member function instead of the list of private member variables. I guess that would be possible to introduce to save compilation times.
To save others the arduous trial of googling it like I had to: http://wiki.c2.com/?PimplIdiom
In the past I've sometimes taken this a step further and defined a pure abstract class plus factory function in the header and then defined a derived implementation class in the source file, kind of a COM lite approach. (Is there an agreed name for this pattern? I don't doubt that, like most things I've invented, it was first thought of in the '60s or '70s. :P )
It's good for libraries because it separates all implementation details from the public interface while adding very little overhead for the library dev. Not so good for smaller utilities which are more natural as header-only classes, though.
These days I don't bother with that kind of messing around until it actually becomes necessary, which it almost never does. I feel like my code's become way simpler over the years.
I wouldn't know, but some Dylan book taught me that, along the abstract-concrete dimension, there are not two, but three kinds of classes:
- concrete, instantiable
- abstract, instantiable
- abstract, not instantiable
where a type <foo> is instantiable if a function make(<foo>) exists (because <foo> is abstract, that function must return an instance of a subclass of <foo>)That factory function makes your abstract class instantiable.
Also, in Java, Foo would be an interface, and that factory would be a FooFactory.
I wouldn't say that it's been great. The evolution of C++ is insanely slow.
From my standpoint, I'm _still_ trying to get my head around all the ramifications of what has arrived in C++-11 (and it's a lot!). And I still have '14 and '17 to plow through too. '20 will be here before I know it. So for me, there is so much to absorb.
To my eyes the C++ leadership has done a great job at setting up standards processes for regularly delivering new versions and the compiler community has done an amazing job at keeping up too.
I expect to see more movement in the world of standard libraries which is where C++ still feels like a desert compared to other languages.
But yes it definitely is not fast when compared to other newer language communities.
The only language today with more independent implementations than C++ is C. Compared to C, C++ evolution is not slow — processes involving so many implementers are inherently not in fast-forward mode.
Most major languages only have a handful of active implementations, if it's not just one implementation. Most don't have specs.
Moving fast (and breaking things) is just not what the standardization committee does, and that's fine. They can move faster since C++11/14, but sometimes you really don't want a giant moving target with new features all the time. I think their approach works for the kind of environment you find C++ used in.
The Rust community doesn't endorse your flavor of evangelism here. It's not a holy war.
The one topic to consider is this - is there a world where a language's existing code base is so large and the community so diverse that even _you_ would hesitate to break things for them? And at the same time, doesn't it make sense for that community to keep marching forward?
Yes the language has baggage and the path forward isn't easy, but there are still paths ahead for C++.
My advice to the rust community. Model yourself after the C++ strategy of evolution. Do not repeat the mistakes of the Python 2->3 world or the perl 5->6 world or what appears to be happening to Go. Don't break the past.
Pointers and virtual class, why do you need the definition to use the interface? Could you provide more details?
> The basic problem with C++ is that it has heavy encapsulation without memory safety.
It's pretty simple to write memory safe code in c++, and encapsulation is a feature that not mandated in c++ code.
It's not simple to write memory safe code in C++, otherwise we would have a lot fewer vulnerabilities in C++ codebases.
Using the STL after using Java collections or Qt collections is a shock. I think there really needs to be a "Safe STL" in addition to "Performant STL" that performs range checks. You simply cannot recommend using the STL for safe code.
SaferCPlusPlus[1] provides compatible, memory-safe versions of the most commonly used STL containers. (The compiler switches mentioned by others add range checking, but do not, for example, catch use-after-free bugs.)
> > It's not simple to write memory safe code in C++, otherwise we would have a lot fewer vulnerabilities in C++ codebases.
Using SaferCPlusPlus, it now is simple to write memory-safe code in C++. And it's not much different from writing traditional (unsafe) C++ code.
[1] shameless plug: https://github.com/duneroadrunner/SaferCPlusPlus
indeed. for gcc, you can compile stuff with '-D_GLIBCXX_DEBUG' to enable random-iterator bound checks. moreover, random-access-iterators do have the 'at(...)' stuff available for bounds checked access to the containers.
but, yeah, a standardized way would be very useful.
It is also possible to explicitly enable them in release code.
https://blogs.msdn.microsoft.com/vcblog/2017/06/28/security-...
Why?
I prefer having a free-standing generic find function as opposed to it being implemented in each and every container. Even better example: copy. You can use it with containers, but also with input/output streams (using stream iterators).
You mentioned safety, is iterator invalidation bothering you?
Most popular languages don't allow putting objects on the stack and thus have at least comparable overhead anyway.
If you are sensitive to these overhead, you pretty much already only have C++ as your only choice. Or maybe Rust, but I do not know rust well to comment if Rust does not have such overhead.
> It's not simple to write memory safe code in C++
No, in C++11 or newer, memory safe code is the default. That's the design goal of the newer standards of C++. IMHO, memory safety is no longer a central issue for C++.
> a lot fewer vulnerabilities in C++ codebases.
This only applies to legacy code.
If you want dynamic dispatch, you don't use a virtual class, you use a "trait object". Basically it's a double pointer: a (pointer to vtable, pointer to data). Technically the C++ standard (as far as I know) doesn't define the exact implementation of this stuff, but in my understanding the vtable pointer is stored with the data.
There are pros and cons to each approach.
Is this referring to Rust? Then it sounds like it will have similar overhead as C++'s virtual functions.
I have been preaching how to write proper C++ code vs "nicer C" since the late 90's, but without much success, specially to enterprise developers.
Many of the so called modern C++ features were already possible with C++98.
As a good example, MFC 1.0 could have been like Turbo Vision, OWL, VCL, Qt and so on, but the test group from Microsoft found Afx too high level and wanted just a thin layer over Win16 thus it was reborn as MFC.
> I have been preaching how to write proper C++ code vs "nicer C" since the late 90's, but without much success, specially to enterprise developers.
In no practical sense is it easy then. Even if you find it easy to write perfect code, you still have to work with other people that don't and use libraries which have problems.
C++ has so many ways to shoot yourself in the foot I literally cannot think of a mainstream language that is actually more difficult to master. Would you say it was easy compared to Python, Java or JavaScript to write safe code in? Those languages have no undefined behaviour and they all have automatic memory management compared to C++.
However, the mechanisms for safer code are there, if one cares to use them in first place.
The usual set warnings as errors, CI build with static analyzers that break on failure, unit tests with sanitizers that break on failure.
But many companies don't care to set this workflow.
They also don't care for doing that for Python, Java or JavaScript as well.
JavaScript might have automatic memory management, but it has its own collection of WTF moments and implementation issues across browsers.
Java is way better, yet there is a reason why Java Puzzles are so entertaining.
While a tracing GC is much more productive than RAII/smart pointers, sometimes you also need to track down those references that prevent the collector to do its job.
Android developers have lots of "fun" doing that regarding context and activities.
One should not forget that safe languages only get us free from memory corruption, regarding safe code. There is still the whole spectrum of logical errors, specially bad in dynamic languages.
In any case, until we finally get a mainstream OS written in Swift, .NET Native, Rust or D, we need to make the best use of our tooling for low level system coding activities and in this regard C++ is so much better than C.
Because as much as I would like to use a safer alternative like Swift, D or Rust, as an ex-Pascal/Oberon user, they aren't there yet.
There isn't much Ada tooling available for those environments, and even using GNAT would be increasing project costs regarding having to implement ourselves stuff that we get for free with the SDK tools that support C++ out of the box.
exactly! C++11 only made it more pleasant to write.
Are you sure you're not referring to _C_ codebases?
This is more a limitation of the ABI than the language (and even then, only comes up if you are using multiple inheritance or have private virtual functions). Objective-C had the same problem, and then they introduced the non-fragile ABI: no language change was needed, just a compile flag.
(I do realize that there is some awkwardness in C++ if you attempt to declare these things in that private-decoupling sense; but to me the reason this is most brutal is not hiding of state, where we have solutions already, but being able to add and remove members without having to recompile users.)
I think in general these things are unrelated, unless you stretch the definition of memory safety rather far.
Also, you can hide things in C, just it's not always zero cost. Put private fields in a forward declared struct that's not implemented in any headers, use static for private functions (also outside of headers).
Is that true when using virtual methods from some virtual base class on an object created elsewhere?
Is this problem solvable at all without specifying the ABI?
C++ needs the full definition of a class, including its private members, before you can use its methods. This is a huge dependency headache. Most later languages have interfaces or traits or something to decouple class definition and interface definition. This looks like an attempt to deal with that. Of course, this is a retrofit, so it's going to be messy.
C++ has a lot of baggage. It may have exceeded its excess baggage allowance. The basic problem with C++ is that it has heavy encapsulation without memory safety. No other language has that. Either nothing is hidden, as with C, or the language is memory-safe, as is almost everything since C++.