Earlier quoted context omitted.
This kind of logic is the exact cause to the optimization problem described. We all know that in practice MAX_INT+1 is negative, and that many "non-standard" programs depends on it, but still, the optimizer is sticking to the C standard that no one follows just because it gives it a nice optimization chance. Bad..
"Bad"? You use C because you want speed above all else. If you don't know the language and need hand-holding, don't use C. Compilers are going to optimize C -- that's why it usually runs so fast.
What Every C Programmer Should Know About Undefined Behavior #2/3
31–40 of 45 posts
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#32Earlier quoted context omitted.
> The relevant element of FP is statelessness. That said, statelessness could easily be considered a leaky abstraction because, at some point, the machine you are working on has state. Your machine has CPU registers and memory and such, so the entire "statelessness" of FP is subject to the underlying system-level implementation. It is only leaky if you are exposed to the statefulness of the underlying machine. Haskel…
Debug.Trace, for instance. More generally, the fact that execution time and memory usage (tail recursion!) sometimes depend on how well the compiler can turn your stateless algorithm into a stateful one, in ways that don't make sense from the perspective of the abstract machine.
Performance analysis of pure algorithms is not a leak of the abstraction, if you consider the abstraction relates to the semantics, the result of the algorithm, and not how much resources it takes to execute.
If you wish to know the resource use of your pure code, then none of the nice abstractions hold anymore, but most of the time, you don't need to.
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#33Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#34Earlier quoted context omitted.
> In an unsafe language like C or C++, you would just assert that the two containers are the same length and use parallel iterators. The type system here lets you optimize away some of the overhead of using a safe language, but it doesn't let you write code that is more optimized than the obvious unsafe code, at least in this example. Well, you can choose any two of: 1. Fast (less run-time), 2. Safe (cannot crash), 3…
> Well, you can choose any two of: 1. Fast (less run-time), 2. Safe (cannot crash), 3. Simple types (None of the advanced type hackery). Many choose 1+3 or 2+3, but advanced types let you choose 1+2 which in many cases is remarkable and somewhat surprising that it is even possible. I don't think it's really that surprising that it's possible. Most programs don't rely on any deep mathematical properties for their corr…
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#35Earlier quoted context omitted.
> In an unsafe language like C or C++, you would just assert that the two containers are the same length and use parallel iterators. The type system here lets you optimize away some of the overhead of using a safe language, but it doesn't let you write code that is more optimized than the obvious unsafe code, at least in this example. Well, you can choose any two of: 1. Fast (less run-time), 2. Safe (cannot crash), 3…
> Well, you can choose any two of: 1. Fast (less run-time), 2. Safe (cannot crash), 3. Simple types (None of the advanced type hackery). Many choose 1+3 or 2+3, but advanced types let you choose 1+2 which in many cases is remarkable and somewhat surprising that it is even possible. I don't think it's really that surprising that it's possible. Most programs don't rely on any deep mathematical properties for their corr…
I never meant to imply Haskell was a "completely safe" language. That is an impossibility, even totality does not imply complete safety. My zip example is actually a point against Haskell (as length-indexed lists are not yet actually in use in the Haskell eco-system).
Haskell can encode low-level programs that are almost C-level, and in that (ugly) style can probably reach the performance you can with lower-level languages (excluding hand-optimized assembly, perhaps).
> As the data structures get further away from algebraic data types, the type hackery gets more and more involved. If you start working with arbitrary mutable data structures that arise in practice, the type hackery becomes a topic for a PhD thesis rather than something usable in practical programming today.
Mutable data structures do not have to "arise in practice". You can have pure semantics with mutable performance (e.g: Clean's uniqueness types, or Haskell's ST).
Lots of people's PhD thesis are in actual use in practical programming today. A PhD thesis often discovers a technique and makes it accessible for real world programs today.
> I don't know of any compiler that actually does a reasonable job converting uses of data structures like lists and association lists into arrays and hash tables in general. I think this falls into the territory of the "sufficiently smart compiler" fallacy.
Converting these is not a good idea because you would change the complexities of the code (which is, IMO, the heart of the fallacy). A prepend of an a-list or a list is O(1), but to a list or hash table, it is (in the worst-case) worse.
But what Haskell's primary compiler, GHC, does do, is fuse together list processing such that lists can disappear altogether into efficient loops.
As for arrays and hash tables, these are not amenable to efficient "pure" modification (unless you use uniqueness types as in Clean), but they have reasonable alternatives that are pure and persistent: Sequence allows O(logN) indexing, O(1) amortized (O(logN) worst-case) prepend/append. Tries and search trees allow for quick lookups and quick pure modification. These are easy to reason about.
> Also, making data contiguous is just the simplest of a common set of data representation optimizations.
This conflicts with O(1) prepend. If you want contiguous allocation, you can use different data structures.
> Does any compiler automatically convert a list into an intrusive doubly linked list or eliminate the use of a visited stack for DFS by stealing a bit from vertices or reversing pointers?
If you need to remove/insert items in the middle of a list, you would probably not use a linked list. So a doubly linked is not a good optimization to apply automatically.
If your point is that code with simpler mathematical semantics that is easy to reason about might cause a constant hit on performance in some cases -- then I agree. You cannot always have simplicity, verifiability, and speed. But often you can.
Also note that purity affords many optimizations that are unavailable in non-pure languages (e.g: rewrite rules like: map f . map g --> map (f . g)).
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#36Earlier quoted context omitted.
It is not that the result of operation is undefined, the operation of INT_MAX+1 itself is undefined(actually the entire program becomes undefined when you do it), so the compiler can do whatever it pleases. According to the C standard, INT_MAX+1 might as well lead to formatting of your hard drive. So, it is safe to assume that x!=INT_MAX and that x+1>x for all x, because if x=INT_MAX your program is undefined, so com…
This kind of logic is the exact cause to the optimization problem described. We all know that in practice MAX_INT+1 is negative, and that many "non-standard" programs depends on it, but still, the optimizer is sticking to the C standard that no one follows just because it gives it a nice optimization chance. Bad..
Apologies for the confrontational tone, but someone making that kind of mistake out of ignorance is understandable. Insisting on wrong thinking after having it explained in detail why it's wrong, isn't.
If you can't live with the fundamental design principles behind C/C++ then the correct approach is to not use them. Don't ask the compiler writers to go against those principles.
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#37Interesting they say there is no way to detect undefined behaviour in C code. This is precisely what the following project is all about: http://www.astree.ens.fr/
So the existence of that tool doesn't contradict the statement of the article.
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#38the way to write good solid code is to use more than 2 compiler, and optimisation etc. i mostly write code that runs on at least 3 different os, and 2 different hardware. ... and it just works. no prog-lang can be faulted for bad programming using one. learn the lang, and use it. :-) gcc still gets the pointer dereference and assignment to what a pointer points to, due to deferring assignments. these edges, idioms of…
Do you fuzz your inputs? Run with the clang undefined integer overflow checker? Run your program on hardware with 16-bit int?
llvm is an excellent tool, hats off, and thanks.
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#39Earlier quoted context omitted.
"Bad"? You use C because you want speed above all else. If you don't know the language and need hand-holding, don't use C. Compilers are going to optimize C -- that's why it usually runs so fast.
This is bad because the optimizer ignores the imperfect reality about the big crowd of non standard programs. It actually punishes non standard programs (and probably the majority of programs out there are not 100% standard). So it is a bad and patronizing optimization
In those cases, just use unsigned math to do the checks.
Re: What Every C Programmer Should Know About Undefined Behavior #2/3
#40Earlier quoted context omitted.
It is not that the result of operation is undefined, the operation of INT_MAX+1 itself is undefined(actually the entire program becomes undefined when you do it), so the compiler can do whatever it pleases. According to the C standard, INT_MAX+1 might as well lead to formatting of your hard drive. So, it is safe to assume that x!=INT_MAX and that x+1>x for all x, because if x=INT_MAX your program is undefined, so com…
This kind of logic is the exact cause to the optimization problem described. We all know that in practice MAX_INT+1 is negative, and that many "non-standard" programs depends on it, but still, the optimizer is sticking to the C standard that no one follows just because it gives it a nice optimization chance. Bad..
"We all know that in practice" type assumptions are exactly what make code difficult to port and/or maintain and developers should really stay away from them. Or at least, if you really want to make such assumptions (for example, for performance reasons), make sure that that (1) you know exactly what you're doing and (b) test for their validity at compile time or runtime and provide fallback code that always does the "right" thing.