"""And when you go with C++ you've forsaken type safety (i.e. memory safety). That's a substantial thing to give up, IMO.""" <- This is true only if you have poorly abstracted type casts. If you design your C++ program correctly, you simply won't ever be type casting or manually handling any of your memory. In fact, with a well designed system, this also solves your issue regarding centralized memory planning. I mean, it is as if you are assuming that once you touch C++ you are going to have a million little calls to malloc() with casts all over the place (which shouldn't even be true in a well-designed C program).
Actually the problem is deeper than this. You can't have type safety w/o memory safety, and it has nothing to do with casting.
Here's an example. You allocate a chunk of memory as type Foo. You use it as Foo. You hand out references to Foo. Everyone is happy. Then someone says, "We don't need this instance of Foo anymore" and deletes it. Someone later comes and allocates Bar and the memory allocator correctly goes and grabs some of Foo's old memory and uses it for Bar.
All good, right? Well, except there's this other thread that is using a reference to that old instance of Foo. Suddenly you have a type safety issue at hand.
Now you can say, "Don't write programs with bugs". And indeed that is just about the only alternative.
My claim is that well designed C++ programs do not have calls to delete at all, not just ones that cause bugs: you come up with your memory abstraction, you build that part of the system (it is likely that this code will have a single call to delete in it), and then your actual program relies on that as a "runtime": if the code in that area calls "delete", you do not allow that code, and treat it as a build failure.
I have been responsible for projects with on the order of hundreds of thousands of line of C++ (such as for a video game we were developing), and the only calls to "delete" were in the stack-locked reference counting implementation I designed, and a few optimized containers. It isn't even hard to think like this in a language like C++, and isn't highly different than a language like Haskell (you build abstractions from unsafePerformIO: you don't routinely code with it).
No; the pointer-to-Foo will always point to the original Foo (unless it's reassigned). The point of the example is to show that type safety depends on not having access explicit heap management.
You're more likely to get silent data corruption without memory safety, than with it.
It has nothing to do with Java specifically, FWIW. Ruby, Python, shell script, C#, Haskell, they are all memory safe. It's a big church.
I don't know if you're being deliberately obtuse. At the semantic level of a memory safe language, there never is any memory reuse, because memory isn't a resource like that. It is impossible to observe memory being reused from within the language. In fact, you could use that as a kind of definition of memory safety. It cuts off a whole kind of memory corruption bug, makes it impossible (aside from bugs in the language and / or runtime, of course).
I'm just going to have to throw up my hands here. The masses on HN are apparently proudly ignorant, and unwilling to learn even the slightest thing before wading in.
It's not completely different from type safety. You're right, they're not the same thing, but GCs prevent a common form of type safety violation. With that said there are other techniques that exist that are orthogonal to GC.
At the same time there are problems, like lack of bounds checking, which can result in type safety issues.
My point isn't that you need a GC per se, but you do need memory safety. GCs happen to be one of the most prevalent ways to achieve it. Someone else in this thread noted that they build a complete runtime that guaratees memory safety and requires their devs to code against that runtime. That's fine too (although I think a lot less common than that poster might lead one to believe). It's almost like the memory safe subset of other popular existing runtimes.
Ok, enlighten me: Assuming you don't have an infinite amount of RAM how do you avoid running out of memory without doing at least one of garbage collection or explicit memory deallocation?
I don't think you understand what memory safety means. Please look it up.
It's independent of how you write or design your program. It's a property of the language + runtime combination.
(Folks out there downvoting me: you could do with some education too... Parent is a completely ignorant (in the best possible sense - easily fixed) comment.)
You cannot escape the world of safety without using an unsafe feature: an unchecked pointer arithmetic or cast operator. These are features I can statically determine you are using from your code, and which I've stated in a well designed system you have fully abstracted out of the actual program.
Yes: in a couple places in your software you will have a cast, but it is about as useful to complain about that as it would be to claim that the JVM itself has a cast operator in it; if the program code isn't using it, then the program code can be proven to be as safe as the runtime, and C++ does not remove your ability to make statements like that.
So no: I believe that your comment is "completely ignorant" (and rude, to boot).
Somehow I feel like if you are spawning off threads while handling a web request, causing concurrency of data generated during the request, you are doing something wrong (that said: I've done it before, in Python; as I did it, however, I believed I was doing something wrong, and the complexity of the code jumped tremendously ;P), but it is a point well taken.
That said, I'm having a difficult time figuring out how that could actually cause a type safety problem, given the same constraints (using a safe memory management framework: garbage collection or stack-locked reference counting). I am totally willing to believe I'm missing something, however; care to provide an example (that does not involve type casts or unbounded pointer arithmetic)?
Wait, you're saying you're using garbage collection in C++? Or you're saying you're using stack-locked reference counting in C++? If the former, you have the same problem as Java: tuning it. If the latter, you've got different performance problems if it's shared between threads. If it's not shared between threads, then you only dodged the question.
I am not claiming a performance improvement, or the lack of having to mess with garbage collection tuning settings. In fact, I have explicitly stated the opposite: that by moving to C++ you do not lose the ability to do global tuning, or even the ability to use a garbage collector to do it.
Nor even is the parent of the post I responded to (as you might then say "well, I am arguing that, and you can't have both"): you easily can have both, as all that these people actually end up doing is brick allocating blocks of objects (either by using C# structs, such as the Stack Overflow articles we've been seeing recently, or doing a poor man's "column store", splitting the fields into arrays, which then causes cache performance issues).
So, as that parent post's parent pointed out, if you are going to go through hell to do that, you may as well do so in C++, as it will be a million times easier (even doing this for their existing managed objects in Managed C++ would have been easier, and it is unfortunate that they didn't evaluate that).
Therefore, with that performance and tuning argument totally removed from the rest of the conversation, I am focussing instead on the irritatingly strong statement "That's a substantial thing to give up, IMO."--a statement I very explicitly pulled away from the unrelated argument in the previous paragraph of the comment--which does not seem at all warranted given the situation, or the facts of these languages.
I mean, the entire premise of this argument is flawed... there are very few systems that actually /are/ type safe, and yet people seem to like using them. We don't even need to go to silly examples like Haskell's unsafePerformIO keyword: C#, a very similar language and one that has been being talked about a lot with respect to GC performance on HN recently (the Stack Overflow article), is quite clearly not type safe, as it allows you to type cast pointers using the "unsafe" keyword.
Of course, you don't have to like people using the "unsafe" keyword, and you can enforce that people on your team not use it; but then that's the real issue: if you are allowed to use the entire specified system, as opposed to restricting yourself to "the known safe subset", then almost no systems of note are actually type safe, partly because users wouldn't stand for it.
With this understanding, we can now go further: Java?... /not type safe/ (sun.misc.Unsafe, as used in the ConcurrentLinkedQueue from earlier in this thread; or more simply, JNI, which people, including myself, use to do all sorts of craziness, even going as far as the JVM itself by backpatching its code at runtime... and I'm not kidding: I actually do that).
Therefore, that anyone is even arguing some hard line that Java is type safe, C++ is not, that the definition is clear, that I'm ignorant for supposedly not understanding that definition (despite spending years researching programming languages and virtual machines in academia, and having implemented multiple), and that this type safety "is a substantial thing to give up", is ludicrous.
On rudeness: I was using ignorant in its strictly technical sense, as in you didn't know the meaning of the phrases I used. You're right in that it was brash; but I was upset that someone had instantly downvoted me when they were WRONG, goddammit!