Reputation
3,792
Top tag
Next privilege 5,000 Rep.
Approve tag wiki edits
Badges
6 14
Newest
 Yearling
Impact
~271k people reached

  • 0 posts edited
  • 0 helpful flags
  • 168 votes cast
Jun
23
comment Compiler time versus programmer time
I tend to believe that in a good language, small changes to a function's implementation should tend to cause similar changes in the generated code. If the fact that some particular parameter is never passed a value greater than 4 would allow some optimization, the question of whether the compiler performs that optimization should be determined by whether the code specifies that invariant. An analysis tool which can indicate "If the parameter will never need to exceed 4, adding XXX directive here would allow code to be faster" could be helpful, but having code depend too much on...
Jun
23
comment Compiler time versus programmer time
I dislike the idea that a compiler should spend huge amounts of time trying to figure out what a program is expected to do, every time it's compiled. Compilers should be expected to know more than programmers about which way of implementing something will be fastest when run under known conditions, but programmers will often know more about compilers about what conditions are most likely to occur; allowing a programmer to specify things that should be invariants, and have a compiler verify them, would seem a better approach than having an optimizer identify things it hopes are invariants.
Jun
23
comment Why is there still case sensitivity in some programming languages?
...then having someone type foo instead of Foo would generate a compilation error, prompting the listener to ask the speaker how the name should properly be typed.
Jun
23
comment Why is there still case sensitivity in some programming languages?
What I would want would be a spec that would indicate that legitimate code must not depend upon either case-sensitivity nor case-insensitivity. If identifiers that differ only in case may be usable within in the same scope, the someone reading code aloud must specify the precise casing for every identifier; if the speaker doesn't specify the case of an identifier, and the listener types foo instead of Foo, it's possible that the listener may end up with a program that compiles but has totally the wrong meaning. If identifiers were required to be distinct in ways other than casing...
Jun
23
comment How safe is it to compile a piece of source code from a random stranger?
A Turing-complete language may allow a program to spend an unbounded amount of time to compile, if the compiler is allowed to run for an unbounded amount of time, but many compilers will create a bounded number of threads regardless of anything that might appear in the code being compiled, meaning that the CPU load from trying to compile one program at a time would be limited. A potentially bigger problem would be disk space requirements; it's entirely plausible that a 1KB source file might generate many gigs of object code.
Jun
21
comment Why do programs use call stacks, if nested function calls can be inlined?
@BasileStarynkevitch: For generation of temporary objects on a GC heap to be anywhere near as fast as stack accesses, the heap space used by youngest generation of GC objects must be small enough to fit in the lowest-level cache. If it isn't, then every cache line worth of continuation that is generated will be a cache line that will end up having to be uselessly flushed to a higher-level cache (or main memory) after it has been abandoned. By contrast, addresses associated with abandoned stack frames will get recycled very quickly, and can thus remain in cache.
Jun
21
comment Why do programs use call stacks, if nested function calls can be inlined?
@Gilles: Many newer ARM cores like the Cortex M0 and M3 (and probably others like the M4) have hardware stack support for things like interrupt handling. Further, the Thumb instruction set includes a limited subset of the STRM/STRM instructions that includes STRMDB R13 with any combination of R0-R7 with/without LR, and LDRMIA R13 of any combination of R0-R7 with/without PC, which effectively treats R13 as a stack pointer.
Jun
21
comment Why do programs use call stacks, if nested function calls can be inlined?
While forbidding recursion does mean that the entire call graph can be represented as a DAG, that doesn't mean that one could list out the full list of nested call sequences in a reasonable amount of space. On one project of mine for a microcontroller with 128KB of code space, I made the mistake of asking for a call graph which included all functions that could affect maximum parameter-RAM requirement and that call graph was over a gig. A complete call graph would have been even longer, and that was for a program that fit in 128K of code space.
Jun
20
comment Are Constant Time and Amortized Constant Time effectively considered equivalent?
...where additions are all done by one thread, but multiple threads may need to "remove" items. If the only effect of removing an item is to set a flag which is never written except to set it, then in some memory models, it's possible to avoid minimize synchronization delays (depending upon the memory model and exact requirements, one may be able to eliminate them entirely) in ways that would not be possible if deletes had to do more "work".
Jun
20
comment Are Constant Time and Amortized Constant Time effectively considered equivalent?
@Deduplicator: Having removal requests mark items as removed without necessarily deleting immediately them can be a good approach if one has addition operations scan part of the list for items that need to be "truly" deleted. If each addition causes a two items to be examined and deleted if marked for removal, that will ensure that the maximum number of dead items will be limited to the maximum number of live items, while allowing both addition and deletion to remain O(1). Such an approach can be especially nice in some multi-threaded scenarios...
Jun
20
comment Are Constant Time and Amortized Constant Time effectively considered equivalent?
@Carcigenicate: Whether removal can be described as O(1) in any sense depends upon how items are identified, and how removal affects the identities of items. If the two operations one performs on a list are "add items to the end" and "iterate through all items and decide for each item whether to remove it", then a suitable-designed array list can perform the addition in time O(1) plus the time for an N-item array allocation every 1/N times the maximum size is increased, and perform the N-item scan-and-delete in time O(N) [so O(1) per element], even if the latter must keep items in order.
Jun
17
comment Why would a program use a closure?
@coredump: In C#, if two closures have any variables in common, the same compiler-generated object will serve both, since changes made to a shared variable by one closure must be seen by the other. Avoiding that sharing would have required that each closure be its own object which holds its own unshared variables as well as a reference to a shared object which holds the shared variables. Not impossible, but it would have added an extra level of dereferencing to most variable accesses, slowing everything down.
Jun
17
comment Why would a program use a closure?
...having a closure keep references to things that it is never again going to use can lead to memory leaks; that can be an especially severe problems in cases where a function generates a closure which is only used briefly but closes over something big and expensive as well as something cheap, and a closure which will be kept for a long time but only closes over the cheap thing. On some language implementations with closures, the latter closure will hold a reference to the big expensive thing even though it doesn't actually use it.
Jun
17
comment Why would a program use a closure?
@coredump: If one has a language with good variable scoping, that can work and isn't too bad. Unless I'm missing something, though, that doens't work so well in something like JavaScript where all closures created within a function will import the same variables. If their lifetimes don't overlap, that's a good thing, but it makes it rather hard to have active be false for one closure but true in another. Further, " "deactivating" a closure by setting a flag won't invalidate references stored therein. Since any reference to a closure is a reference to all variables therein...
Jun
16
comment Why would a program use a closure?
@AndresF.: It is possible to encapsulate a stateful object in a wrapper that supports invalidation; if code encapsulates a privately-held List<T> in a (hypothetical class) TemporaryMutableListWrapper<T> and exposes that to outside code, it could be ensured that if it invalidates the wrapper, outside code will no longer have any way of manipulating the List<T>. One can design closures to allow invalidation once they've served their expected purpose, but it's hardly convenient. Closures exist to make certain patterns convenient, and the effort required to guard them would negate that.
Jun
15
comment Has variable width types been replaced by fixed types in modern C?
@Veedrac: Using uint32_t, the modulus will be 2^32 in all cases where the result is defined, but the Standard presently allows 64-bit compilers to negate the laws of time and causality for some values of n. Also, in some cases it may be just fine to perform calculations with a modulus which is known to be an arbitrary unknown multiple of a modulus one is interested in, and only reduce the result to the modulus of interest after all other calculations are complete, since reducing at the end will yield the same result (in defined cases) as reducing at every step.
Jun
15
comment Has variable width types been replaced by fixed types in modern C?
...code which stores a computation in a smaller integer type and then uses that value cannot simply use the cached in a register unless it first truncates and sign-extends it. The programmer might not care about whether oversize values are truncated or left as-is, but the Standard requires the truncation in any cases where it would be detectable.
Jun
15
comment Has variable width types been replaced by fixed types in modern C?
@Veedrac: Part of the design intention with unsigned types is that operations with them are defined on all inputs; it is common for things like hash functions to use unsigned types perform modular arithmetic. Having a Standard say that n*=n; is always allowed to perform the result according to mod-4294967296 arithmetic, is only required to do so when n is 3037000499 or less, is silly. As for signed types, the problem is that having overflow defined for signed types smaller than int means that...
Jun
15
comment Has variable width types been replaced by fixed types in modern C?
@ALXGTV: The function was meant to be illustrative of something that computed something power-related. What it actually computes is N^(2^exponent), which is a part of efficiently computing N^exponent, and may well fail even if N is small (repeated multiplication of a uint32_t by 31 won't ever yield UB, but the efficient way to compute 31^N entails computations of 31^(2^N), which will.
Jun
15
comment Has variable width types been replaced by fixed types in modern C?
@MarkHurd: The function is poorly named, since what it actually computes is N^(2^exponent), but computations of the form N^(2^exponent) are often used in computation of exponentiation functions, and mod-4294967296 exponentiation is useful for things like computing the hash of the concatenation of two strings whose hashes are known.