Seriously. Hillary was openly hostile with Russia, and while I doubt it would have reached the point of increased risk of nuclear war, Russia still has real nukes, so you never know. Trump on the other hand is, if anything, too friendly with Russia.
Trump and Hillary had similar strategies. They wanted a plausible external enemy that they could blame. Hillary was smarter, because she picked Russia when Trump picked China. The US economy could easily survive complete isolation from Russia, but couldn't survive isolation from China without a lot of careful planning (China has either the second or third highest GDP, depending on whether you count the EU as a single entity or not, Russia comes in 12th, even behind Italy).
Unfortunately, the converse is also true: if Trump damages US-China trade, then it's going to hurt China about as much as it will hurt the USA, and China is a country with a strong military, nuclear weapons, a surplus of men (about a hundred more military-age men than women of similar age) and a need to present the ruling elite as infallible. That's not a good combination.
OSMAnd has a world map that is about 30MB and gives you the country and major cities, but nothing much beyond that. Detailed maps for European countries or US states weigh in at 100-300MB (except France, which seems to have incredibly detailed maps and is a few GBs). Routing works offline and I can easily store a map of my home country and half a dozen countries that I've visited recently or plan to visit soon on my cheap 3-year-old phone.
If MS can bring Windows Server down to 2-3GB (uncompressed)
Windows 2000 Advanced Server was slightly cramped on a 1GB disk, but fitted fine. 2-3GB is a very low bar for an OS. A full install of the FreeBSD plus web, mail, and DNS servers is well under 1GB.
Same here, though for a subtly different reason. If you rate everything 1, then it's easy to discount (you're just difficult to please). If you rate the people 10 but everything that's part of the institutional structure 1-3 then they get a data point of someone who is using the full range of the rating system and thinks that everyone except the easily-firable staff is dangerously incompetent.
Many years ago, I participated in a focus group for a marketting company (rating some new ads for Pepsi). They asked us to rate things from -5 to +5. It was quickly apparent that most people in the group didn't understand negative numbers, so rated from 0-5. I am certain that, when they presented the numbers to their client, they gave them in a range of 0-10 and were able to say that all of the scores were broadly positive.
There are two kinds of ad. The first kind makes you aware of something that you didn't know existed and gives you information about the product. Not only are these useful, they're so useful that many people actually pay to receive them in various forms (trade magazines and so on). The second kind tries to persuade you to buy something that you probably don't need and wouldn't want without the advertising. These are the mental equivalent of punching someone in the face and the law ought to treat them as such.
And if your thrown exception type is not a derived class, then it should just be a pointer comparison anyhow
No, you only get to make the saving if you're in a language that doesn't permit subclassing. In a few cases (e.g. throwing an int) you could special case it to generate a simple comparison, but that case is sufficiently rare that it's not worth optimising for. In C++11, if a class in a catch block is marked as final then you could potentially do the same optimisation, but most exceptions are subclasses of std::exception or some library-specific equivalent, so that's also pretty unusual and not worth optimising for.
Multiple catch blocks is no different from a switch on a return code
No it isn't. If I write try {...} catch (foo e) {} catch (bar e), then I must check first if the thrown exception is a subclass of foo, then if it's a subclass of bar. It's only a simple switch for a language that doesn't allow subtyping so I have a unique value for each type and only exceptions of type foo are caught by the first and exceptions of type bar are caught by the second catch.
Your point is that if you restrict the language semantics to something less expressive than the current exception model then you can make it more efficient, at the cost of generality. That's true, but not particularly relevant to why exceptions are expensive for a language that has rich exception semantics.
What the hell does the CPU generation have to do with the amount of RAM in a device?
For about the last 10 years, the memory controller has been on the CPU, so the maximum amount of RAM that a device can support is controlled by the CPU. No Intel mobile chips has ever supported more than 16GB of LPDDR, so that's the limit that we have for mobile devices (unless you want to use full-power DDR and either have crappy battery life or a battery so large that the FAA won't let you take it on a plane).
Even if I could upgrade this one, it has the maximum amount of RAM that the memory controller supports, so removable RAM wouldn't help. It would make it cheaper to replace the RAM in the case of a fault, but I had a PowerBook go back in for repairs 7 times because the DIMM slots kept popping off the logic board slightly (just enough to cause data loss in RAM) when the machine got hot, so soldering the RAM to the board probably improves reliability there.
LLVM code is mostly pretty nice. They adopted a lot of C++11 library features with their own implementations before they were standard and then replaced them with C++11 when it was widely supported. For example, llvm::OwningPtr was originally a purely local implementation, then had an #ifdef so if you were compiling with a modern compiler and standard library it was just another name for std::unique_ptr, and eventually uses were all replaced with std::unique_ptr and the LLVM class went away. Oh, and when lambdas were supported widely a whole load of copy and pasted code was replaced with a lambda that was just called in the function - compilers are really good at inlining these, so you end up with identical binary code, but much simpler sources.
I've found that there are two really bad ways to write C++. One is to think of it as a C-like language and try to write in the style of C. The other is to think of it as an OO language and write Smalltalk-like code. The language supports both styles (though supports the latter less well), but it doesn't do either very well.
Because unwinding into a stack frame involves finding where the called frame spilled any registers and restoring it. The Itanium ABI (which all UNIX systems use) specifies DWARF unwind data for this. The callee can spill things on the stack, move them to different registers, and so on. You must first parse tables to find where all of these things are and reconstruct a register set for the next stack frame that you're unwinding into. You then need to determine whether the frame is going to catch the exception. For C++, this involves first checking whether it's a C++ exception. If so, then you next have a list of possible catch blocks. Each has an associated type_info object. You then have to call the check method on the type_info objects to see if the thrown object is compatible (which, in cases of diamond inheritance is very expensive and in cases of simple inheritance involves walking a linked list). If none of the catch blocks match or it's a foreign exception, but there is a catchall (catch(...) block) then you jump there. If there's no catchall, but any local objects have nontrivial destructors, then you have to do a cleanup, which will then resume unwinding at the end.
The decision to walk the stack twice is to allow language semantics (C++ supports this, as do a few other languages) where unhandled exceptions invoke a handler on top of the stack, without destroying any current stack frames. The simplest use for this is to print a stack trace of where an unhandled exception was thrown before terminating, but it's also allowed for a program to walk up the stack running cleanups and gracefully terminate a thread that has an unhandled exception, or do something like aborting any in-flight transactions from that thread and shutting down the program gracefully.
Oh, and in C++11 you're allowed to catch the exception, encapsulate the in-flight exception in an object, and then pass it to another thread for handling (rethrowing it there). Or simply defer it and rethrow it later. All of this adds complexity.
TL;DR: Exception throwing machinery is complex because the semantics of exceptions are far more complex than simply 'oh, this thing returned an error, run cleanup code'.
Yup. I have a late 2013 MacBook Pro and our usual upgrade cycle is 3 years. Work would buy a new one, but I'm waiting until the next generation of CPUs so that I can get one with 32GB of RAM. There hasn't been a single compelling update to the MBP line since 2013 (Haswell).
It seems that jargon nuance is lost over time. The term emulator in technical jargon refers to something emulating a separate machine code instruction set or other hardware
This is simply not true. Even in the '70s the term encompassed a lot more. There's a reason that the term 'machine emulator' was in common usage for a while. It's only recently that 'emulator' has been shorthand for 'machine emulator'.
The JVM itself is an emulator, emulating an invented instruction set
No it isn't, because for something to be an emulator there must be something that it is emulating. If the emulated thing does not exist, then it is a simulator not an emulator. The JVM isn't even that, it is a virtual machine.
execve isn't particularly simple. When you do execve on a UNIX system, you're inheriting a bunch of things such as file descriptor tables. In Windows, the process creation mechanism is entirely different.
It's not laziness, it's generality. When you have exceptions, you're unwinding an arbitrary number of stack frames. When I throw a C++ exception, I have no control over the languages of the intervening stack frames. They might be C, Objective-C, Java (with gcj), Fortran, Algol, Go, Swift, or something else. The unwinder has to be able to run cleanups for all of them. If you're willing to sacrifice the ability to call between languages, then you can optimise (which Java can, because it has an entirely different mechanism for propagating exceptions through JNI frames, which most JNI code gets wrong).
True (and there's no social mobility in the book, which adds another point that's converging with reality). Actually, I'd say that the biggest differences with the book are that the overwhelming majority of people in Brave New World were happy, contented and fulfilled, there was no unemployment or underemployment, and no poverty or wealth inequality.
And legalised drugs, sorting people into social classes based on intelligence, procreation entirely through industrial processes, and a purely centrally planned and managed economy. I'm guessing lobiusmoop hasn't actually read Brace New World and just wants to sound literate.
In Nineteen Eighty-Four, it's not clear whether Big Brother even exists and it's implied that he's an entirely fictional construct to provide a focus for popular belief (and the Goldstein might be as well). The book doesn't contain any direct actions of him other than a couple of carefully choreographed speeches, so I'm not sure where you get an idea about his emotional maturity from.
On the other hand, in WSL you can start amd64 Linux ELFs and nothing else. A compat layer on Windows that can't even interact with Windows -- what's the point?
You can, at least, interact with the filesystem, and I think some forms of IPC work between the Windows and Linux worlds. This isn't new for Windows: NT 4 had a POSIX compatibility layer that, like WSL, was a separate OS personality. It implemented the minimum possible amount of POSIX (anything allowed to simply return not-implemented errors did) and gave you a completely distinct set of APIs. But it let them tick the checkbox...
X11 makes this easier on *NIX systems because it's intrinsically designed for remote display, so all of the communication is via well-defined IPC mechanism. If you run a Linux binary on FreeBSD, the Linux system calls are translated into FreeBSD ones at the syscall layer (in a similar way to how WSL works), but the UNIX domain socket and shared memory regions that you use for communicating with the X server are the same on both operating systems and so you can easily run graphical Linux and FreeBSD applications that interact with the same clipboard and so on with no interposition.
My understanding is that rather than an emulator, it's just an API wrapper, or alternatively a simulator or maybe "high level emulator", but I'm not an expert on how you name these things.
It's an implementation of the Win32 APIs. Microsoft has implemented many of these twice (though often sharing code), once atop the services provided by the Windows 9x series of operating systems and once atop those provided by the Windows NT kernel. In this sense, WINE is no more an emulator than Windows 7 is when it provides reimplemented APIs created for Windows 95.
WINE is a little bit more like an emulator, in that it is often providing Windows services atop other APIs with a similar level of abstraction. For example, WINE translates Direct3D into OpenGL, whereas the Windows implementation translates Direct3D into the APIs used by the top of the 3D device driver. It doesn't always work this way though. Windows font, windowing, and 2D drawing are all implemented by WINE on top of lower-level APIs and there was some work a couple of years back to provide a Direct3D state tracker in Gallium, allowing WINE to directly translate Direct3D into things consumed by the top of the GPU driver stack, just as the Windows implementation does.
If WINE is an emulator, then GNU Classpath running on the Kaffee JVM is an emulator of the Sun JVM.
Plus, people just assume any C++ feature that's not in C must be slow, so the idea of cleaning up allocations and whatnot automatically as part of stack unwind must somehow be slower than writing all that code manually at the bottom of every function.
It's important to separate the mechanism from the implementation. I know of five mechanisms that mainstream languages have used to implement exceptions:
Make every try block a setjmp, every throw a longjmp. Put the exception in a thread-local variable and put the handling code in the conditional path from the setjmp.
Reserving a second return register for the exception and following every call with a branch on that register value.
Following every call instruction with a branch to the exception handler and making the normal return path return to the following instruction (return address plus the size of one instruction).
Emitting unwind tables that describe to some support code how to unwind each stack frame and where to go for each kind of cleanup.
Creating a linked list of functions in thread-local storage that know how to do the unwinding.
The first is a terrible way of implementing exceptions, because it makes throwing exceptions quite cheap but entering try / catch blocks very expensive. It was easy though, so a lot of systems used it. Java implementations often use one of the next two, because exceptions are quite common and want to be on the fast path. These have very similar performance characteristics, independent of whether you take the normal or exceptional return path.
The next one is the so-called 'zero-cost exception' model. This is used on most UNIX (and bare metal / embedded) systems. If you don't enter the exception path, these are almost free (the overhead comes from the fact that you split basic blocks to allow for the exceptional control flow path and so make some compiler optimisations less efficient). The cost of throwing an exception is very high in this model. You first call into the language runtime library, which allocates space to store the exception and some structures for storing the unwind state. It then calls into the generic unwinder, which parses some data structures (DWARF frame descriptions on UNIX systems), constructs a partial unwind state, then calls into the language-specific personality function (32-bit ARM has a few optimisations on this that reduce flexibility but generate smaller code, but the approach is broadly the same), which then parses some more data structures to work out whether to catch the exception, whether it needs to run cleanups, or whether this frame is safe to ignore. Once the generic unwinder has found a place that catches the exception, calls back into the personality function for each frame that needed to run cleanups. Each call provides the landing pad for the cleanups and the personality function unwinds the stack to that function and allows it to continue. This function then calls back into the generic unwinder, which then repeats the process until you end up at the catch frame. At the end of the catch statement, the catching function calls back into the language runtime, which frees language-specific data structures and the unwind state.
The final approach is used on Windows. This is slightly cheaper to use because each of the functions that handles the unwinding (called funclets in Windows terminology) runs on the top of the stack, but with a pointer into the stack frame that it's unwinding. If they're running cleanups, then they destroy objects in place, then tail call the next funclet. The one that handles the cleanup then transfers control back to the original function.
The problem for embedded programming is that the exception path and the non-exception path have very different performance characteristics. Exception implementations (particularly for C++) tend to assume that exceptions happen in exceptional circumstances and so optimise for the non-exceptional c
That's a false dichotomy. The Ingalls definition of an OO language is one in which you can declare a new kind of integer and use it to describe the coordinates of a window that you place on the screen. Concepts are a lot closer to this definition than C++'s attempt at OO. I suspect that a lot of the hostility towards OO comes from languages like C++ that get the rough shape of OO right but without getting most of the useful parts.
Seriously. Hillary was openly hostile with Russia, and while I doubt it would have reached the point of increased risk of nuclear war, Russia still has real nukes, so you never know. Trump on the other hand is, if anything, too friendly with Russia.
Trump and Hillary had similar strategies. They wanted a plausible external enemy that they could blame. Hillary was smarter, because she picked Russia when Trump picked China. The US economy could easily survive complete isolation from Russia, but couldn't survive isolation from China without a lot of careful planning (China has either the second or third highest GDP, depending on whether you count the EU as a single entity or not, Russia comes in 12th, even behind Italy).
Unfortunately, the converse is also true: if Trump damages US-China trade, then it's going to hurt China about as much as it will hurt the USA, and China is a country with a strong military, nuclear weapons, a surplus of men (about a hundred more military-age men than women of similar age) and a need to present the ruling elite as infallible. That's not a good combination.
OSMAnd has a world map that is about 30MB and gives you the country and major cities, but nothing much beyond that. Detailed maps for European countries or US states weigh in at 100-300MB (except France, which seems to have incredibly detailed maps and is a few GBs). Routing works offline and I can easily store a map of my home country and half a dozen countries that I've visited recently or plan to visit soon on my cheap 3-year-old phone.
Why is someone earning over $400k and still sharing a room? Are you both living on the ISS?
If MS can bring Windows Server down to 2-3GB (uncompressed)
Windows 2000 Advanced Server was slightly cramped on a 1GB disk, but fitted fine. 2-3GB is a very low bar for an OS. A full install of the FreeBSD plus web, mail, and DNS servers is well under 1GB.
But our compiler makes SPEC run really fast! It must be your code that's wrong!
Same here, though for a subtly different reason. If you rate everything 1, then it's easy to discount (you're just difficult to please). If you rate the people 10 but everything that's part of the institutional structure 1-3 then they get a data point of someone who is using the full range of the rating system and thinks that everyone except the easily-firable staff is dangerously incompetent.
Many years ago, I participated in a focus group for a marketting company (rating some new ads for Pepsi). They asked us to rate things from -5 to +5. It was quickly apparent that most people in the group didn't understand negative numbers, so rated from 0-5. I am certain that, when they presented the numbers to their client, they gave them in a range of 0-10 and were able to say that all of the scores were broadly positive.
There are two kinds of ad. The first kind makes you aware of something that you didn't know existed and gives you information about the product. Not only are these useful, they're so useful that many people actually pay to receive them in various forms (trade magazines and so on). The second kind tries to persuade you to buy something that you probably don't need and wouldn't want without the advertising. These are the mental equivalent of punching someone in the face and the law ought to treat them as such.
And if your thrown exception type is not a derived class, then it should just be a pointer comparison anyhow
No, you only get to make the saving if you're in a language that doesn't permit subclassing. In a few cases (e.g. throwing an int) you could special case it to generate a simple comparison, but that case is sufficiently rare that it's not worth optimising for. In C++11, if a class in a catch block is marked as final then you could potentially do the same optimisation, but most exceptions are subclasses of std::exception or some library-specific equivalent, so that's also pretty unusual and not worth optimising for.
Multiple catch blocks is no different from a switch on a return code
No it isn't. If I write try {...} catch (foo e) {} catch (bar e), then I must check first if the thrown exception is a subclass of foo, then if it's a subclass of bar. It's only a simple switch for a language that doesn't allow subtyping so I have a unique value for each type and only exceptions of type foo are caught by the first and exceptions of type bar are caught by the second catch.
Your point is that if you restrict the language semantics to something less expressive than the current exception model then you can make it more efficient, at the cost of generality. That's true, but not particularly relevant to why exceptions are expensive for a language that has rich exception semantics.
What the hell does the CPU generation have to do with the amount of RAM in a device?
For about the last 10 years, the memory controller has been on the CPU, so the maximum amount of RAM that a device can support is controlled by the CPU. No Intel mobile chips has ever supported more than 16GB of LPDDR, so that's the limit that we have for mobile devices (unless you want to use full-power DDR and either have crappy battery life or a battery so large that the FAA won't let you take it on a plane).
Even if I could upgrade this one, it has the maximum amount of RAM that the memory controller supports, so removable RAM wouldn't help. It would make it cheaper to replace the RAM in the case of a fault, but I had a PowerBook go back in for repairs 7 times because the DIMM slots kept popping off the logic board slightly (just enough to cause data loss in RAM) when the machine got hot, so soldering the RAM to the board probably improves reliability there.
LLVM code is mostly pretty nice. They adopted a lot of C++11 library features with their own implementations before they were standard and then replaced them with C++11 when it was widely supported. For example, llvm::OwningPtr was originally a purely local implementation, then had an #ifdef so if you were compiling with a modern compiler and standard library it was just another name for std::unique_ptr, and eventually uses were all replaced with std::unique_ptr and the LLVM class went away. Oh, and when lambdas were supported widely a whole load of copy and pasted code was replaced with a lambda that was just called in the function - compilers are really good at inlining these, so you end up with identical binary code, but much simpler sources.
I've found that there are two really bad ways to write C++. One is to think of it as a C-like language and try to write in the style of C. The other is to think of it as an OO language and write Smalltalk-like code. The language supports both styles (though supports the latter less well), but it doesn't do either very well.
Because unwinding into a stack frame involves finding where the called frame spilled any registers and restoring it. The Itanium ABI (which all UNIX systems use) specifies DWARF unwind data for this. The callee can spill things on the stack, move them to different registers, and so on. You must first parse tables to find where all of these things are and reconstruct a register set for the next stack frame that you're unwinding into. You then need to determine whether the frame is going to catch the exception. For C++, this involves first checking whether it's a C++ exception. If so, then you next have a list of possible catch blocks. Each has an associated type_info object. You then have to call the check method on the type_info objects to see if the thrown object is compatible (which, in cases of diamond inheritance is very expensive and in cases of simple inheritance involves walking a linked list). If none of the catch blocks match or it's a foreign exception, but there is a catchall (catch(...) block) then you jump there. If there's no catchall, but any local objects have nontrivial destructors, then you have to do a cleanup, which will then resume unwinding at the end.
The decision to walk the stack twice is to allow language semantics (C++ supports this, as do a few other languages) where unhandled exceptions invoke a handler on top of the stack, without destroying any current stack frames. The simplest use for this is to print a stack trace of where an unhandled exception was thrown before terminating, but it's also allowed for a program to walk up the stack running cleanups and gracefully terminate a thread that has an unhandled exception, or do something like aborting any in-flight transactions from that thread and shutting down the program gracefully.
Oh, and in C++11 you're allowed to catch the exception, encapsulate the in-flight exception in an object, and then pass it to another thread for handling (rethrowing it there). Or simply defer it and rethrow it later. All of this adds complexity.
TL;DR: Exception throwing machinery is complex because the semantics of exceptions are far more complex than simply 'oh, this thing returned an error, run cleanup code'.
Yup. I have a late 2013 MacBook Pro and our usual upgrade cycle is 3 years. Work would buy a new one, but I'm waiting until the next generation of CPUs so that I can get one with 32GB of RAM. There hasn't been a single compelling update to the MBP line since 2013 (Haswell).
It seems that jargon nuance is lost over time. The term emulator in technical jargon refers to something emulating a separate machine code instruction set or other hardware
This is simply not true. Even in the '70s the term encompassed a lot more. There's a reason that the term 'machine emulator' was in common usage for a while. It's only recently that 'emulator' has been shorthand for 'machine emulator'.
The JVM itself is an emulator, emulating an invented instruction set
No it isn't, because for something to be an emulator there must be something that it is emulating. If the emulated thing does not exist, then it is a simulator not an emulator. The JVM isn't even that, it is a virtual machine.
execve isn't particularly simple. When you do execve on a UNIX system, you're inheriting a bunch of things such as file descriptor tables. In Windows, the process creation mechanism is entirely different.
It's not laziness, it's generality. When you have exceptions, you're unwinding an arbitrary number of stack frames. When I throw a C++ exception, I have no control over the languages of the intervening stack frames. They might be C, Objective-C, Java (with gcj), Fortran, Algol, Go, Swift, or something else. The unwinder has to be able to run cleanups for all of them. If you're willing to sacrifice the ability to call between languages, then you can optimise (which Java can, because it has an entirely different mechanism for propagating exceptions through JNI frames, which most JNI code gets wrong).
True (and there's no social mobility in the book, which adds another point that's converging with reality). Actually, I'd say that the biggest differences with the book are that the overwhelming majority of people in Brave New World were happy, contented and fulfilled, there was no unemployment or underemployment, and no poverty or wealth inequality.
If that were true, then the phrase 'I'm not a racist but...' would be a lot less widely used.
And legalised drugs, sorting people into social classes based on intelligence, procreation entirely through industrial processes, and a purely centrally planned and managed economy. I'm guessing lobiusmoop hasn't actually read Brace New World and just wants to sound literate.
In Nineteen Eighty-Four, it's not clear whether Big Brother even exists and it's implied that he's an entirely fictional construct to provide a focus for popular belief (and the Goldstein might be as well). The book doesn't contain any direct actions of him other than a couple of carefully choreographed speeches, so I'm not sure where you get an idea about his emotional maturity from.
On the other hand, in WSL you can start amd64 Linux ELFs and nothing else. A compat layer on Windows that can't even interact with Windows -- what's the point?
You can, at least, interact with the filesystem, and I think some forms of IPC work between the Windows and Linux worlds. This isn't new for Windows: NT 4 had a POSIX compatibility layer that, like WSL, was a separate OS personality. It implemented the minimum possible amount of POSIX (anything allowed to simply return not-implemented errors did) and gave you a completely distinct set of APIs. But it let them tick the checkbox...
X11 makes this easier on *NIX systems because it's intrinsically designed for remote display, so all of the communication is via well-defined IPC mechanism. If you run a Linux binary on FreeBSD, the Linux system calls are translated into FreeBSD ones at the syscall layer (in a similar way to how WSL works), but the UNIX domain socket and shared memory regions that you use for communicating with the X server are the same on both operating systems and so you can easily run graphical Linux and FreeBSD applications that interact with the same clipboard and so on with no interposition.
My understanding is that rather than an emulator, it's just an API wrapper, or alternatively a simulator or maybe "high level emulator", but I'm not an expert on how you name these things.
It's an implementation of the Win32 APIs. Microsoft has implemented many of these twice (though often sharing code), once atop the services provided by the Windows 9x series of operating systems and once atop those provided by the Windows NT kernel. In this sense, WINE is no more an emulator than Windows 7 is when it provides reimplemented APIs created for Windows 95.
WINE is a little bit more like an emulator, in that it is often providing Windows services atop other APIs with a similar level of abstraction. For example, WINE translates Direct3D into OpenGL, whereas the Windows implementation translates Direct3D into the APIs used by the top of the 3D device driver. It doesn't always work this way though. Windows font, windowing, and 2D drawing are all implemented by WINE on top of lower-level APIs and there was some work a couple of years back to provide a Direct3D state tracker in Gallium, allowing WINE to directly translate Direct3D into things consumed by the top of the GPU driver stack, just as the Windows implementation does.
If WINE is an emulator, then GNU Classpath running on the Kaffee JVM is an emulator of the Sun JVM.
Plus, people just assume any C++ feature that's not in C must be slow, so the idea of cleaning up allocations and whatnot automatically as part of stack unwind must somehow be slower than writing all that code manually at the bottom of every function.
It's important to separate the mechanism from the implementation. I know of five mechanisms that mainstream languages have used to implement exceptions:
The first is a terrible way of implementing exceptions, because it makes throwing exceptions quite cheap but entering try / catch blocks very expensive. It was easy though, so a lot of systems used it. Java implementations often use one of the next two, because exceptions are quite common and want to be on the fast path. These have very similar performance characteristics, independent of whether you take the normal or exceptional return path.
The next one is the so-called 'zero-cost exception' model. This is used on most UNIX (and bare metal / embedded) systems. If you don't enter the exception path, these are almost free (the overhead comes from the fact that you split basic blocks to allow for the exceptional control flow path and so make some compiler optimisations less efficient). The cost of throwing an exception is very high in this model. You first call into the language runtime library, which allocates space to store the exception and some structures for storing the unwind state. It then calls into the generic unwinder, which parses some data structures (DWARF frame descriptions on UNIX systems), constructs a partial unwind state, then calls into the language-specific personality function (32-bit ARM has a few optimisations on this that reduce flexibility but generate smaller code, but the approach is broadly the same), which then parses some more data structures to work out whether to catch the exception, whether it needs to run cleanups, or whether this frame is safe to ignore. Once the generic unwinder has found a place that catches the exception, calls back into the personality function for each frame that needed to run cleanups. Each call provides the landing pad for the cleanups and the personality function unwinds the stack to that function and allows it to continue. This function then calls back into the generic unwinder, which then repeats the process until you end up at the catch frame. At the end of the catch statement, the catching function calls back into the language runtime, which frees language-specific data structures and the unwind state.
The final approach is used on Windows. This is slightly cheaper to use because each of the functions that handles the unwinding (called funclets in Windows terminology) runs on the top of the stack, but with a pointer into the stack frame that it's unwinding. If they're running cleanups, then they destroy objects in place, then tail call the next funclet. The one that handles the cleanup then transfers control back to the original function.
The problem for embedded programming is that the exception path and the non-exception path have very different performance characteristics. Exception implementations (particularly for C++) tend to assume that exceptions happen in exceptional circumstances and so optimise for the non-exceptional c
That's a false dichotomy. The Ingalls definition of an OO language is one in which you can declare a new kind of integer and use it to describe the coordinates of a window that you place on the screen. Concepts are a lot closer to this definition than C++'s attempt at OO. I suspect that a lot of the hostility towards OO comes from languages like C++ that get the rough shape of OO right but without getting most of the useful parts.