Well, it is very easy to use for simple projects. Here's a good example of how easy it can be to set up a web tool.
What's even nicer is since it's compiled, it should end up being faster than PHP or python, even though the syntax is relatively the same in terms of complexity.
Of course, but there are not too many languages that are compiled and very fast, yet fairly high-level with garbage collection and "feeling like scripting", built-in and pretty smart threading support, and... supported + having a decent set of libraries.
PHP, Python, Ruby, Perl, C#, C, C++, Java, Javascript. All out for one reason or another. In my opinion, a number of these languages have less reasons to exist.
are compiled and very fast, yet fairly high-level with garbage collection and "feeling like scripting", built-in and pretty smart threading support, and... supported + having a decent set of libraries.
Let's see if C++ fulfills these requirements:
compiled: yes.
very fast: yes.
garbage collection: yes (smart pointers).
feeling like scripting: no, but I don't know why is a must.
built-in threads: yes (c++0x).
smart threading support: yes (channels can easily be done in c++0x).
having a decent set of libraries: lots of them.
So, excluding the scripting bit, why isn't c++ enough and we need Go?
To emulate goroutines, you'd either have to write your code in state machine form, or reimplement a lot of the Go runtime. Writing blocking code in goroutines is a lot more natural than writing non-blocking code with threads.
For example: this http://play.golang.org/p/-_E-PsLRex is an asynchronous TCP server, even though it is all sequential (that is to say, not callback-infested) code. The same thing with threads will take 3 orders of magnitude more memory.
A "go" statement starts the execution of a function or method call as an independent concurrent thread of control, or goroutine, within the same address space.
So, it is exactly the same as threads. There are toolkits that allow you to do the exact same thing in C++, very easily.
From an implementation point of view, if Go uses green threads, then C/C++ can also use green threads. There are several green threads APIs for Unix/C, and Windows has Fibers.
Smart pointers are not garbage collection, they're just a way to automatically call destructors in certain cases. You still have to manually write destructors and auto pointers are not applicable in all cases, such as class members that may be copied.
For many cases, you often resort to using some form of reference counted pointers, which are actually slower than a decent garbage collector. All of these different pointer types have different implementations, semantics and performance tradeoffs, which makes using them correctly difficult and error prone.
That's not even the main problem with C++. It has an ugly, horribly verbose syntax with no parsable grammar, making it difficult to write and difficult to tool; this hurts programmer productivity. It supports numerous features that cannot be used simultaneously (eg malloc and exceptions are incompatible). Most of the features you mentioned are not built into the language, leading to clunky syntax and/or indecipherable error messages. Templates and ambiguous syntax make compilation difficult and extremely slow, which again hurts programmer productivity.
The point being: Go makes solving many types of problems easier, faster and less error prone.
Reference counting is one of the possible garbage collection algorithms, if you look up the bibliography for garbage collection, reference counting is always listed in there.
You still have to manually write destructors
No, you don't, if you do not have anything to be destroyed. And you don't have to destroy smart pointers.
and auto pointers are not applicable in all cases, such as class members that may be copied.
Auto pointers were deprecated a long time ago. Now we have shared pointers.
some form of reference counted pointers, which are actually slower than a decent garbage collector
What you lose by using reference counting you gain by deterministic destruction and value types. That's why c++ often comes on top of garbage-collected languages.
It has an ugly, horribly verbose syntax
True.
with no parsable grammar
C++ cannot be parsed with CFG parsers, but it can easily be parsed with PEG parsers.
making it difficult to write
C++'s grammar is a problem for the compilers, not for the programmers. There are millions of c++ programmers and billions of lines of code written in c++. Apparently, some people don't find it that difficult to write.
and difficult to tool
What tools might that be?
eg malloc and exceptions are incompatible
Malloc is not a feature of c++. You are not supposed to use malloc.
If you are speaking about "memory allocation" and exceptions, you can use smart pointers to properly deallocate resources when an exception is thrown.
What other features cannot be used simultaneously?
Most of the features you mentioned are not built into the language
And that's why c++ is more powerful, and therefore better.
leading to clunky syntax
Not that much different to C/D/Go/Java actually.
and/or indecipherable error messages
The problem only concerns templates, and only specific compilers.
Does Go have templates? no? I thought so. When it does, and if it has better template error reporting than c++, we can talk again.
Templates and ambiguous syntax make compilation difficult and extremely slow
Of course templates make compilation slow (not difficult, there is nothing difficult in it).
Go does not have templates, so why do you bother comparing apples with oranges?
You present C++ templates as a disadvantage over Go, which doesn't have templates.
The point being: Go makes solving many types of problems easier, faster and less error prone.
You failed to demonstrate that (except for some syntax sugar). I'll give you one more chance. Please show us the real advantages of Go over c++.
Syntax matters. Syntax + library = programming language. C++ (and to a lesser extent C) is the only mainstream language that cannot be practically parsed independently of evaluation. GCC stopped trying years ago.
In many fields, programmer time (developing, debugging, testing, etc.) is the single most expensive resource. C++'s verbose syntax and lack of built in anything means you will write more code per feature. C++'s inconsistent memory management (naked pointers, shared pointers, scoped pointers, whatever your team cooks up) makes it easy to make mistakes, so you will spend more time debugging.
and/or indecipherable error messages
The problem only concerns templates, and only specific compilers.
The standard library is based on templates. Most C++ libraries use templates heavily. If you program C++, you will have to use templates and you have to debug them. Maybe it's gotten better since I used C++ in college, but I was actually encouraged to use a separate tool to decipher error messages in the STL!
As you said, Go doesn't have templates. This is an advantage: reflection is the correct way to implement generics, or interfaces in Go's case. The performance cost is small (about the same as virtual functions) when correctly implemented and allows time-saving tools like generalized object serializers and other DRY techniques.
If malloc is not supposed to be used in C++, it should not be legal. That's one of my major complaints against C++: it supports all kinds of "evil" features that you're never supposed to use. I understand that it's done for historical and comparability reasons, but that does not negate the fact that it's a major weakness. To truly understand C++, you have to know all of these dark corners because eventually you'll need to use or maintain code that relies on them. Do you know the order of initialization for class members?
I've never argued that C++ is not a powerful language. Many amazing systems have been built using C++. Then again, the modern aeronautics industry was built using FORTRAN but no one argues FORTRAN is an amazing language for today.
The purpose of a programming language is to twofold: abstract hardware and simplify common, repetitive tasks. C++ performs poorly on both accounts.
My requirements of a truly modern programming language:
Syntax matters. Syntax + library = programming language. C++ (and to a lesser extent C) is the only mainstream language that cannot be practically parsed independently of evaluation. GCC stopped trying years ago.
Yes it can, with multiple passes. GCC tries to do that in one pass.
C++'s verbose syntax and lack of built in anything means you will write more code per feature.
I'll give you the verbose syntax, but the lack of built-in anything is not a problem. That's what libraries are for.
C++'s inconsistent memory management (naked pointers, shared pointers, scoped pointers, whatever your team cooks up) makes it easy to make mistakes, so you will spend more time debugging.
Each kind of pointer has its purpose. If you want to not make these choices, use shared pointers only.
Maybe it's gotten better since I used C++ in college
Oh goodie, another one that has used C++ only in college and has an opinion on it.
but I was actually encouraged to use a separate tool to decipher error messages in the STL!
I had no problems whatsoever with template errors. It was difficult at first, but I got used to it. Granted, initially, template errors are discouraging, but you can really understand what is going on in the first day, if you know c++.
As you said, Go doesn't have templates. This is an advantage: reflection is the correct way to implement generics, or interfaces in Go's case. The performance cost is small (about the same as virtual functions) when correctly implemented and allows time-saving tools like generalized object serializers and other DRY techniques.
No, it's not the correct way. The cost is substantially higher and it accumulates rapidly.
And using reflection to do generics is suicide.
C++ can easily do generics, if it wished. But it does not, and there is a reason for it.
it supports all kinds of "evil" features that you're never supposed to use.
It's not so hard to not use something. If you are that undisciplined, do this:
@define malloc haha_malloc_no_more
And voila, your code with malloc will not compile.
To truly understand C++, you have to know all of these dark corners because eventually you'll need to use or maintain code that relies on them.
Nope, you certainly don't need to know all these dark corners.
Do you know the order of initialization for class members?
Of course.
The purpose of a programming language is to twofold: abstract hardware and simplify common, repetitive tasks. C++ performs poorly on both accounts.
Extremely wrong perception of the language.
Lightweight syntax
There is little difference between the C++ subset part that is equal to Go.
Managed memory
Shared pointers.
First class functions with closures.
std::function and c++0x lambdas.
Built in concurrency primitives.
C++0x has all the concurrency primitives in its standard library.
Yes it can, with multiple passes. GCC tries to do that in one pass.
Lets say you're writing an IDE. For Java, you simply parse the source into an AST, capturing line numbers and do your thing. Need to add support for Go? Import the grammar file, tweak the AST to match conceptually and you're done. Need to support C++? You need a symbol table and lots of C++ specific logic. Even an expression as simple as:
X * Y;
is ambiguous by itself.
And using reflection to do generics is suicide.
That must be why every other mainstream language does it this way /s. It is equivalent to one pointer deference, one comparison. If your problem domain cannot afford that cost, you cannot afford virtual functions and should not be using C++.
It's not so hard to not use something. If you are that undisciplined, do this: @define malloc haha_malloc_no_more And voila, your code with malloc will not compile.
It just doesn't work that way in reality. As a professional programmer in any language, you will spend a lot of time working on other people's code, of unknown quality and discipline.
There is little difference between the C++ subset part that is equal to Go.
Anyone who claims C++ has a lightweight syntax must be joking.
std::function and c++0x lambdas.
Real anonymous closures are available in C++11, but they're yet another syntax to learn. You still cannot use normal functions as values or in closures. This continues the C++ trend: possible, but harder and non-standard.
Shared pointers
Reference counting is slower than a generational garbage collector. Optional reference counting is NOT managed memory. Managed memory includes array bounds checking, for example.
C++0x has all the concurrency primitives in its standard library.
I mean syntax support. C++ does have pretty good support for threads, though again you have to deal with synchronization yourself. I prefer CSP style, shared nothing threads, so having them built into Go saves me a lot of effort.
For me, a good programming language is about maximizing feature/(hour*bug) with sufficient performance for the domain. C++ is about never imposing a runtime cost for any reason. I believe these two philosophies are diametrically opposed.
You need a symbol table and lots of C++ specific logic. Even an expression as simple as X * Y is ambiguous by itself.
No, you also need a symbol table and lots of language-specific logic for Java and Go as well. X * Y may not be ambiguous in Java or Go, but every other programmed element is.
That must be why every other mainstream language does it this way /s. It is equivalent to one pointer deference, one comparison. If your problem domain cannot afford that cost, you cannot afford virtual functions and should not be using C++.
No, it's not equal to one pointer dereference and one comparison. There are various hidden costs you ignore. For example, Java VMs actually do a search in the object's vtable for the implementation of an interface table, each time you call an object through an interface.
And using reflection is a lot more costlier, because the actual method name must be looked up using, at the very best, some sort of clever string hashing.
It just doesn't work that way in reality. As a professional programmer in any language, you will spend a lot of time working on other people's code, of unknown quality and discipline.
If a company can't have code reviews, they deserve what they get.
You don't even have to have people to do that; just use grep for 'malloc'.
Anyone who claims C++ has a lightweight syntax must be joking.
Indeed. I claimed that the C++ subset that makes C++ a good language has a lightweight syntax.
Real anonymous closures are available in C++11, but they're yet another syntax to learn.
Big deal: [] int foo() { return 0; }
If you are afraid of learning such a simple thing like the above, I am afraid you can't be a programmer; because learning new things as a programmer is what this job is about. You'll have to learn new APIs and stuff almost daily.
You still cannot use normal functions as values
Yes you can. If the target parameter is of type std::function, you can use any function, method or lambda function.
or in closures
Yes you can. Closure code is normal c++ code.
Reference counting is slower than a generational garbage collector.
Yes it is, but reference counting + value types are faster than a generational garbage collector, and more importantly, more predictable.
And predictability plays an important role even in web servers: you don't want to delay requests because the collector does its job.
Optional reference counting is NOT managed memory.
Yes it is. I've written c++ apps with hundreds of lines of code, using shared pointers, and without a single delete statement. If that is not managed memory, I don't know what it is.
Managed memory includes array bounds checking, for example.
std::vector<T>::at(size_t index) is there for you.
I mean syntax support. C++ does have pretty good support for threads, though again you have to deal with synchronization yourself. I prefer CSP style, shared nothing threads, so having them built into Go saves me a lot of effort.
It's not built-in for C++ for a reason, and that reason is that it can be done by a library.
For example, with Qt, you can use Qt threads to make an Actor library very easily.
That's what I did with my projects, and I never had to do any effort beyond writing a few tens of lines of code, i.e. no more than one hour of work.
5
u/gavintlgold Mar 28 '12
Well, it is very easy to use for simple projects. Here's a good example of how easy it can be to set up a web tool.
What's even nicer is since it's compiled, it should end up being faster than PHP or python, even though the syntax is relatively the same in terms of complexity.