The joke is on you: tail recursion can be seen as the ultimate evolution of GOTO.
The tail-recursive factorial function in Scheme or ML is completely equivalent to an iterative one with goto, except that it's safer and clearer.
In most functional programming languages you can code (for instance) state machine transitions directly by 'calling' the next state. Since the call is in tail position, it acts almost exactly like GOTO.
(I won't even mention typed assembly languages like TALx86 or the continuation semantics of your CPU...)
There are Godel/Turing-type results which imply that most mathematical truths are 'random' -- ie they don't have short/elegant/informative proofs.
Build a combinatorial structure and ask some random question about it, and the odds are pretty decent you'll need to resort to brute force.
Simple: missing return statement (in C)
on
Pet Bugs?
·
· Score: 2, Interesting
I used to be on UWaterloo's ACM programming contest team. More than once I got bitten by the ever-so-simple yet ever-so-annoying to debug 'missing return' phenomenon.
It seemed that on some architectures (eg. the local workstation I was testing on), the right value would just happen to be in the right register anyway. On the judges architecture (fortunately this was a local practice contest, not the world finals!) it failed one time out of one hundred. Yeah, yeah, I know, turn on warnings... it wouldn't fit with the contest mentality: vi + gcc and one terminal and you're set.
Extensive use of templates can result in substantial executable code expansion. If you know what you're doing you can mitigate this by sharing code between instantiations. Like other time/space tradeoffs in C++ it requires the exercise of programmer judgement.
Extant versions of MS Visual C++ still don't support lots of important aspects of templates. You usually don't get bitten until you're writing your own STL-style utilities (ie just using the stuff is fairly portable). Someday MS may get their act together and make an attempt towards ISO compliance.
Your analysis is fallacious. You can't base your storage needs on the predicted amount of information to be retrieved unless you can predict, in advance, exactly which information you will wish to 'experience'. Unless you believe in predestination (or perhaps 'The Matrix') any person would prefer to have more information accessible than they could ever access or 'absorb', just as I prefer to live in a world which is physically too large to fully explore in one lifetime.
The same observation applies (less philosophically) to algorithms.
C++ is, in my opinion, a superb language for programming in the large. It is my first choice for any programming project of substantial size, and I shudder at the thought of working on a 100k+ line project in anything else. I particularly appreciate how the strong typing facilities can be used to express and statically check many of a program's semantics.
However, when writing something smaller, I am drawn (like many people) to languages with facilities for terser, higher-level data structures and algorithms. Standard ML, Python, and even Perl make it easier to work with tuples, strings, lists, or higher-order functions. These languages sometimes permit faster prototyping or experimentation. It is easy to be put off by the sheer amount of verbiage required to write well-engineered C++ code (private undefined copy constructors, redundant include guards, the occasional ribbon cable, etc. ).
How can we bridge the gap between productivity in the large and productivity in the small?
(Note: I do not mean to imply that C++ is never suitable in the small; rather that there are many classes of problems for which different langages seem to me more productive, at least up to a certain program size).
jd wrote: > all existing processors are procedural
I would argue that existing processors are not innately procedural. Most support a 'state machine' style of programming even more directly. Nearly all instruction set architectures support efficient call stacks, which I guess you could consider a "procedural" feature, but C++ uses these processor facilities just as effectively as C does. A 'tuned for C++ chip' might trim a cycle or two from a virtual function call, but those are already cheap on existing architectures.
Unless you're suggesting hardware GC, heap management, or persistence, I believe that current processor architectures are well suited to stack-heavy OO languages like C++.
Digression: with all that said, I remember reading about an object-oriented CPU designed by Linn ("Rekursiv"?), back in a mid-80s Byte magazine. It had hardware support for persistence, 40-bit 'object identifiers' rather than pointers, and was apparently used in a production system.
The terms "virus" and "worm" originally referred to the form of the code, not its method of propagation. A "virus" was a object code patch which made a program or operating system do additional viral tasks (such as patching other programs); a "worm" was a stand-alone program or process which propagated. If you replace "worm" with "bacterium" the biological analogy is clear: a virus is inert except when it's integrated into existing executable code (DNA), a worm/bacterium is self-contained and directly infects a host (multi-cellular organism).
There's at least one more GCJ participant that I know of headed for Google employment.
The joke is on you: tail recursion can be seen as the ultimate evolution of GOTO.
The tail-recursive factorial function in Scheme or ML is completely equivalent to an iterative one with goto, except that it's safer and clearer.
In most functional programming languages you can code (for instance) state machine transitions directly by 'calling' the next state. Since the call is in tail position, it acts almost exactly like GOTO.
(I won't even mention typed assembly languages like TALx86 or the continuation semantics of your CPU...)
There are Godel/Turing-type results which imply that most mathematical truths are 'random' -- ie they don't have short/elegant/informative proofs.
Build a combinatorial structure and ask some random question about it, and the odds are pretty decent you'll need to resort to brute force.
I used to be on UWaterloo's ACM programming contest team. More than once I got bitten by the ever-so-simple yet ever-so-annoying to debug 'missing return' phenomenon.
It seemed that on some architectures (eg. the local workstation I was testing on), the right value would just happen to be in the right register anyway. On the judges architecture (fortunately this was a local practice contest, not the world finals!) it failed one time out of one hundred. Yeah, yeah, I know, turn on warnings... it wouldn't fit with the contest mentality: vi + gcc and one terminal and you're set.
Wasted waaaay too much time on that one.
Extensive use of templates can result in substantial executable code expansion. If you know what you're doing you can mitigate this by sharing code between instantiations. Like other time/space tradeoffs in C++ it requires the exercise of programmer judgement.
Extant versions of MS Visual C++ still don't support lots of important aspects of templates. You usually don't get bitten until you're writing your own STL-style utilities (ie just using the stuff is fairly portable). Someday MS may get their act together and make an attempt towards ISO compliance.
Too many Java games are PIGs already.
next week:
* Should the Internet be shut down?
* Should Open Source be illegal?
Your analysis is fallacious. You can't base your storage needs on the predicted amount of information to be retrieved unless you can predict, in advance, exactly which information you will wish to 'experience'. Unless you believe in predestination (or perhaps 'The Matrix') any person would prefer to have more information accessible than they could ever access or 'absorb', just as I prefer to live in a world which is physically too large to fully explore in one lifetime.
The same observation applies (less philosophically) to algorithms.
Byte magazine, 1983 or 1984 IIRC. Steve Circia's Circuit Cellar gives complete plans for a
homemade EEG.
...is to design and implement the language you're using. The 1999 winners were the authors of OCaml, GHC, and HBC.
The 1998 winners built Cilk.
C++ is, in my opinion, a superb language for programming in the large. It is my first choice for any programming project of substantial size, and I shudder at the thought of working on a 100k+ line project in anything else. I particularly appreciate how the strong typing facilities can be used to express and statically check many of a program's semantics.
However, when writing something smaller, I am drawn (like many people) to languages with facilities for terser, higher-level data structures and algorithms. Standard ML, Python, and even Perl make it easier to work with tuples, strings, lists, or higher-order functions. These languages sometimes permit faster prototyping or experimentation. It is easy to be put off by the sheer amount of verbiage required to write well-engineered C++ code (private undefined copy constructors, redundant include guards, the occasional ribbon cable, etc. ).
How can we bridge the gap between productivity in the large and productivity in the small?
(Note: I do not mean to imply that C++ is never suitable in the small; rather that there are many classes of problems for which different langages seem to me more productive, at least up to a certain program size).
jd wrote:
> all existing processors are procedural
I would argue that existing processors are not innately procedural. Most support a 'state machine' style of programming even more directly. Nearly all instruction set architectures support efficient call stacks, which I guess you could consider a "procedural" feature, but C++ uses these processor facilities just as effectively as C does. A 'tuned for C++ chip' might trim a cycle or two from a virtual function call, but those are already cheap on existing architectures.
Unless you're suggesting hardware GC, heap management, or persistence, I believe that current processor architectures are well suited to stack-heavy OO languages like C++.
Digression:
with all that said, I remember reading about an object-oriented CPU designed by Linn ("Rekursiv"?), back in a mid-80s Byte magazine. It had hardware support for persistence, 40-bit 'object identifiers' rather than pointers, and was apparently used in a production system.
The terms "virus" and "worm" originally referred to the form of the code, not its method of propagation. A "virus" was a object code patch which made a program or operating system do additional viral tasks (such as patching other programs); a "worm" was a stand-alone program or process which propagated. If you replace "worm" with "bacterium" the biological analogy is clear: a virus is inert except when it's integrated into existing executable code (DNA), a worm/bacterium is self-contained and directly infects a host (multi-cellular organism).