Slashdot Mirror


User: Deorus

Deorus's activity in the archive.

Stories
0
Comments
543
First seen
Last seen
Profile
(view on slashdot.org)

Comments · 543

  1. Re:Thanks Apple on Apple Tells Retailers To Stop Selling Certain Samsung Devices · · Score: 2

    No evidence. Assumption bias fueled hypocrisy.

    If there is assumption bias, it is not mine, though you can always wait for the earnings conference calls to be sure.

    Is there no doubt as to why analytical people despise Apple culture with such fervor that they will avoid it even when it is a reasonable alternative?

    The term you're looking for is rational, and if you avoid something when it's a reasonable alternative then you are not being rational yourself.

  2. Re:Apple: You do the nice gear... on Apple Tells Retailers To Stop Selling Certain Samsung Devices · · Score: 1

    So you support all actions taken by MPAA and RIAA?

    I agree with the grandparent, and that doesn't mean I support the RIAA/MPAA. The main reason why I don't support them is because they abuse the courts in order to gain information about citizens that they should never have access to in order to practice extortion. Instead they should just complain to an authority, mention all the steps they took in order to prevent the violations, and only then expect authorities to take action. This is essentially what Apple is doing, they are making sure that no retails can claim lack of knowledge by directly informing them and guaranteeing that they will face consequences should that not be enough. Apple is not extorting anyone here.

  3. Re:annoying? on Apple Tells Retailers To Stop Selling Certain Samsung Devices · · Score: 0

    It's annoying to support this kind of bickering with my dollars.

    You aren't supporting anything, you paid for actual products, it wasn't a donation.

    At least since I really want 75% of all tech patents invalidated (because they are too obvious) and don't think software patents should exist at all.

    Invalidation is not the proper way to deal with the problem as it won't change the system in any way. The best way to change the system is to actually push for this kind of legal warfare until governments realize that it's causing more harm than good (assuming it actually is). Even then care must be taken to ensure that the solution doesn't end up being worse than the original problem.

    If you buy from a company you are supporting their business practices, all of them.

    No I am not, I am buying a product.

    Don't know about "annoying" but it's quite legitimate to scrutinize what you are patronizing. It's no surprise that not everyone will like how a given company does business.

    You are perfectly justified to opt out if a company does not do business with you the way you think they should; how they do business with others in order to serve your needs, however, should be no concern to you. It does not make sense to be concerned about that because that ethical mentality is a huge can of worms and you'd not really be buying anything from anyone if you knew everything there is to know about their business practices. If you want to care, then at least be glad that Apple is actually open about their business practices, unlike many other companies.

  4. Re:Thanks Apple on Apple Tells Retailers To Stop Selling Certain Samsung Devices · · Score: 0, Flamebait

    That's no more evidence of strong demand than it is of short supply. Furthermore, how can you claim that iPads are sitting in the stores? Do you work for a retailer? The iPad 3 was on a worldwide short supply for months, and that was effectively due to huge demand!

  5. Re:annoying? on Apple Tells Retailers To Stop Selling Certain Samsung Devices · · Score: 1

    How's it getting annoying? How's it even affecting you?

  6. Re:Not the first to do it on Russian Hacker Sidesteps Apple iOS In-App Purchases · · Score: 1

    Its not that he was the first that shocked anyone, its that he pulled it off WITHOUT jailbreaking the phone using DNS redirects and user-installed certs

    Yes, he exploited common vulnerabilities on random apps. How innovative! It's almost like mass-exploiting Wordpress and claiming that the OS running it is not secure.

  7. Re:One good reason... on What's To Love About C? · · Score: 1

    In another post, you claimed that C++ is only missing features, and there is no safety issue. Are you changing you mind about that one? The C++ standard requires a basic_filebuf to perform a sync in its destructor, and to allow that sync to silently fail.

    I never said that the language didn't have safety issues, what I said was that the language was missing features, not safety, as in I don't need it to be safer, I just want more features.

    OK, but what about errors that are the result of an attempt to free resources, like an I/O error that results from closing a file?

    That's not an error resulting from attempting to free the resource, that's an error resulting from attempting to sync it. If you want to be clean (and slow) you can always fsync() first to separate the synchronization from the deallocation, otherwise you can just treat close() as a dirty call with double intent, throw exceptions relating to the deallocation task, and ignore the rest.

    Are we going to loop on this? Sometimes errors occur while resources are being freed. If an exception cannot leave a destructor, then the destructor is responsible for both freeing resources and for dealing with errors, or else you just abort whenever you have an error while freeing resources.

    Until you understand it, I am afraid so. All exceptions relating to freeing resources should be let through, because if a destructor can't deallocate, then the program has crashed; all other exceptions must be suppressed. How messy this ends up being depends on how messy the rest of your code is.

    As an example, the exception might have been thrown in the middle of writing record-oriented data (i.e. the logging facility threw an exception before the record was completely written); if you are unable to resume the operation, then you will either need to have a way to roll back the partially completed write (which may be ugly, e.g. if your stream was a socket), or a way to keep track of how much you had written (or the third option: you wind up with a corrupt file). Restarts provide a much cleaner solution here: if the error can be corrected or if it is safe to ignore, you can safely continue with the operation, without having to waste time on rolling things back and without having to keep redundant information about how much had been written (which is already tracked by the stream, except that the stream has no knowledge of your record structure). You also allow the clients of your class to decide priorities without having to know the details of your implementation: maybe logging is not important and can be skipped, or maybe logging is of equal importance to writing the records.

    Can you please give me an example of an error worthy of an exception that can be corrected without human interaction? Following that also provide an explanation as to why the caller would be better suited to correct the error than the callee when the caller isn't supposed to know anything about the callee's internals (this is how the self-containment principle is violated).

  8. Re:One good reason... on What's To Love About C? · · Score: 1

    Well, it may just be a matter of opinion at this point, but if you are using RTTI to do something that your compiler could have done for you, then I would say you are writing a hack. This is not always the case, of course; dynamic_cast should be used if you are performing a cast down an inheritance hierarchy, but cannot guarantee that the cast will be valid (i.e. the client might use your code the wrong way, in which case an exception should be thrown). That is not the case here; here, you are using RTTI to implement a missing language feature (multiple dispatch); you might not call it a hack, but I would, just like I would call implementing objects in C by using structs and function pointers a hack.

    My compiler is pretty much doing it for me, and that its way of doing it; typeid is an operator. It's done this way because fortunately C++ is a static language and requires compile-time resolution, otherwise you'd be getting runtime error for things that could and should have been fixed before the code was even compiled.

    Well until C++11, lambda expressions -- yes, there was the Boost lambda expressions library, but that was not quite what was needed and it was not part of the standard. It would also be nice to have a built-in multiple dispatch facility (see above; the language only provides bits and pieces that can be used to implement multiple dispatch by hand), a more complete introspection system (not something I frequently use, but some people do), restarts or continuations (beyond what you can hack together with setjmp and longjmp), etc. The C++ language is missing quite a few modern features that other languages provide.

    In essence, you want to turn a static language into a dynamic language. Not going to happen. Regarding introspection, you can already do it with templates, except for structs, which for now you have to emulate using tuples. Restarts are something that I strongly oppose because they only address the representation of your program in memory, and your objects can represent a lot more than that.

    Which is just a way of saying, "The standard is missing the things you need in those cases." If you are using the word "custom," then you are no longer talking about what the language itself provides.

    Who cares? The tools are there, build your house! I could see the reason to complain about that in C, but in C++ I really don't. Even in C you have debugger implementations that pretty much do that for you (Valgrind).

    Even if that statement were true, it would be a huge improvement to move to higher level languages.

    Performance matters.

    Which are not standardized across operating systems, hardware architectures, etc. If these things are necessary for C++ programmers to do their work effectively, then they should be part of the standard.

    They are not necessary, but the advantage of native code is that it is very easy to debug and there are plenty of tools to do it.

    See my other post about restarts; basically, when an exception is thrown, it should be possible for the thrower to set restart points that the exception handler can jump to once the error is corrected (or perhaps if the error can safely be ignored, etc.).

    You should not be catching exceptions to correct errors.

    That is not true; if the error can be corrected, the destructor can continue executing and the program will be fine. That's the point of restarts.

    If there is an error that can be correct, then you should have avoided it in the first place. Exceptions are supposed to be unrecoverable.

    No, inexperienced programmers violate them as well. If you know how to write a cast (a novice level construct) then you know how to make an undefined conversion between pointer types.

    Ju

  9. Re:One good reason... on What's To Love About C? · · Score: 1

    OK, but if the error can be corrected, then the destructor can proceed. Are you suggesting that the class should know both how to deallocate itself and how to correct external errors?

    No, I am suggesting that destruction time is too late tot hunk about external problems.

    Which means that there is a class of errors that the clients of the class will never have the ability to handle. Even something as simple as logging errors cannot happen under that rule.

    Yes, that class of errors is called a program crash.

    Then why sync at all? If it is not something that should be expected to work properly, then it is not something that should be done.

    From a design point of view, it makes no sense because your caller isn't expecting it; from a quality point of view, it makes your class a little more reliable.

    I am not seeing why that is any more wrong than throwing an exception from a constructor or a member function.

    Because unlike all other functions in a class, destructors are supposed to remain reliable even when the rest of the class is in an invalid state. If the destructors themselves become unreliable, then there is no way to destroy a class in an invalid state and the program has technically crashed because the principle of determinism has been violated.

    The approach you are suggesting is that if the destructor does not have any good way to deal with an error, the destructor should just fail silently. Even a global error flag is better than that.

    I never said that a destructor should fail silently, I said that exceptions unrelated to deallocation should be caught by the destructor because those do not compromise the destructor's purpose, which is to deallocate everything.

    We can have both reliability and performance, by allowing errors to be corrected.

    The current implementation already allows errors to be corrected.

    The ugly way to do that is to enclosing synchronization routines in loops, and to have catch blocks that take corrective action and then resume the loop.

    You catch exceptions to prevent your code from crashing, not to correct errors. Exceptions are supposed to be unrecoverable; there is no retrying unless you are in an interactive session with a user and that user specifically tells you to retry.

    So off the bat, you just dismiss the idea that you could ever correct the error and continue the execution of whatever code caused the exception to be thrown.

    Yes. If you could have done it right then you should have done it right.

    If you have an object that will write to a file, and you catch an exception that indicates the disk is full, what will you do?

    Depends on the code. If the code is part of a user interface which primary objective is to write to a file, then I will present the user with a pretty prompt and let them decide what to do. If the code is a function which primary objective to write to a file, then I will let the exception through because it is related to the task that I was expected to perform. If the code is a function which primary objective is not to write to a file but I called a function which primary objective is to write to a file, then i will catch and suppress the exception, because writing to a file is not part of the task that I was expected to perform. If the code is a function which primary objective is not to write to a file and I called a function which primary objective is not to write to a file, then I will let the exception through because this is a bug and the program must abort. In essence I only catch exceptions at user interfaces or when I am performing tasks that are unrelated to the purpose of the task that I am expected to be performing. For the pur

  10. Re:One good reason... on What's To Love About C? · · Score: 1

    No, it is just a hack using RTTI. You might as well claim that using a textbook visitor pattern means that you have double dispatch; the effect is the same, but you are using other language features to compensate for / implement a missing feature.

    Can you name a valid RTTI use that you don't consider a "hack"? Can you explain the existence of RTTI if not to solve this particular issue? And if you agree that RTTI exists to solve this particular issue, then what makes my intended use of it a "hack"?

    Except that you still need some set of core language features. The library can only go so far in compensating for inherent drawbacks in the design of the language.

    What can you not do with the library that you think is necessary and should absolutely be in the core?

    Actually, I have a C++ background -- most of the code I have written in my life has been C++. I just do not think that C++ is that great of a language; debugging C++ code often involves debugging the mechanics of a program, rather than the logic i.e. locating a dangling pointer, figuring out where an array bound is not being checked, etc. Programmers have spent countless hours dealing with these issues, there have been countless bugs and security vulnerabilities resulting from bad program mechanics, and most of the time the software in question did not need to be written in a low level language. Even in cases where the software does need to be written in a low level language, there is no excusing a language whose standard does not explicitly forbid statements that cannot possibly produce correct code, and there are numerous such cases in C++.

    I hope, for the sake of competence, that you are aware that all those examples you give can be fixed by proper debug libraries with custom smart pointers, custom array containers, custom allocators, and custom new, new[], delete, and delete[] overloads. Such libraries can raise exceptions and abort at the first sign of odd behavior like a delete leaving more than one dangling pointer, an attempt to dereference a pointer that has not been initialized or reset after its pointee got deleted with information in the exception about the exact line where the pointee was deleted, a pointer reassignment resulting in a memory leak, an out-of-bounds access to a generic sequence container, etc. C++'s staticity also allows for very powerful static analysis so that problems like the one you described earlier where a lambda capturing its environment by reference is assigned to a variable with a storage duration that is incompatible with the captured environment on top of all the stuff that is already possible to detect without extra tools thanks to C++'s strong typing and template metaprogramming. Also, thanks to being a native language, C++ can take advantage of all the available native debugging tools ranging from IDA Pro to Valgrind. Lastly, these are problems that you continue to have to deal in higher level languages, except you may not end up having security issues because of them, but if that's your problem you can always implement your own garbage collector, your own safe smart pointers, your own safe containers, and your own allocators thanks to C++'s generic programming support. You will obviously suffer a performance hit, but that's what you get in exchange for safety.

    I have not ignored anything. You have simply dismissed the idea that exceptions could be recoverable, despite having clear examples of situations where recovery is both possible and appropriate.

    Not without violating the principle of self-containment. So far in this thread everyone claiming that C++ exceptions have a problem are yet to demonstrate a single case in which catching a destructor exception would make any sense and does not imply bad design of their classes, so feel free to try...

    Why does the language allow exceptions to propagate out of d

  11. Re:One good reason... on What's To Love About C? · · Score: 1

    OK, but sometimes errors occur when a resource is being freed, and there needs to dealt with somehow. What are you suggesting happen in that case?

    Deal with them in the destruction; abort execution with an unexpected exception if handling the error is found to be impossible, because if your class that has knowledge of its own internals and the resources that it represents can not free its resources, nobody else can.

    That is true of exceptions in general, regardless of where they are thrown. That is one of the downsides of exceptions: there is no guarantee that the program will even continue to run after an exception is thrown, even if the exception is thrown from a non-destructor.

    Except destructor exceptions aren't supposed to be caught at all.

    Unless the object is deallocated because the stack is being unwound, in which case the only guarantee you have is that the destructor will be called.

    That's the trade-off with deferred synchronization: you exchange performance for reliability. Make your class synchronous if reliability is that important to you.

    OK, I must have been looking at something out of date; sorry about that. The point was not about the standard allowing an exception to propagate out of a destructor, however; the point was that the destructor for basic_filebuf will flush its buffer and then close the file, something you are claiming is a bad thing to do.

    I never claimed that you shouldn't sync in a destructor, I claimed that you shouldn't throw exceptions if it fails, because destruction time is already too late to expect synchronization. Feel free to do all the damage control you think you should do in the destructor, just don't expose your users to its hazards! That's wrong! If I ask for an instance of your class to delete itself, I do not want to be dealing with synchronization excepts because that's not what I asked for!

    That being said, if flushing or closing the file causes an error, the standard essentially says that the error should just be ignored -- no exception will be thrown, and there is not even a global error flag that can be checked. How is that a good thing?

    Asynchronous resources sacrifice reliability for performance. If reliability is that important to you, make your interface synchronous.

    The entire point of exceptions is that they cannot be ignored; allowing exceptions to just stop propagating or having a standard the requires errors to happen silently is a violation of the entire premise of exceptions. We might as well just stick with global error flags and checking return values if that is what we consider to be acceptable.

    Wrong premise: the point of an exception is to interrupt the flow of code and signal a condition in which an object has entered an invalid state; anything beyond that is bullshit. Just because a callee signaled an invalid state doesn't mean the caller itself has entered an invalid state, especially when the caller is attempting to do something beyond its premise (such as a destructor trying to sync).

    Once again, the right answer is for the stack to be unwound after the exception is caught. If the user does not want to try a restart, they can at least have a chance to catch exceptions that are thrown during the unwinding process.

    The right answer is for you to learn OOP.

    You have done no such thing. All you have done is reiterate your view that there is never a good reason for an exception to propagate out of a destructor, changed your argument about flushing and closing files in a destructor, and promoted the idea that errors should happen silently. All that just to defend the C++ approach to exceptions -- and all that despite the fact that better approaches have already been implemented and hav

  12. Re:One good reason... on What's To Love About C? · · Score: 1

    And how is closing a file not freeing a resource?

    Closing a file is freeing a resource, that was not my point. My point is that freeing that resource should not throw an exception. If there's an error, handle it in the destructor itself because at that point it's too late to throw anything, and if you really must throw something then don't expect it to be caught, because there really is no way to catch an exception from an object with either static or thread_local storage duration even if you ignore everything else I said. If the user of the class is really interested in making sure that all the data has been flushed (or in handling exceptions if it isn't), they should call sync() before deleting; try delete is simply stupid; either it really deletes appropriately or everything is fucked up and the program must abort.

    Solid argument you have there -- restate your personal definition of a destructor, then declare that I must be wrong if I disagree. I am just going to guess that you have not spent much time reading the C++ standard, though, since your argument applies equally to the C++ standard itself.

    I don't know exactly which standard is that you're reading, but I am reading ISO/IEC-14882 Third edition 2011-09-01 AKA the final publication of the C++11 standard, not a draft or an outdated standard, and it states the following regarding the destructor for basic_filebuf:

    "Effects: Destroys an object of class basic_filebuf<charT,traits>. Calls close(). If an exception occurs during the destruction of the object, including the call to close(), the exception is caught but not rethrown (see 17.6.5.12)." [27.9.1.2p5].

    As in the previous post, I will ignore the rest of what you wrote since on top of having completely destroyed your line of thought here, I have actually demonstrated that you are to blame for the things that you are accusing me of doing.

  13. Re:One good reason... on What's To Love About C? · · Score: 1

    You can manually implement a vtbl for single dispatch, or even a more complicated structure for multiple dispatch, if you want. Yet nobody would claim that C has OOP facilities, just like nobody should claim that C++ does not lack multiple dispatch.

    The moment you start passing structs as arguments and calling functions that are declared outside of the struct that is supposed to be your object you can no longer talk about object oriented programming because there really is absolutely no relationship between the function and the object. Furthermore constructors, destructors, inheritance, polymorphism, and encapsulation are all missing features in addition to the already mentioned lack of self-awareness. The method that I described, in the other hand, can be regarded as an actual feature of the language, as it allows you to decide between calling the overload for the base class or the overload for the derived class on top of also offering you enough static analysis to inform you, at compile-time, whether the version of the overload that you wish to call is actually available without any drawbacks at all.

    They are not required, even for closures. The use of a smart pointer in C++ is just a "nice" way to manage allocation and deallocation; it is not something that the language itself provides, it is provided by a library.

    The library is part of the language, and one of the strengths of C++ is that, by not being part of the core, these features are both optional and replaceable by custom versions.

    That is basically working around the fundamental problem, which is that the environment of a closure and the closure itself are allocated, managed, and deallocated separately.

    This is not a problem: C++ supports 4 types of storage duration constraints: static, thread_local, dynamic, and auto, and smart pointers serve the purpose of binding objects with dynamic storage duration to other kinds of storage duration. There is absolutely nothing wrong wit this, choice is a good thing, and the only reason why you feel uncomfortable with this is because your functional background has limited your mind to a more restrictive set of storage duration constraints.

    The fact that you can destroy the environment of the closure but continue to use the closure is the problem here. It is like calling an object's destructor, but continuing to use the object after that.

    If you mean closure as in everything captured by reference, then you can't actually do that (it's undefined behavior); if you mean lambda as in everything captured by value, then I see absolutely no reason for you not to be able to do it since you are accessing a copy of the original environment, not the original environment itself.

    No, it is because exceptions in C++ are implemented the wrong way. The stack should not be unwound until the exception handler is located, period. Unwinding the stack first is what creates this messy situation with exceptions that propagate out of destructors. The C++ standards committee spent too much time listening to compiler authors when it came to this issue; unwinding the stack first is easier to implement efficiently (unwinding after the exception is caught can be implemented efficiently, it is just harder for the compiler writer to do).

    As I have explained in the previous post, which you pretty much ignored for whatever reasont, it makes no sense to implement exceptions any differently. Destructors are not the place to throw exceptions, if nothing else then just because static and thread_local storage durations create situations in which you can simply not catch exceptions from destructors. You are not supposed to throw exceptions from destructions, at all, it doesn't make any sense no matter how you look at it because destroying an object should never leave it in an invalid state (and if it does, the program shou

  14. Re:One good reason... on What's To Love About C? · · Score: 1

    Except that there might be an error, which is the point of exceptions. I agree in principle that exceptions are a good thing -- I just think the C++ implementation is bad, mainly because there is no way to know if any exception will actually be caught even if you have a catch(...). The double exception fault basically reduces exceptions to Unix signals -- you should never rely on exceptions for cleanup, nor should you even rely on the program continuing to execute at all after an exception is thrown.

    There is, don't throw exceptions from destructors! It's wrong! It's anti-pattern! It serves no purpose!

    How is that? For simplicity, you can just assume that your program is the only program in the entire system -- imagine that we are back in the days of DOS. That does not mean that you will never have an uncommitted write; you might be using buffered I/O, and the buffer will need to be flushed when the file is closed.

    A destructor is a deallocator, it's not supposed to synchronize or guarantee anything else, only free resources. If the resource that your object represents is asynchronous, then you should implement a sync() function that its users can call to guarantee that nothing is lost before explicitly destroying the object.

    Since this pretty much kills your line of thought, I see no point in replying to the rest of your post.

  15. Re:One good reason... on What's To Love About C? · · Score: 1

    Or you could return an error code from member functions, and test that -- which is what the iostream classes in C++ did before exceptions were added to the standard.

    If the user asks for the result of an action, they are expecting the result of that action, not an error. The problem with in-band error checking is that, on top of requiring lots of repetitive code, including cleanup code (or alternatively, heavy goto usage), it also prevents you from chaining calls because in-band error values don't interrupt the flow of code, and if the fact that you can not do foo().bar().baz() anymore with error checking wasn't bad enough, the inability to chain calls also makes generic programming impossible (i.e.: you can't feasibly do 1 + 2 + 3 + 4 + 5 or even a + b + c either).

    Not true; the exception may have nothing to with the object being destroyed. Suppose, for example, that you have a class that encapsulates your logging process, and the destructor for that class closes the log file. Suppose some function creates a local object of that type, and then tries to write to a separate output file; the write may fail because you ran out of disk space, and that should cause an exception to be thrown. However, if that exception is not caught in the function that created the logging object, then the attempt to close the log file might also fail -- since it might try to flush the stream, which will fail because there is no disk space left. That too should cause an exception to be thrown, but that is not a result of the logging object being in an invalid state (there is nothing that the class could do to prevent the error).

    OOP is a synchronous paradigm; and the case that you are describing is asynchronous. If closing the file fails, it's up to you to try again until it succeeds. If you can't handle that problem, then how are you expecting the user of your class to handle it? If you can't ensure proper destruction, then the entire program is left in an invalid state since from that point forward it is no longer possible to determine how to recover from a partial destruction.

    Also, exceptions in native code can have information about the stack -- if the stack is not unwound before the exception is caught. If you wanted a core dump with that stack included, you could call abort at that point; you could also resume execution from where the exception was thrown e.g. if you do not want to halt a critical function because of a non-critical error.

    If you don't catch the exception, it will abort and dump core and you will be able to examine the stack with that. If you catch the exception, then you are pretty much telling the implementation that you don't really care about debugging because the error is expected and you can take care of it at runtime. You should not be catching exceptions unless you have pretty good reasons to do so and know exactly what you want to handle. For example: while a write error for lack of space exception should be handled and displayed to the user (as this error results from conditions unrelated to your program), a write error due to your use of an invalid file descriptor should not (because this error signals a potential bug in your code).

    No, the program is in an error state, which may first require the program to enter additional error states before execution can be resumed. Calling abort() is supposed to be an absolute last resort, reserved for situations where the program has no way to continue executing correctly. Exceptions are supposed to prevent programs from entering invalid states by forcing programs to enter error states; that is why exceptions as an idea are generally good. The problem is that in C++ (and to be fair, several other languages), the transition to the error state can trigger additional errors, which makes the correct error state ambiguous.

    Exceptions cause objects to self-destroy. If the destructor

  16. Re:One good reason... on What's To Love About C? · · Score: 1

    That is as bad as doing OOP in C -- sure, you can implement OOP constructs, but it adds complexity and it adds new ways for things to crash. C++ only supports single dispatch; you are on your own if you want something more.

    No, actually it's impossible to implement OOP in C. OOP requires self-awareness (i.e.: a this pointer), and C does't have that, so you can't implement instance member functions at all. RTTI, however, is fully supported by C++; you need to put some effort to use it, but the building blocks are fully supported by the language, and you will get the appropriate runtime errors if you dynamic_cast into the wrong type. If it wasn't this way, you'd lose the static analysis and thus end up with code that is more error prone because mistakes that could have easily been spotted at compile-time are left for you to bump against at runtime, and this, to me, is a lot more important than the edge cases in which I can not rely on virtual functions and may need to downcast.

    I was precise: the allocation and deallocation of the lexical environment for a closure. If you return a lambda from a function and your capture specification is simply [&]. then any reference to local variables from the enclosing function in the lambda expression will be invalid. You have to capture by value i.e. with the capture specification [=], which makes a copy, but now you must ensure that you do not free your pointers until you are done using the closure.

    Yes, I actually meant [=] when I posted that. That's the main theoretical difference between closures and lambdas: lambdas capture by value whereas closures capture by reference. Regarding your pointer issue, the language specifies smart pointers, and you can even implement your own, so I don't see an issue there. As a matter of fact you should actually be using at least unique_ptr to make sure that RAII takes proper care of the destruction of dynamic objects when an exception is thrown.

    Except that you could have a top level catch(...) block, and still wind up have your program abort when an exception is thrown. That happens if an exception propagates out of a destructor that was called as part of the stack unwinding process for another exception. This is not a problem in Lisp, since the exception handler is found before the stack unwinding process begins, which allows the stack unwinding to be optional -- a program could resume execution from the site where an exception is thrown (e.g. if you have a non-critical logging function, you probably do not want it to prevent a critical function from running).

    I have already addressed that "issue" elsewhere in this thread. Destructors should not throw exceptions. Exceptions are meant to signal error conditions in which an action performed on an object causes it to enter an invalid state, and destroying an object should never cause that because, well, the object is being destroyed... If the object self-destroys by throwing an exception and then a destructor throws another exception, then the entire program is in an invalid state because the object is supposed to have been destroyed when the second exception was thrown, and now you are left with absolutely no means to destroy that objects, nor can you, as a user, tell exactly how destroyed it was before it threw that exception. Destructors in C++11 are noexcept precisely because handling a destructor exception is as pointless as handling a SIGSEGV (though the latter can still be useful when you are implementing user land threads / fibers).

    No, reaching the end of a non-void function is not forbidden by the standard, it is left up to implementors to decide what to do. Some compilers will not allow it, some will warn, and some will just ignore it and compile your program without complaint.

    Wrong, the final publication of ISO/IEC-14882 Third Edition 2011-09-01 states, in 6.6.3p2, that "Flowing off

  17. Re:One good reason... on What's To Love About C? · · Score: 1

    You know the rule of the Internet that says that every spelling flame must contain a spelling mistake? Well, you don't seem to understand what "volatile" means.

    You're not the first misconceived person that I've had to refute about this. Volatile forces every read and write from and to memory to actually be a read and write, which among other things disables certain compiler optimizations that would incorrectly assume that a variable can not be written by anyone else.

    In the following example:

    sig_atomic_t i; void foo(void) {i = 3; while (i) i ^= 1;}

    nothing other than volatile can prevent the compiler from optimizing to:

    sig_atomic_t i; void foo(void) {for (;;);}

    with the logic behind the above optimization being that the function never actually returns as the condition in the loop is always true, and since it never returns it's not worth changing the global variable either because, really, no other function within the same execution context is going to read it again anyway. This is all fine and dandy when there's only one execution context, but fails miserably in the presence of concurrent memory access from external hardware, signal handlers, longjmp(), or threads because the changes that were supposed to happen are never made visible in memory, and it is to address those visibility problems that the volatile qualifier exists.

    Don't worry, you're not the first idiot I've refuted on the Internet about this, but I am not certain of exactly where the misconception that volatile is useless for threads started. It is true that many people think of volatile as having memory ordering enforcement properties (though I suspect this has to do with x86 enforcing acquire and release semantics on loads and stores, and some compilers actually implying fence semantics in the presence of volatiles) and that is an incorrect assumption, however to ignore the visibility problems caused by a lack of volatile usage is just as bad if not worse.

  18. Re:Who made that question? on What's To Love About C? · · Score: 1

    Not really. For one thing, header files are not automatically generated. One could write a tool to do that, but, since standard C does not have any way to indicate what types to export, it would have to be driven by "magic comments" or something like that. For another, header files still permit code in them, and have other problems associated with textual inclusion (such as pollution by essentially "private" macros).

    First, it's easy to guess what types to export -- you need to export all the types that your non-static functions and variables use either as return values or arguments. Secon, nobody in their right mind puts non-inline and non-generic code in header files. Doing so would cause link-time collisions, so that's a non-existing issue. Third, pollution is a problem that you would continue to have with or without headers since people would continue to forget to make their stuff static. Furthermore, without headers you would actually have no way to propagate macros, and this is a real issue to me.

  19. Re:One good reason... on What's To Love About C? · · Score: 1

    How do you get multiple dispatch in C++?

    C++ is a static language, but you can still accomplish what you wish by defining functions for the derive types, using RTTI to perform the type comparison, and dynamic_cast to the the derived types. If you meant something else, be precise.

    Why do you have to manage the allocation and deallocation of the lexical environment when you create a closure in C++11?

    You do?

    [&](){}

    That's a pure lambda, no allocation or deallocation of anything whatsoever. If you meant something else, be precise.

    Why can exceptions cause programs to abort in C++?

    Because exceptions are supposed to signal error conditions in which an object finds itself in an invalid state, and if they aren't handled it means the exception wasn't expected thus the entire program is in an invalid state.

    Why can a C++ function claim to return something, but never actually have a return statement (which can cause things to become completely unpredictable in the case where you were supposed to return an object value where the destructor is virtual)?

    It can't as far as the standard is concerned, but most compilers allow it, assume a default value, and only display a warning. Using your compiler properly should fix the problem.

    None of these things are problems in Common Lisp.

    You didn't mention any actual problems except for the last one which is not a feature of the language.

  20. Re:Who made that question? on What's To Love About C? · · Score: 1

    Same way it's done everywhere else. Add keywords to indicate which members of the translation unit should be exported, and generate separate files containing only metadata from them. Those don't have to be binary - they can be plain text if desired, and they can even use regular C declaration syntax (but be restricted to declarations only) for backwards compatibility.

    You've just described header files.

    The other thing would be replacing #include with something that'd remove the need for explicit header guards, like Obj-C #import.

    Most compilers support #pragma once, a VC++ extension. Personally I've done macro-metaprogramming before and like to be able to recurse headers for when i need black magic in C (C++ has templates for that).

  21. Re:One good reason... on What's To Love About C? · · Score: 1

    Exceptions -- I personally like exceptions, but exceptions in C++ are terrible and not necessary.

    Exceptions are an essential part in any object oriented programming language. They are the only way to signal that an interaction has left an object in an invalid state.

    No clearly defined exception type -- you could potentially catch something that has no descriptive string, no information about the stack, etc.

    It's native code. If you want to see the stack, either attach a program to a running process or read the core dump. The standard defines several exception types in and , all inheriting publicly from std::exception, but it doesn't force you to use them, you're free to create your own if you wish, or to throw something else that you find relevant.

    Double exception faults. This is a subtle problem but one that seems to be easier to trigger in C++ than other languages, and one that could be fixed by changing how exceptions are handled. For those who are not familiar, exceptions that propagate out of a destructor cause abort() to be called if the destructor was called as part of the stack unwinding process for another exception. If I wanted to call abort() when errors occurred, I would not bother with throw statements, I would just call abort().

    As per my definition above, you are not supposed to be throwing exceptions in destructors, because a destructor is not supposed to be causing your object to enter an invalid state. It's already destroying itself, after all. If you're having problems with exceptions at destruction time, then your code is improperly designed.

    Incidentally, the problem here is the order in which things happen. Exceptions should be caught before the stack unwinding process, which guarantees that the handler will execute before another exception is called. This also allows for "restarts" i.e. the ability to resume execution from the point where an exception was thrown, which might make sense (e.g. for exceptions that indicate some non-critical function could not be performed, which should not prevent a critical function from completing).

    No, it does not make sense. If a destructor signals an error condition, then the object is in an invalid state, and if the object is in an invalid state then it should self-destroy, but since the error was found during destruction it can't self destroy, so the entire program is in an invalid state, and the only way out of that is to abort and let the operating system / debugger handle the mess.

    I have also seen quite a few large C++ projects that simply ban exceptions, because they wind up creating more problems than they solve.

    Indeed, which actually contradicts your earlier remark that exceptions are unnecessary.

  22. Re:One good reason... on What's To Love About C? · · Score: 2

    It always infuriated me that most C++ compilers will happily accept printf() as valid.

    Most of C's standard library is part of C++'s specification. That function in particular is defined in <cstdio>, so compilers accepting it are conforming to the standard. This is not to mention that there are actually certain manipulators that stdio accepts and iostream does not, such as the precision manipulator for character strings which limits the amount of data read from character string buffers (C99). Also don't even get me started about the real bloat that iostream actually is. If you've never implemented a custom streambuf, please by all means do it and see for yourself.

  23. Re:Who made that question? on What's To Love About C? · · Score: 1

    It is unfortunate, though, that today C is indeed the best tool for that, because it was not the best tool historically, and it does have quite a lot of warts. Starting with #include and declarator syntax. All of that could be fixed without detracting a single bit from it being "close to the metal" etc. But then if you did all that, you'd end up with Modula-2...

    How do you fix #include without adding requirements to binary file formats? The metadata that goes in headers needs to be somewhere, the compiler can't just guess how your functions and data types (and templates in C++) are declared.

  24. Re:One good reason... on What's To Love About C? · · Score: 1

    And presumably "*" is overloaded? And how do you know whether a pointer is smart or not? Presumably you look at the #includes? Right. What if someone uses a different smart pointer library/template/whatever?

    You declared the pointer yourself as unique_ptr<T> somewhere within the function. If you can't keep track of that, better start refactoring. Operators don't magically overload themselves.

    And what about new and delete and arrays, vectors, and all that jazz?

    New and delete are overloaded on a per-class basis, or in some cases globally for debugging purposes alone. Container classes use allocator<T> for their value types, not new / delete overloads.

    So why don't they just make pointers behave like that in the first place? Oh, because that would break backwards compatibility with C source (you are meant to have swallowed the pill and be compiling all your C code in your C++ compiler, and modify it where its broken)... even although the language isn't a strict superset of C and you can't rely on the behaviour of the compiled code to be the same...

    Because it wouldn't make sense, as those features are not used on a language-wide basis.

    There are two types of people in this world: those that pretend to understand C++ and those that don't pretend that they don't.

    And you belong to the former group.

    Next idiot question? Don't be shy now, your ignorance is already public knowledge!

  25. Re:One good reason... on What's To Love About C? · · Score: 1

    Compare C++ to Objective-C. You might dislike the syntax of Objective-C some, but it has clear advantages:

    For each "advantage" there's also a "disadvantage". Your problem is that you know nothing about C++ and are talking out of your ass. There are cases in which smalltalk-style OOP is superior and cases where simula-style OOP is useful, and your opinion is extremely biased due to ignorance, so let me do the Internet a favor by demonstrating how clueless you really are.

    It is a strict superset of C: C compiles as Objective-C (C++ doesn't, since structs have a different syntax, among other things)

    Here I've learned that you don't even know C++. C++'s structs are exactly like C's structs, and you'd be challenged to find C11 code that doesn't compile as C++11 unless it's doing something very C specific such as to use compound literals (C++ supports initializer lists, which are neater), not casting to void * / char * (which are not universal pointer types in C++), or using keywords that are reserved in C++ such as new, delete, try, catch, operator, template, class, etc. Some of these problems also exist when you port code to Objective-C. For example, you can't use nil as a variable name.

    More importantly, it is runtime-resolved. That means you can expand Objective-C classes without breaking the ABI;

    That also means a lot of errors that a static analyzer would immediately point out in compile time are only reported as runtime errors if you are lucky enough to trigger the required conditions, thus making your code more error prone.

    in C++ you can't add members to classes, at all.

    The only place where this concern makes sense is while loading dynamic libraries, in which case you should actually only be using C or extern "C" in C++, because that's the only way you can guarantee that other languages can easily locate your symbols and don't have to deal with bindings.

    Class members can be in different libraries, and in different header files (a "private" member is one not exposed in the API, but you COULD access it directly by defining it or including the header for it).

    What?

    The mangling in C++ is a serious pain and makes loading C++ libraries and programs retardedly slow.

    Type mangling shouldn't be a problem at all unless you're trying to do something that you really should't, such as to dynamically load C++ symbols into another language. C++ gives you extern "C" precisely for the cases when you need ompatibility with the lowest common denominator (C). Also, type mangling does not slow anything down, I don't know where you got that idea from. Type mangled symbols aren't any slower or faster to load than any other symbols on any implementation that I'm aware of.

    Operator overloading and templates are an abomination, and don't exist in Objective-C.

    So Objective-C is better because it doesn't support a feature? Do you even understand generic programming at all?

    We can all supply better languages for a purpose; Objective-C and C++ have the same purpose (an object oriented general purpose native compiled mid-level programming language), and so this comparison is relevant.

    It would, if you actually had a clue of what you're talking about. The paradigms are quite different: Objective-C is dynamic, C++ is static.

    Swizzling (you can replace members of classes at runtime--not just inherit, but actually overload class members) makes the language quite a bit more flexible.

    Even C supports function pointers, and C++ adds lambdas / closures. You've been able to replace stuff at runtime all along, except in C++ you actually get to define exactly when it is OK for the users of your classes to do it.