I learnt C++ in 2018 and have no regrets
vishnubharathi.codes
vishnubharathi.codes
This was a big problem for me when I first started using C++. I don't remember it being too bad when I was just working on small projects and things I wanted to do at school. The problems started when moving past the "1-person" projects. Want to contribute to other projects? Chances are they all have very different build setups and configurations when it comes to building, testing, dependency management. That adds some friction even before you start taking a look at the actual code-base.
I understand that a lot of these problems can occur for languages as old as C++, but I wish the tooling was a little more opinionated and worked a little better at guiding newcomers into doing things in a nicer manner.
One can have an opinionated, canonical build system and still allow unorthodox things.
Maybe one can't reorganise the source tree layout because to do so would break our custom tooling / integration systems / interface with proprietary vendor tools. We can't change version numbering schemes because our packages already exist 'in the wild' and can't be changed mid-sequence without causing both technical and user pain.
Fundamentally: the codebase has worked perfectly well this way for the last 20 years; what's the business case for changing it (at potentially significant cost) just to be compatible with XYZ new tool that everyone is rallying behind?
In all seriousness, I think this is the only way. Yeah you may have forever to deal with it cross patching but let's face it, for big lumbering code bases, perfect backwards compatibility in the source tree is usually the smallest of issues, and the benefit of using standard tools far outweighs the cost of occasionally reinterpreting back-patches (if they are even possible.)
Staying in the cooking pot of ever larger proprietary and exotic hacks is how organizations grind to a halt.
Your assertion really depends on your definition of "widely supported". Jumping from fad to fad, however, is only effective as a way to waste time.
>Staying in the cooking pot of ever larger proprietary and exotic hacks is how organizations grind to a halt.
Using established build systems for C++, whether autotools or even plain makefiles, ensures that the project doesn't suffer from bit rot and developers can focus om developing code instead of wasting their time trying out every flavor of the month. And do note that the main reason C++ hasn't adopted any official build system is that each and every flavour of the month ends up being very horrible and very hard to maintain.
Yes, including CMake. If a build system is known for telling essentially all users that they are doing it wrong, that means the build system is the problem.
Yes. And there are codebases that are going to outlive thee shiny tool of the month (or the decade, even).
That hardcodes the source layout? I don't buy that a tool that's being sold for money would do that (precisely because there's no standardization in the C++ world; any tool that wants to have more than 1 customer will have to support more than 1 directory layout), and if the tools are internal then by definition you have the ability to make changes to them.
> Fundamentally: the codebase has worked perfectly well this way for the last 20 years; what's the business case for changing it (at potentially significant cost) just to be compatible with XYZ new tool that everyone is rallying behind?
Well, if you make adopting good tooling in C++ harder than switching to a language that already has good tooling, don't be surprised when developers do that.
I happen to work in a shop with problems that look somewhat like this. We have a non-trivial amount of legacy code, that we just don't have the resources or motivation to fix. In those cases, we've found that the cohesion of doing it the same (wrong) way everywhere is easier to work with than doing it the new way in some places.
If you work with proprietory hardware (think FPGAs), if you want to use the hardware, you have to use proprietory vendor tools, whether you want to or not.
> if the tools are internal then by definition you have the ability to make changes to them.
This misses the point. Having the technical ability to modify the tool does not equal having the real-world-practicability, business-case-defendable ability to change the tool.
> Well, if you make adopting good tooling in C++ harder than switching to a language that already has good tooling
The point is that in a 20 year, n-million line codebase, neither is "easy", and the pragmatic solution is to do neither.
In my experience, this just means they don't know how to do custom thing in Maven. Maven is very configurable; it can do pretty much anything you want, as long as you're willing to throw enough XML at it.
And if you are throwing a ton of XML at it, and your pom file starts to look like a nuclear disaster, that's a good sign that the custom thing you're doing isn't such a good idea after all.
They're not customizable, by design. I find people with this problem tend to be missing the option of using a multi-module project: if you need to build A, B that depends on A, C that depends on B and so on, the right way to model that in maven is to have those things in separate modules with dependencies between them. That way your dependency graph lives in the normal maven representation that anyone working on it can understand, and the within-module phase ordering continues to be what anyone working on will expect (compile before test before package, etc.)
Sure, so you need support for a multi-module project. Any serious build tool will have that.
Meson seems to be spreading pretty rapidly. After I was introduced to it a few years ago for work, I started using it as my default build system for C++ elsewhere and more C++ devs I know have started using it. I've seen it replace CMake and make at large companies for C++.
The tradeoff is that Meson takes a fairly rigorous "one correct way" approach to how you organize your builds. It doesn't prevent you from doing anything functional but what it forces you to do is very sensible, minimizes the potential for issues in diverse environments, and reduces the degrees of freedom Meson has to sort out. A prohibition on unfettered creativity, advisable or not, in how you manage your builds has turned out to be a blessing in my experience because it codifies what are very arguably best practices in code and then makes it easy to implement them.
I'm fairly agnostic on build systems -- I've probably used a dozen -- but Meson, even in its relatively youthful state, is the best C++ build system I've used so far in terms of getting things done quickly in a maintainable way that is easy to use for average programmers.
Basically, I wonder if you would recommend Meson as a build system for a mostly C project with maybe some C++ parts and some extra external tools ran on top.
CMake is the most used build system for C++. Meson doesn't even register. CMake is also 6th fastest growing language on github : https://fossbytes.com/fastest-growing-languages-in-2018-gith...
Even grabbing libraries from github, I was unsure if I should grab just the headers and DLLs, or import the entire tree and mashup my build scripts with theirs.
I wish I had stayed with it since college but now I feel I have to reach for something like Go or Rust just to get something shareable in reasonable time purely because of the tooling, whereas I would really like to use the C++ language itself specifically for working with win32.
Gonna be very hard to do. For the last 15+ years COM is essential part of WinAPI, and too many things in Rust conflict with COM: ownership, OOP, virtual tables, inheritance, they all too different.
Not just in Rust, in all languages, actually. You only have 2 good choices for complex platform-dependent windows development: either C++, or a microsoft's language with COM support embedded deep in the runtime, like VB6 or VBScript or .NET.
JavaScript is OK for platform-independent development with electron. For platform-specific i.e. WinRT not that good, .NET is just better, and MS put the JS libraries in maintenance mode: https://github.com/winjs/winjs
Python was never good. I’ve tried using winapi through C interop a few times, didn’t like it at all despite what I did wasn’t even too complex.
JavaScript has first class support on UWP. Of course WinJS is in maintenance BB mode. The future of JavaScript on UWP are PWA apps, with direct access to UWP APIs, no more need for WinJS, which was a Windows 8 library.
Python has supported COM with help from PyWin32 since ages. Hardly any different from VBScript.
When I search “Delphi DirectX”, I only find some Russian website last updated in 2009 and offering Direct3D 10.1 bindings. The newest one is 12, the oldest supported is 11.2.
When I search “Delphi Media Foundation” it’s better, finds bindings updated 4 years ago.
These COM-based technologies are among reasons why I sometimes still pick C++ even for new projects.
Also, in both cases just bindings are not enough, the frameworks are complex, need code samples, stackoverflow community, sometimes books, etc. There’re tons of resources on using these from C++, many from C#, very few for the rest of the languages.
> JavaScript has first class support on UWP
Win32 GDI also has first class support on Win10, just because it’s supported doesn’t mean it will go anywhere. I have doubts MS will continue with that support, they haven’t achieved much and need to do something else, e.g. include CEF in the OS.
> Hardly any different from VBScript.
The difference is that VBScript _is_ COM. All VBScript variables are VARIANT, all strings are VARIANT of VT_BSTR type, and all objects are IDispatch. The interop is not required, COM is already native to the runtime. I can write a COM server in a page long text file with *.wsc extension and VBScript inside, register it with regsvr32.exe, and consume from any language, e.g. `#import "progid:..."` in VC++. I’m not sure you can do same in Python.
Apparently you missed the news regarding PWAs in Windows and its support for native UWP. Again, WinJS got dropped, because it was tied to the Windows 8 programming model, which got improved on Windows 8.1, only to be replaced by UWP on Windows 10.
Win32 GDI actually has "we wish you were all using Win2D and DirectDraw" support on Windows 10.
Here are some examples of automating Excel with Python, http://pbpython.com/windows-com.html, hardly any different from using VBA.
In my first comment I wrote that COM became an essential part of WinAPI. Excel runs on Windows but it’s not Windows. DirectX on the other hand is in OS kernel, mayor parts are dxgkrnl.sys. Same applies to media foundation, Windows shell and clipboard, WMI, and many other OS components.
> which requires writing wrappers by hand, including in .NET, hence Managed DirectX, XNA and SharpDX projects.
Right, and all except SharpDX are first-party i.e. made by MS. MS made even more wrappers, WPF, Direct2D and UWP are also manually written wrappers around D3D 9 or 11.
How many wrappers MS made for Delphi or C++ builder?
> you missed the news regarding PWAs in Windows and its support for native UWP
I’m a bit skeptical about the technology.
> examples of automating Excel with Python
Simple IDispatch not that hard even in pure C. It’s more advanced things that require better support for COM: servers, events-callbacks, data structures like arrays and dictionaries, etc.
Do they? COM in its essence defines two things:
1. A binary ABI for interoperability of components written in whatever language. 2. Reference-counting mechanism and "casting" mechanism (IUnknown).
MS has an article that shows how to build a COM component from the ground-up using only plain C structs containing function pointers (which is how vtables are implemented anyway: array of function pointers). What you think of inheritance can be implemented with a struct containing nested structs of function pointers. Etc.
It's not insurmountable, e.g., PyWin32 has utilities for both consuming and implementing COM components.
COM is quite a lot of things. Also threading model, date-time-currency formats, late binding/dynamic dispatch/scripting, type info both runtime and design time, IPC, RPC, security, and more.
> What you think of inheritance can be implemented with a struct containing nested structs of function pointers
What I think of inheritance in the context of COM is called “aggregation” and it’s more complex than that.
> It's not insurmountable
It’s not, but you’ll spend ~2x more time doing that compared to C++, and ~4x more time compared to VBScript or .NET.
Update: that 2x-4x is for implementation. For consumption C++ and .NET are close, but anything else is more complex due to FFI in between. C++ or VBScript don’t need FFI, .NET runtime is designed around many key parts of COM e.g. they have reused HRESULT’s and type info format.
Honestly this is something that apt (et al.) make so easy on Linux distros that when you move to Mac or Windows you just have hard time believing people still in 2018 have to _deal with this shit_ (installing libraries and their headers by downloading each one separately and running an "installer" and trying to figure out where it put everything)
Like, why. It's one of the principle things keeping me away from developing on Windows for the last 10 or 15 years, the absolute lack of standards with regards to dev package management. Every time I decide I need to get something working on Windows it's an incredible pain in the ass compared to Ubuntu. Oh, now go to THIS website and download this installer and run it, now this one, now this one. And figure out for each one where it decided to put the headers. Now copy the DLLs around, etc. (Yes, there is system32 and Program Files but installers don't adhere to this by any means, and discovery via a build system is not given.) It's just barely worth it, and people only put up with it because of the huge user base. Honestly, for small projects I've found it easier to install MingW32 under Linux and cross-compile instead of working on Windows, it's that much of a pain.
At least Mac has Homebrew and Windows has a couple of good solutions now I guess (chocolatey, who came up with that name), but they are not officially supported and that is sad. I understand, they don't want to pay an army of people to package open source software full time, which effectively is what keeps Debian and Fedora going.. but they should. I would say it's one of principle reasons then end up doing something like providing an Ubuntu environment on Windows .. it's not just that people wanted a Unix-like environment, it's that they wanted _package management_.
I do agree that there is a lot of room for standardizing tool chain and dependency install workflows, but the tools themselves are of high quality now imo.
The chocolatey repo (https://github.com/chocolatey/choco/wiki/History) explains the name as a pun based on the previous package manager NuGet: "Chocolatey started out as a joke because everyone loves Chocolatey nougat (nuget)."
You get one version of each package, and it is often years out of date. If you need a newer version you'll have to install it yourself and then try to navigate how to get your projects to use your local version. For any popular package that is still undergoing a fair amount of change it is likely that eventually some project you want to build will need a newer version than the one your distro provides.
So you still need a solution to the versioning problem separate from the distro packaging environment, at least for development.
Headers/libraries on an Ubuntu LTS may be years out-of-date.
Am I supposed to just download a tar.gz and do the configure/make/make install dance to /usr/local or /opt or something for each dependency that I need a more current version of?
Even worse - what if my deployment target is 3-4 years older than the machine I'm developing/compiling on?
I don't think anything is "solved" with a traditional UNIX environment. Not even close.
No, you're (usually)supposed to stick with the out of date version rather than the shiny new version. Doing otherwise is taking on the responsibilities of a distro maintainer, usually not consciously.
> Even worse - what if my deployment target is 3-4 years older than the machine I'm developing/compiling on?
Either use the older version for developing or at least have a version of that environment for CI.
It does look promising but because of the mess I'll probably gravitate to another language if I don't need to consume such a low level API.
And remember -- a lot of the complexity comes from historical reasons AND also allow you to, e.g. run on, say an Atmel 328p or other microcontroller. So the complexity is partly from having such a wide target area.
What people call "opinionated" is nothing more than something being "architected". Someone has made a bunch of decisions for you that down the road you have no idea whether or not it will actually be good for you.
Using these types of frameworks short-circuits the process of being able to understand the nuances of building software. It's the apartment building or high rise of software development.
It turns design of your system from a personal journey toward the solution of your problem into little more than assembling linking logs.
I can understand the argument for an opinionated toolbox, but not for wanting base tooling itself to be opinionated.
Opinionated also means that these decisions will be the same in other places/projects I may join. In the medium and long term, that advantage may easily offset the value of custom decisions.
A lot of stylistic stuff like filesystem layout falls into this bucket.
You might have some highly-specific need which demands a particular tool, but it's likely that you're best accepting whatever is most popular in your chosen ecosystem (gtest for C++, nose/tox for Python, etc).
Tho, it still won't be anything like ruby or node. Some Qt projects opt for cmake over qmake, for example. But at least getting your project bootstrapped is much simpler/faster.
#beentheredonethat
After the hellscape that is CMakeLists.txt, Bazel is such a breath of fresh air. I'd encourage anyone looking at C++ for new projects to give it serious consideration.
That’s great! I’ve been using it since 2013 and still haven’t learned it!
I've been using Python since 2008-ish on and off for various scripting tasks and small tools, I can't say that I've "learned" it. They keep adding new stuff, some things I forgot, others I never needed.
I've been using C++ professionally since ~2006 and for similar reasons I won't say that I master it either. Metaprogramming is a clear weak point for me, but OTOH I find the whole exercise pointless and unpleasant. Unless one wants to be on the standards body, it's not really worth trying to learn C++ (or any other language) at 100% IMO.
And does it really matter if you don't? No, not at all.
As a contrast, the description of Common Lisp syntax fits on a sticky note, but the library and semantics spec take about the same number of pages to describe a similar amount of functionality.
The two extremes represent different locations on the syntax-vs-library complexity tradeoff continuum.
I'd say it's a syntax x language semantics x libraries triangle. Common Lisp may have trivial syntax, but there are some hidden gems of complexity in the language semantics level. To this day I don't really understand eval-when, and I've been using Common Lisp for the past 9 years.
Incidentally, after working with node for a couple years near really knowledgeable coworkers, it's been the first time in my life as a developer that I feel I have a near complete understanding of the language I'm using.
Granted, most of that feeling probably comes from the small standard library (which is the root of several important issues, as we all know), and the feeling adds nothing to your life as a developer except for a vague sense of comfort, but it's still nice.
admittedly, Java got a lot bigger in Java 8 and beyond. but it's still the language I'd put forward as "most possible to master".
Just for context, I was such a C++ bigot at one time that my car's license plate read C++HACKR and my personal website was on the cpphacker.org domain. But somehow I drifted into doing more Java and wound up mostly leaving the C++ world.
Edit: heck, this conversation triggered such a pang of nostalgia that I just re-registered cpphacker.org. Maybe I'll go back to having a personal website there. I've been thinking hard about setting up a new personal site and ditching Facebook anyway...
Can anyone recommend any source for someone with lots of pre-C++11 experience to get up to speed with current capabilities, and the current community?
EDIT: Thanks everyone for the suggestions!
EDIT2: I skimmed Anthony Calandra's list, and most of the new features seem indeed just cute, but not fundamental changes. Still, I want to reiterate the worry I expressed downthread: how much did the underlying semantics, the idioms, and the general way of thinking change?
https://github.com/AnthonyCalandra/modern-cpp-features/blob/...
Other books I've been reading: _C++ 17 The Complete Guide_ by Josuttis _C++ 17 in Detail_ by Filipek
Lots of good blogs out there. Also the CPP Podcast. http://cppcast.com/
There are also a lot of great blogs covering new features. Also
Note: I do wish HN would adopt standard markdown
Aaand you've just learned all the formatting HN has :). That, and URLs automatically turn into clickable everywhere except the body of a self-submission (i.e. submitting a text instead of a link). Any other formatting here is just convention.
If you already know the language flow control you don't need to read paragraphs of a book to relearn to how "think" in the language. You just need the "whats new" parts.
(I hear the compile times are the same though -.-)
The combination of "auto" (plus template type inference), ranged for-loops, initializer lists, structured bindings, lambdas and certain new standard library mechanisms (std::unique_ptr, std::variant, std::optional, std::move, etc.) together change the high-level expressiveness of the language, encoding a lot of common patterns and eliminating common, redundant code. For example:
std::vector values = {1, 2, 3};
for (auto v : values) { ... }
New for loops support structured bindings: for (auto &&[key, value] : mapOfStuff) { ... }
There's a lot of little conveniences, such as the ability to define a default constructor, or accept a initializer list in the constructor: struct Foo {
Foo(std::initializer_list<int> values) { ... }
}
Foo f = {1, 2, 3};
or indeed named initializers: struct Person {
string name
}
Person p = {.name = "bob"};
The forthcoming range library in C++20 also finally make lazy sequence iteration functional and composable, e.g. something like (off the top of my head): getNumbers()
| view::filter([](int a, int b) { return a > b; }
| view::reverse()
| view::take(10);
Another big change that's coming is concepts, which are somewhat similar to Rust traits or Haskell typeclasses: The ability to put compile-time constraints on template arguments. For example, in classical C++, invalid template invocations generate notoriously bad error messages, since templates are only compiled once they have been expanded with their arguments: template <typename T>
T add100(T v) {
// Compiler will fail on this line:
return v + 100;
}
auto n = add100("hello world");
Concepts will let you constrain T to something that actually supports the operations you need: template <Incrementable T>
T add100(T v) {
return v + 100;
}
// Compiler fails on this line:
auto n = add100("hello world");
Then there's the contract spec, which adds support for Eiffel-type contracts.Lastly, C++ designers seem to have thought a lot about safe memory semantics, and so there's a renewed focus on smart pointers (that actually work) together with move semantics and tightening of cop constructor semantics. The end result is that it's generally easier to work with RAII and avoid explicit heap allocation with the "new" keyword.
Which probably means that someone who learned modern C++ will have significant difficulty with older C++.
Sometimes it makes me wonder if someone should just declare a subset of C++ as "good" and call it a new language.
Wouldn't have it any other way haha
To me, this is the most powerful reason to learn C and C++. If you know these languages, you can read the codebases of all the things you use and contribute to them (every browser in existence, every Unix in existence, most user space tools, many GUI tools, many low-level libraries that mobile apps use).
Even if everybody stops writing C/C++ today, you'll still be using software written in C/C++ for decades.
And of course, that's a joke -- there's still at least 10x more C/C++ being written every day in the world than any other language that compiles to native code (Rust, Go, etc.)
Welcome! As someone who’s been using C++ pretty much continuously for two decades, I think there has never been a better time to learn it. We finally have compiler competition that has resulted in robust support for the language’s great features.
Ah, yes. I think they called it "C".
In modern C++ it is very much possible to write fast and safe code, but the tradeoff is now put into the amount of stuff the developer needs to know to be productive (Which in my experience isn't as bad as people like to go on about on here/reddit, even if it still pretty shoddy)
Thats a bit unfair. A recent headache for my C++ project was mixing audio buffers. The buffers are cached to avoid repeated reads, the channel count differs, the sample rate can differ, the output rate can differ, and mixing has gain limiters applied etc. Lots of buffers, lots of copying, lots of boundary cases (eg. sample #1 doesnt start until t=100ms, sample #2 ends before sample #1, etc).
I struggled for days getting all the buffer copying right (raw pointers to many interrim buffers). You may think that my problems were due to using "crap c++ in unidiomatic way". However, I challenge you to find a better, and as efficient method to accomplish the same goal. The end MixAudio() function looks like plain old C code from the early 80's, but how else can you tackle this problem in a modern way?
It seems like you struggled with math (indexing logic) rather than C++.
> how else can you tackle this problem in a modern way?
You could try to write an iterator that takes into account sample rate, channel count, etc. That way the logic for handling buffer formats and iteration over samples is encapsulated into a single reusable component.
Efficiency should be roughly the same, especially given that you can optimise loops (and other code) with just as much access.
OTOH if not for C compatibility we would not have this discussion, since we would most likely never heard of C++.
You can make whole applications without touching memory management with RAII patterns; and C++ APIs are usually not the Java OOP monstrosities everyone hates.
Operator overloading is just so damn useful . You can make very elegant APIs in C++ as a result.
Honestly, I don’t really like it. The only real reason for that is that using smart pointers is verbose, but I don’t want to do manual memory management where it’s possible to instead rely on RAII.
Ironically enough, though, C++ is probably the second of two languages I’d consider my “go to.”
Its pretty unlikely anyone is going to take on the monumental project of "write a software GUI kitchen sink suite like Qt, but in Rust" any time soon. Not because you can't, but because such projects are by their nature at minimum millions of LOCs.
> blog post in January 2019
> "learnt" in past tense
This is what also makes Bjarne one of the greatest language designers. Where most designers would have gone off making new languages, Bjarne has been polishing the C++ stone the whole time.
Is it better to build a complex programming language that handles real world complexity?
Or is it better to build a simple programming language where complexity is an emergent property than in turn use that to handle real world complexity.
One issue of building a complex programming language is that if you build the language to handle one type of complexity, it becomes hard mutate or shift that programming language to handle a different type of complexity. This is essentially the issue with whats happening with the newer versions of C++.
Autodesk AutoCAD (36+ years old) CAD software is one of those piece of software that is still widely used today and very likely used to design physical products many people use today from your toothbrush, office chairs, towering skyscraper buildings to parts of a jet plane you've flown in from your last vacation.
I don't think this is more than a minor issue. If you can't afford it, the book is very easy to obtain online for free, either through piracy or a paid / free trial Safari Books Online subscription. If you felt so inclined, you could pay for the book after making money with the C++ it taught you.
The document is definitely not a good way to learn the language.
Personally, I find Scala standard library much easier to work with and at the same time much more flexible and powerful.
Like a few days ago I saw a bunch of complaints about how C++14 and beyond were adding so much stuff and it's just bloat or overcomplication. No! Using that stuff makes my life so much easier, whereas C++98 was indeed a miserable nightmare.
What is the best C++ IDE on the Mac?
In particular, fully project-aware autocomplete is a baseline feature. Does emacs or Vim offer an autocomplete plugin that matches the power of IntelliJ, or even Xcode?
Is CLion worth the money? Other paid alternatives?
[1] https://www.qt.io/download
[2] https://valloric.github.io/YouCompleteMe/
[4] https://marketplace.visualstudio.com/items?itemName=ms-vscod...
[5] https://github.com/MaskRay/ccls
So I agree, 1 year doesn’t even begin to cut it. You need more than book knowledge, you need the experience of watching your masterpiece crumble under its own weight (sometimes several times) or have the joy of hunting some obscure bug because you failed to recognize the trap you had set for yourself.
I certainly wouldn't want to scare anyone off from C++, because personally I find the empowerment is worth the pain. It just takes time to learn what to avoid.
Very good point, but that's by no means unique to C++. Maybe that level of experience ;) in a related language, plus a good working knowledge of C++ would be acceptable?
He started ~2 months ago.
I've started to learn some C++ a few days ago, mostly go get into lower level code and into game development (Unreal), and I've found it to be pretty great!
I've been going through A Tour Of C++ and it's a great primer on the whole language. I also read the Learn X In Y Minutes on C++ to get a feel of it before diving in.
What are some high quality, small C++ projects I could play around with and read the source code? I'd like to explore it in more practical use next.
So many times I wish to learn it seriously but these new editors for web development and Python made me lazy enough that I wish to have some environment and way to write and compile C programs easily.
I heard modern C++ is way better than what it was in early 2000. I want to give it a try, hopefully, I will be able to learn and implement Pointers properly.
I can't stress enough how true this is.
Things might even work in the end, but you can end with a weak project that wont scale or will crumble when faced with the destructive nature of time.
I know its a controversial topic, but i think a little bit of zen-budhism training of the mind can make wonders in making those sort of decisions, where the unbalanced parts of our psychology will eventually show up and cripple what could be a great thing.
I am an IT enginner, but i practice a lot of self-mind vigilance to understand my decision making process, to avoid making the most confortable decisions and going for the write answer, no matter how painful and expensive it may sound.
To give an example of this, i remember for instance CouchDB vs. MongoDB, where the concepts were layout in CouchDB, but it was done in Erlang, so as soon someone did almost the same thing in a language that suits a database development well like C++, the tool sky rocket and reach all of its potential.
The language i see this happening the most for instance is Python. Where you have great concepts and great enginners but where a lot of them shouldn't be using Python for that particular goaç. Again here i can use Mercurial as an example of a great tool in a bad fitting language (for the given tool, as Python might be a great fit for other use cases).
This is obviously not what one should do. Read the test cases first is what I do. It makes for much quicker iteration.
I tried rust, but they keep changing it and breaking modules i need to use!
If you find your dependencies are breaking:
• Keep a lockfile (Cargo.lock) committed in your project, so that your deps won't suddenly get updated to some newer, potentially buggy/incompatible version.
• If you're updating dependencies, also update the compiler. It's possible that new versions of dependencies require latest version of compiler.
1. Current setup and where to go learning (the books) 2. It also had nightmares in colleague with C++, but yes, C++11 fixed a lot of it. 3. Nice links to the other tooling.
So, author, thank you for your post!
Also, you could "learn" it in a year, but it takes you a lifetime to master it.
Learning bash became easy when I learned pipelines and the GNU coreutils.
Now I wish I could take what I'd learned from GNU coreutils and apply that to C++.
If all you know is C++ you will be able to produce a limited amount of working code in a handful of C++-like languages, sure - but even in Python or Java or Bash you'll produce very unidiomatic code if you write in C++ style. If you tried to work in e.g. Smalltalk or Erlang or even OCaml you'd really struggle. It is not a good way to learn general-purpose programming, because the language is hugely complicated and most of the complications are C++-specific.
The complication is C++ specific and moving to java, bash or python is simply removing that complexity. Hence moving to C++ is easier then moving from python or another similar language because in most cases you would be adding complexity.
OCaml and Erlang are too different for me to comment about a transition in the functional direction.
Hoever to even get there you first need to learn incredibly complex nonsense and waste massive amounts of time for knowlage that is virtually useless.
Then you might as well pick up Java, the most popular OOP language and learn it there.
Except that it makes a point that is subtly different from the one pg originally raised in discussing Blub paradox: If you only care about shipping something, you aren't inclined to think about abstraction as a goal state, and that's what these other languages are doing: handling things with a goal of adding abstraction that for a C++ user is out of reach or requires considerable knowledge of the C++ standard. Users of Python or JS don't know what a pointer is, and that's intended by design, because for most applications it is an implementation detail and automating it away is desirable.
When most software was written in assembler, data structures more complex than an array were often avoided, because it was difficult to code and debug them. And if you were an assembly coder of that era, you might well say that you didn't see the point of structured programming, or that you could easily get the same effect in fewer bytes. And to some degree, you'd be right, because you would just design a smaller scope of application that makes those techniques viable.
Trying to write something resembling modern C++ style in x86 assembly, in contrast, would be as fruitless as a JS coder trying to use C++ like JS, since your abstractions wouldn't be there. You'd have to learn the thought process of a lower level coder and apply those strategies instead of the ones you are comfortable with.
WTF, RAII is the corner-stone of C++ development. And I miss it (deterministic destruction) in every other language I use.
These days I use C# in parallel with C++, C# has using statement, but it relies on IDisposable, and IDisposable itself is a kludge (just look at guidelines on how to implement it "properly").
Did they try the languages I mentioned? C++-trained programmers might be able to write lowest-common-denominator code in other languages but they'll struggle to write effective, idiomatic code in languages that make significant use of pattern matching/sum types or polymorphism, or rely on extensive use of higher-order functions.
> but of course plenty of people know other languages and can't do C++.
I'd agree that C++ programmers can usually write Java/Python, Java programmers can usually write Python but not C++, and Python programmers can usually write Java but not C++. But the implication is not that C++ is more general than Java or Python but just the opposite: programming in C++ requires learning a lot of C++-specific stuff that programmers in those other languages don't bother with.
C++ does more at a higher cost, and in recent standard updates the cost has been steadily decreasing.
I'm not convinced. C++ offers some abstractions but is also missing some quite basic ones (no sum types, no true parametric polymorphism, polymorphic code can only be typechecked once fully expanded). ML-family languages offer substantially better abstractions at minimal performance cost or, in the case of Rust, no cost. Even for GCed languages my experience is that at practical levels of developer effort C++'s high performance on benchmarks is outweighed by the language complexity burden (e.g. Haskell code that solved the same problem as C++ code was not only shorter and more maintainable but also substantially faster; no doubt if we'd carefully hand-optimized every line of the C++ it could have achieved higher performance, but even unoptimized C++ took much longer to write than the Haskell solution).
> C++ does more at a higher cost, and in recent standard updates the cost has been steadily decreasing.
The big cost is the complexity of the language, and since the language rarely if ever removes anything standard updates usually add to that rather than reducing it.
Significant bad parts of C++ have been deprecated or effectively replaced with something better; you just have to adopt the good way. For example, the new initializer syntax allows for simpler and saner rules about type conversions and lookup of constructors.
I'm not convinced. Small-scale heavily-optimized microbenchmarks show C++ as at most a single-digit multiple faster than e.g. Haskell. I wouldn't expect you to achieve even that much over Rust. And like I said, I've yet to see such a performance advantage to C++ in a real-world scenario - quite the opposite. It's not always a tradeoff - sometimes one thing really is better than another thing.
> Significant bad parts of C++ have been deprecated or effectively replaced with something better; you just have to adopt the good way.
And ensure that all your libraries/tools/coworkers have adopted the good way, which you have no way of enforcing; at best you have ad-hoc linters that flag up some (but not all) bad practices.
I mean, yes, in C++ you have to clean up the memory yourself. That means that you need to know when to do so. That means that, for the graph nodes, you're probably doing some kind of reference counting, and it will be a bit fiddly to get right. If you do it in a base class, though, you'll only have to do it once.
I wouldn't call that "impractical" at all. (I might call that "reason to prefer a garbage-collected language for doing graph-based work", but if I needed to do such work in C++, I wouldn't be particularly daunted by the prospect.)
- Manual memory management and direct use of pointers.
- Emphasis on giving as much latitude as possible to compiler writers so they can generate fast code on obscure architectures.
- Separation of header files from object files.
- Explicit handling of object files and linking in the build process.
In fact, I think after learning C++ you should be able to read almost any C code with no issue, which is nice for being able to peek under the hood of the infrastructure we rely on every day.
>"Rust"
>3 results
T-h-r-e-e? How is this even possible?
C++ is very messy, but for the most part you can ignore the messy things.
I feel we should build our programs the same way. Bottom up from a small set of simple primitives. Not top down like C++.
But to be clear: Node and Java (and anything with a managed heap) doesn't have a paradigm for things like RAII or inlined parametrazation or copy-by-value or move semantics because it doesn't have a way to express them. But those are useful tools and important in some regimes.
* C++
* Lua
..
.. [a thousand other things]
..
..
* Node
* Javascript
__ bottom of the pile..
The Node/JS ecosystem is such a steaming pile of garbage, I can honestly see with great clarity why people should be running from it back into the arms of C++[11,17] ..
Now, I'm sure some people have an easier time with Makefiles, but I've found it even easier to get up and running in Javascript. Most of the tools in Javascript (create-react-app, Webpack, etc.) are very user friendly, making setup trivial.
It is best not to speak with such authority/certainty that C++ is easier to use than Javascript.
https://www.infoq.com/presentations/Simple-Made-Easy
JavaScript is a simple language that can be made extremely complicated via "simple" tooling. You can open the node_modules folder and see how sausages are made. :-)
C++ is dealing with essential complexities, there is no silver bullet:
https://nbviewer.jupyter.org/gist/ontouchstart/1af198f8535eb...
Don't underestimate the pile of garbage JS indeed is! Yes, you can install a package with ease, you'll have to do that with about 100 packages that keep changing all the time with all kinds of breaking changes (not talking about their 1000's of dependencies). I'm also sick and tired of the hipster JS community where every piece of shit can become a hype. With JS you'll be forced to work with things you hate. Almost all codebases I have to work with are horrendous piles of rubbish that often need to be completely rewritten from scratch. Almost everything you write doesn't last. You've spent a year learning Backbone? Just throw it away, now it's Angular you can start all over again. One year later? Stop doing Angular, it's React now, just start all over again! Hey, now we have some hipsters promoting Vue, they say it's the holy grail, just start all over again, it's fun! Flux stores? Fluxxor, Alt, Redux, Redux with Saga's, or just go with Thunk? It doesn't matter that much, it only lasts for 1 or 2 years! I'm completely sick and tired of it, including the fact that I'm only working on stupid e-commerce websites..
Talking about make files, a magnitude easier than trying to setup babel and webpack for a medium sized SSR SPA. I recently had to upgrade from babel 6 to 7, what a fuckin pain that was, so many changes, the deployment server refused to boot etc, etc..
Mind your step going into JS!
Similarly, with C++ there are also many packages to do the same thing. This summer I was using TLS and I found a variety of options, OpenSSL, mbedTLS, wolfSSL, etc. etc.
I do agree that it is tiring to learn some of React's accessories. I have never used Redux and when I do need some form of global state management, I think I will use MobX.
The complaints about code base quality and "stupid e-commerce websites" don't seem to be problems inherent to Javascript, although I suspect the problems Javascript solves are less interesting than the ones C++ solves.
All in all, I feel like C++ (for me) has been more difficult than Javascript due to a lack of standardization and the community being less beginner friendly.
That being said, I was trying to use a relative obscure feature (SGX) in C++, whereas with Javascript I stick to relatively mainstream applications.
Unless of course you have 30+ years of experience in the software business, have kept abreast of all the latest and greatest distractions from proper software engineering practices, have built a few hundred examples of such personally, and have no desire to throw more garbage at the fiery pile. As is my personal case. Node/Javascript are the Visual Basic of the 21st Century - this doesn't mean people haven't been productive with them as technologies, just that they've been productive in spite of them.
--
[0] - Everything I worked on, from games through embedded to web development, was a poor fit for C++/Java-style OO, but I suspect there are some domains where OO modeling is the best way of looking at things.
I agree though, that having the entire program be a graph of objects is actually usually the worst pattern.
For Alan Kay it was all about messanging but I dont think most people think about that.
Structs with some kind of dynamic dispatch based on the type would be the most general discription I think.
Common Lisp really opened my eyes here. Initially it felt weird to have methods[0] living completely independently from classes, but over time I realized that where classes and objects implement nouns, generic functions and methods represent verbs, and in a language the verbs are an independent domain from nouns, representing their own generalized concepts that's unrelated to the taxonomy of nouns.
--
[0] - A "method" in CLOS is an individual implementation of a "generic function". So e.g. you could have a generic function `(defgeneric draw (device figure))`, and then specific implementations dispatching on any combination of arguments; e.g. `(defmethod draw ((device printer) figure)` to draw any kind of figure on a specific device, or `(defmethod draw (device plotter) (figure circle))` to draw a specific thing on a specific device, etc.
def method():
this.value = this.value + 1
lisp does something like this? def method(object):
object.data = object.data + 1Common Lisp gets rid of implicit `this` by making all arguments explicit, and by not restricting polymorphism to the first parameter - in fact, you can do a method dispatch on any of the method parameters, or any combination of them. See https://news.ycombinator.com/item?id=18848384 for an example.
So you might have.
define generic inspect-vehicle (v :: <vehicle>, i :: <inspector>) => ();
define method inspect-vehicle (v :: <vehicle>, i :: <inspector>) => () look-for-rust(v); end;
define method inspect-vehicle (car :: <car>, i :: <inspector>) => () next-method(); // perform vehicle inspection check-seat-belts(car); end;
define method inspect-vehicle (truck :: <truck>, i :: <inspector>) => () next-method(); // perform vehicle inspection check-cargo-attachments(truck); end;
This is Dylan code, but its the same concept, easier to read compared to CL. See: https://opendylan.org/documentation/intro-dylan/multiple-dis...
Once you start thinking about dispatch in a broader sense the advantage is clear.
This is what I was primarily thinking about, and this is what is most written about in OOP books. OOP is a big bag that wraps itself around a lot of things, and which appropriated quite a lot of concepts. The concept of gluing together a bunch of data and code in order to treat them as a single entity is indeed useful (at least for imperative code), and while it is the foundation of OOP, I don't think it's really the distinguishing thing about various OOP approaches. For the class-based OOP, it's the composition of data+behaviour, encapsulation, polymorphism and inheritance that together create a particular philosophy - one that I find much less useful than advertised.
The building blocks are no doubt useful - a proper type system is great, but you don't need classes and objects for that. So is polymorphism, and again, you don't need Java-style classes to get method dispatch (see e.g. Common Lisp multimethods for an arguably better way of doing this, and one that doesn't even treat methods as parts of classes!).
I'll concede that OOP approach fits UI libraries unusually well (though you can hit some conceptual roadblocks there too; I'm not sure I've ever seen a good OOP design of tables, nor do I know how to design it well). But then again, I was recently writing some React code in ClojureScript, and it turns out that functions and plain data can handle building stateful UI components well too.
What I mean by saying that OOP appropriated things - I've seen people thinking, and even myself I used to think, that "abstraction" is something that a class creates, and is what you achieve with OOP. I gradually grew out of that belief, and I vividly remembering that reading SICP made it finally click in my head that quite a lot - if not most - of the software engineering practices discussed and attributed to OOP are in fact more general concepts applicable regardless of your programming paradigm.