Clever programmers choose sharp tools, not ones that make the problem harder.
It's amazing how everyone knows the answer...
on
Software Aesthetics
·
· Score: 2, Interesting
...yet the code out there is still awful.
Part of the problem is the languages people use: modern functional languages virtually force you into a safer, cleaner programming style and these days don't require you to compromise on efficiency; most imperative and OO languages lack any real facility for abstraction and in many ways just make you stupid. There is some hope: if you want the best of both worlds use OCaml - it's often faster than C with all the OO, abstraction and type safety you could ask for. It's imperative, to boot, if you have to think that way.
Market forces place universities under pressure to just teach people Java/C#/C++/whatever is being used in industry at the time, rather than teaching students how to use abstraction to solve complex problems (as opposed to just ad hoc hackery). The debate isn't going to get anywhere, however, because people who demanded and got this sort of bricks-and-mortar-but-no-architecture degree don't want to hear it. They're in the majority and managers know what they're hiring, even if experience shows time after time that the results are bad.
Why don't they just call their next chip the Athlon 4000... that'll satisfy the marketing chaff requirement (ooh, a bigger number than Intel has) and they won't have to bother faking out the clock speed on the info panel.
Perhaps the major problem for contemporary processors is the latency of memory accesses. Adding still more levels of caching offers rapidly diminishing returns. While using short machine instructions will be of some help in reducing I-cache misses (although with the unfortunate prevalence of OO languages even this probably won't make much difference), it does nothing for the D-cache hit rate still leaving you with the problem of branch prediction and all the complications that entails for the CPU design (I'd hate to have to try to design an n-way speculative execution unit for a stack based architecture). Do you have anything in mind that might help resolve the latency problem?
My second question concerns Forth. Many virtual machines are stack based because compiling to such architectures is perceived as being easier than for register models. This is a highly contentious assumption and it is certainly the case that generating fast object code for stack architectures is much harder (the program tends to spend much of its time rearranging the stack; the alternative is to keep variables on the heap in memory, but then you lose the advantage of having local variables stored locally in processor registers or on its stack). So while one might argue it may be possible to get higher theoretical peak processing power on a minimalist stack processor (see my first question), do you think it's worth it given the difficulty of generating fast object code for such designs?
We can be more precise: a neural net is a graph whose vertices (neurons) compute some function of their inputs (typically a thresholded exaggeration towards 1.0 or 0.0 of a weighted sum) which is communicated along its outputs. There is typically no notion of temporal behaviour, neural nets are generally sequences of feed-forward only layers of neurons (i.e. the standard neural net is a DAG, not a cyclic graph), and these things are just classifiers.
The human brain, on the other hand, is not like that.
Minski's "Society of Mind" seems like a plausable approach for creating a synthetic consciousness, but it may just be the equivalent of DaVinci's drawings of a "helipcopter": a handcranked cork-screw sail on a wooden platform.
I incline to the latter view: it's fairly easy to wave one's hands in the air and construct a plausible sounding story for how intelligent machinery might be put together, but until someone comes up with some sensible engineering principles for implementing these ideas, they can't be tested and should therefore be treated with the usual degree of scientific scepticism.
You need both. The security and integrity properties of the system have to be proved formally. Then you need to "prove" that the implementation meets the specification. Then you need to stress test the implementation to see what happens when the things you had to simplify away to make your "proof" work (e.g. assume no buffer overruns) get exercised.
During the WWII, the Germans had a seriously robust cryptographic engine in the Enigma, but it was weaknesses in its application (i.e. the way it was used/abused) that allowed so many messages to be decrypted.
This looks like C-- with some syntactic sugar and a bit of object wobble thrown in. In fact it also smells a little bit like Oberon.
I'm not a great fan of OO languages (just how much syntax do you really need?), but it would be wonderful if somebody would get rid of the pointless `new' keyword for object construction, add algebraic datatypes and pattern matching, and add closures as first class objects.
But when you use genuinely modern declarative languages (Mercury, OCaml, Haskell,...) there's no real incentive to go back. It's like good hi-fi.
I suspect part of the reason is that comp. sci. curricula are, in many universities, dictated by the students who are convinced that their investment in time and money is best spent on learning great chunks of Java, VB, C++ practice, in terms of graduating with the best job prospects.
Unfortunately the teach-em-only-what-industry-is-using approach does not provide students with any real perspective and you end up with second rate programmers.
For my own part, the "safe" languages aren't safe enough. Java etc. don't give Joe programmer access to dangerous pointers and so forth, but you still get runtime type errors, unchecked error cases, suckful performance, and an inability to stick to a spec. [Plug: it's nigh on impossible to avoid checking error codes in Mercury...]
'Fraid `cat' wouldn't get past the testing stage: it doesn't know how to spot malformed input.
The '00 task was hard work, but they did give us a whopping 24 page spec (it went through something like 18 revisions in the course of the contest as the teams found bugs and ambiguities therein). That said, I think hardly any of us contestants had a serious background in computer graphics, beyond the obligatory undergraduate lecture course way back when...
The mark of a declarative language (the set of which contains the pure subsets of functional languages) is that it respects referential transparency. That is, code of the form
-- use x as a name for the value of
-- expression e when evaluating M
let x = e in M
has the same meaning as
-- substitute expression e for free
-- occurrences of x in expression M
M[e/x]
Imperative languages are not referentially transparent because they depend upon destructive assignment. This means the substitution property doesn't hold because the value associated with a variable name changes as the program evolves.
[Sorry if this is the wrong forum; maybe someone could point me at the right place to ask this question if so.]
I believe that despite what the documentation says, any thread (at least under pthreads) that performs disc IO may block the entire process and prevent other threads from running. This is a problem the Flash high-performance web server had to get around by using multiple processes just for disc IO.
Can anyone tell me categorically that this bug has been fixed or give me some idea of when it will be fixed?
I concur. Wading through semi-literate sub-English in the hope of finding something worthy of consideration is excruciating. These days I rarely bother - it hasn't affected me adversely.
The 60.7MB of static Web content was small enough to easily fit into RAM, so this benchmark primarily tested networking and thread management code, not disk-handling routines (we did have Web server logging enabled, however).
What makes a web server fast is not how well it gets stuff out of memory and onto the wire, but how well it handles latency across the disc and the network, the disc being the major problem. Any benchmark that does not test this does not tell you anything about how well the system will perform in practice.
To make it worse, on most Unices (Linux, BSD, Solaris...), "non-blocking" disc IO does in fact block! To get around it you either have to have a separate process for each asynchronous disc request or use non-portable asynchronous IO APIs.
Have a look at the Flash web server to see how these problems are tackled for real (Flash beats the pants off Apache and Zeus.)
Modern programming languages are not based on Ada Lovelace's ideas. They cluster around notions of change of state (imperative languages), function composition (functional programming), or logical deduction (unification based logic languages).
Hardware is more reliable than software because (a) it's far less complicated, (b) H/W designs start off with a very precise spec., (c) H/W is sufficiently simple that modern formal methods are applicable, (d) most software programmers out there are monkeys.
Quite how you get from "based on parallel streams of signals" to non-algorithmic (whatever that means) is beyond me. I refer you to the Church-Turing thesis ("all Turing-powerful computational models are equivalent") for which a counterexample has yet to be presented.
Among the main reasons why many languages are strongly biased towards sequential execution are that (a) it's easy to understand, (b) it has a clear computational cost model, (c) it's easier to design H/W for this model, (d) data dependencies often demand that you work sequentially.
There are plenty of languages which do focus on concurrency (e.g. Occam) and plenty of schemes for supporting cheap concurrent programming (e.g. the Transputer, data-flow architectures, parallel functional language compilers, lazy functional languages, etc.) although they all have their drawbacks - mainly that the bookkeeping cost tends to seriously water down the naive intuitive expectation that it'll "all just work really fast."
In my opinion, we have such buggy software because programmers are rarely given a rigorous spec. to start with and are rarely capable of following it properly when they are, and that the most common languages in use today (C, C++, Java, VB, Perl) are unbelievably poor: they have weak type systems, if any, they have weak abstraction mechanisms, and they have absolutely no mathematical underpinnings, and they are very bad at preventing mistakes (I would spend time debunking the "Java's not like that" arguments, but...)
This sort of "you're all fools - why can't you just see?" kind of rant really gets up my nose, especially when it's just backed up with an ill-informed wish list.
Planning and scheduling are hard AI problems and way way more complex than IP routing or print spooling (I invite you to try writing serious planning/scheduling software if you doubt me.)
These problems are AI in the sense that (a) no known tractable engineering solution exists and (b) they are tasks that lie squarely in the province of (talented and capable) human beings.
Um, yes, but walking, machinery, and any kind of rhythmic activity on the sand (no, don't go there...) would summon the worms.
Fighting never really took place out on the open sand in the books (except for destroying harvesting operations): it all happened around the rock surfaces on which the various cities were built.
That was why the Fremen had a chance, I suppose: they were superior close-quarters troops compared to the Sardaukar or the militias of the Great Houses.
Must go back and re-read those books again now I've got this in my head...
Regardless of whether it's a good game or not, the developers seem to have taken a major liberty: in Frank Herbert's Dune universe
shield technology is ubiquitous
and shields repel anything moving faster than a slow fist*
so missiles and machine guns etc. are largely useless
leading to war being waged by infiltration of saboteurs on the one hand and massed hand-to-hand conflict on the battlefield,
NOT rockets'n'guns'n'stuff.
(* although lasgun-shield interactions were lethal to both victim and gunman.)
From what I can see, most units are armed with guns'n'bombs'n'missiles'n'flamethrowers'n'generall y ballistic stuff. Oh deary me.
[That said, the Harkonnen did defeat the bulk of the Atreides army on Arrakis by sealing them in caves with artillery - but this was something that would only ever work once.]
'nother point: on Arrakis nobody went out on the open sand other than the Fremen and the spice harvesters - the worms ate everybody else and any harvesters that weren't picked up by the carryall in time.
Hmm, just how much functional programming experience have you had? It most certainly is not hard to tackle real-world problems using FPLs. It is harder to lash-up any old pile of crap that just about gets the job done provided you don't stress it too hard - I'll give you that.
I suspect the ray tracers you're referring to were the ones people wrote for last year's ICFP programming contest. That contest was a free-for-all (imperative entries welcome) that lasted 72 hours from the time the spec. was posted to the time the binaries had to be in. Do you really imagine that a serious performance system is going to be coded in that time? Anyway, this is a straw man since (a) modern FPLs are fast - certainly competitive with C++ and Java - and (b) Perl is not what you use if performance is an issue. By the way, for the three years that the ICFP contests have been going, there have been Perl entries all along, but I don't believe any of them got past the basic correctness tests (I may be wrong about the 1998 entries - anybody know for sure how well they did?)
As for libraries, there I agree with you. Perl does indeed have a very large number of them. Loking at the module list on CPAN there are a large number of modules fixing up holes in the language (which I find astounding given the size of the language.) Surprisingly, I find little there that does not already exist for Mercury other than the systems support libraries (I'm not qualified to report on their quality; my colleagues give them mixed reviews).
But this is all rather beside the point - I don't seriously expect to garner any Mercury converts on this thread. The point is that if you are going to write non-trivial working programs then you should use a language which makes it hard to code bugs in and which is easy to maintain. Perl singularly fails on both these counts.
I can't remember the last time I read a paper that wasn't on the web.
That said, what makes conferences and journals valuable is the peer review process that each paper has to go through - it cuts out huge amounts of chaff. People are, of course, quite at liberty to publish their papers on the web, but these works are typically not accorded the same respect as peer reviewed work.
Mercury (a pure, fast, functional/logic programming langauge) has a very simple performance model for the basic language. Some of the higher level aspects of the language, such as typeclasses and higher order code, have less obvious models, but as soon as the optimizer is turned on in any language you lose the simple performance model. That said, you can do much more in the way of optimization with a pure, referentially transparent language than you can with imperative stuff like C and (ugh...) C++.
...then take a look at Eric Meijer's CGI library in Haskell. Using Haskell gives you all the power of a modern, pure, powerful, strongly-typed functional language [oh well, that's lost 99.9% of the audience.] Read the paper here and you can find the source here.
With the forthcoming.NET integration this should become easy to integrate with all the other stuff a web site has to deal with.
This kind of moral grandstanding disguised as informed criticism really hacks me off.
1. Of course we don't know that the poster isn't a nutcase, nor, if he is, whether that is due to reading pornography when younger (in the West, statistically speaking almost all males past puberty have some pornography stashed somewhere and, statistically, virtually none of them turn into dangerous types - rather poor grounds on which to posit a causal relationship.) In the same vein, we don't know that you're not some evil Bible-bashing fuitcake prepared to cause any amount of misery in order to protect other people's moral wellbeing. Your first point is nonsense.
2. While, no doubt, some people in the pornography business do get abused, we have to assume the vast majority don't otherwise it simply wouldn't (and couldn't) exist in anything like the scale it does. We all find the idea of children being exploited in sweatshops to make fashionable running shoes repugnant, yet those shoes still sell in their millions.
3. What has the original poster done that leads you to suspect that (a) somebody has suffered because of him and (b) that he has not taken responsibility for it?
To sum up, of course one posts one's own opinions. How, pray tell, is one supposed to prove objectivity?
Sorry, but contentless holier-than-thou rhetoric is just the lowest form of debate.
Clever programmers choose sharp tools, not ones that make the problem harder.
Part of the problem is the languages people use: modern functional languages virtually force you into a safer, cleaner programming style and these days don't require you to compromise on efficiency; most imperative and OO languages lack any real facility for abstraction and in many ways just make you stupid. There is some hope: if you want the best of both worlds use OCaml - it's often faster than C with all the OO, abstraction and type safety you could ask for. It's imperative, to boot, if you have to think that way.
Market forces place universities under pressure to just teach people Java/C#/C++/whatever is being used in industry at the time, rather than teaching students how to use abstraction to solve complex problems (as opposed to just ad hoc hackery). The debate isn't going to get anywhere, however, because people who demanded and got this sort of bricks-and-mortar-but-no-architecture degree don't want to hear it. They're in the majority and managers know what they're hiring, even if experience shows time after time that the results are bad.
Why don't they just call their next chip the Athlon 4000... that'll satisfy the marketing chaff requirement (ooh, a bigger number than Intel has) and they won't have to bother faking out the clock speed on the info panel.
Perhaps the major problem for contemporary processors is the latency of memory accesses. Adding still more levels of caching offers rapidly diminishing returns. While using short machine instructions will be of some help in reducing I-cache misses (although with the unfortunate prevalence of OO languages even this probably won't make much difference), it does nothing for the D-cache hit rate still leaving you with the problem of branch prediction and all the complications that entails for the CPU design (I'd hate to have to try to design an n-way speculative execution unit for a stack based architecture). Do you have anything in mind that might help resolve the latency problem?
My second question concerns Forth. Many virtual machines are stack based because compiling to such architectures is perceived as being easier than for register models. This is a highly contentious assumption and it is certainly the case that generating fast object code for stack architectures is much harder (the program tends to spend much of its time rearranging the stack; the alternative is to keep variables on the heap in memory, but then you lose the advantage of having local variables stored locally in processor registers or on its stack). So while one might argue it may be possible to get higher theoretical peak processing power on a minimalist stack processor (see my first question), do you think it's worth it given the difficulty of generating fast object code for such designs?
Medicine first, then ethics.
We can be more precise: a neural net is a graph whose vertices (neurons) compute some function of their inputs (typically a thresholded exaggeration towards 1.0 or 0.0 of a weighted sum) which is communicated along its outputs. There is typically no notion of temporal behaviour, neural nets are generally sequences of feed-forward only layers of neurons (i.e. the standard neural net is a DAG, not a cyclic graph), and these things are just classifiers.
The human brain, on the other hand, is not like that.
I incline to the latter view: it's fairly easy to wave one's hands in the air and construct a plausible sounding story for how intelligent machinery might be put together, but until someone comes up with some sensible engineering principles for implementing these ideas, they can't be tested and should therefore be treated with the usual degree of scientific scepticism.
Perhaps the land of the free should take a look at its legal system?
During the WWII, the Germans had a seriously robust cryptographic engine in the Enigma, but it was weaknesses in its application (i.e. the way it was used/abused) that allowed so many messages to be decrypted.
I'm not a great fan of OO languages (just how much syntax do you really need?), but it would be wonderful if somebody would get rid of the pointless `new' keyword for object construction, add algebraic datatypes and pattern matching, and add closures as first class objects.
But when you use genuinely modern declarative languages (Mercury, OCaml, Haskell, ...) there's no real incentive to go back. It's like good hi-fi.
Unfortunately the teach-em-only-what-industry-is-using approach does not provide students with any real perspective and you end up with second rate programmers.
For my own part, the "safe" languages aren't safe enough. Java etc. don't give Joe programmer access to dangerous pointers and so forth, but you still get runtime type errors, unchecked error cases, suckful performance, and an inability to stick to a spec. [Plug: it's nigh on impossible to avoid checking error codes in Mercury...]
The '00 task was hard work, but they did give us a whopping 24 page spec (it went through something like 18 revisions in the course of the contest as the teams found bugs and ambiguities therein). That said, I think hardly any of us contestants had a serious background in computer graphics, beyond the obligatory undergraduate lecture course way back when...
The mark of a declarative language (the set of which contains the pure subsets of functional languages) is that it respects referential transparency. That is, code of the form
-- use x as a name for the value of
-- expression e when evaluating M
let x = e in M
has the same meaning as
-- substitute expression e for free
-- occurrences of x in expression M
M[e/x]
Imperative languages are not referentially transparent because they depend upon destructive assignment. This means the substitution property doesn't hold because the value associated with a variable name changes as the program evolves.
To quote Michael Jackson from Jon Bentley's "More Programming Pearls" (every programmer should own a copy),
I believe that despite what the documentation says, any thread (at least under pthreads) that performs disc IO may block the entire process and prevent other threads from running. This is a problem the Flash high-performance web server had to get around by using multiple processes just for disc IO. Can anyone tell me categorically that this bug has been fixed or give me some idea of when it will be fixed?
But then I am a screaming intellectual snob.
To make it worse, on most Unices (Linux, BSD, Solaris...), "non-blocking" disc IO does in fact block! To get around it you either have to have a separate process for each asynchronous disc request or use non-portable asynchronous IO APIs. Have a look at the Flash web server to see how these problems are tackled for real (Flash beats the pants off Apache and Zeus.)
- Ralph
Good grief. Where does one start?
...)
Modern programming languages are not based on Ada Lovelace's ideas. They cluster around notions of change of state (imperative languages), function composition (functional programming), or logical deduction (unification based logic languages).
Hardware is more reliable than software because (a) it's far less complicated, (b) H/W designs start off with a very precise spec., (c) H/W is sufficiently simple that modern formal methods are applicable, (d) most software programmers out there are monkeys.
Quite how you get from "based on parallel streams of signals" to non-algorithmic (whatever that means) is beyond me. I refer you to the Church-Turing thesis ("all Turing-powerful computational models are equivalent") for which a counterexample has yet to be presented.
Among the main reasons why many languages are strongly biased towards sequential execution are that (a) it's easy to understand, (b) it has a clear computational cost model, (c) it's easier to design H/W for this model, (d) data dependencies often demand that you work sequentially.
There are plenty of languages which do focus on concurrency (e.g. Occam) and plenty of schemes for supporting cheap concurrent programming (e.g. the Transputer, data-flow architectures, parallel functional language compilers, lazy functional languages, etc.) although they all have their drawbacks - mainly that the bookkeeping cost tends to seriously water down the naive intuitive expectation that it'll "all just work really fast."
In my opinion, we have such buggy software because programmers are rarely given a rigorous spec. to start with and are rarely capable of following it properly when they are, and that the most common languages in use today (C, C++, Java, VB, Perl) are unbelievably poor: they have weak type systems, if any, they have weak abstraction mechanisms, and they have absolutely no mathematical underpinnings, and they are very bad at preventing mistakes (I would spend time debunking the "Java's not like that" arguments, but
This sort of "you're all fools - why can't you just see?" kind of rant really gets up my nose, especially when it's just backed up with an ill-informed wish list.
Planning and scheduling are hard AI problems and way way more complex than IP routing or print spooling (I invite you to try writing serious planning/scheduling software if you doubt me.)
These problems are AI in the sense that (a) no known tractable engineering solution exists and (b) they are tasks that lie squarely in the province of (talented and capable) human beings.
- Ralph
Fighting never really took place out on the open sand in the books (except for destroying harvesting operations): it all happened around the rock surfaces on which the various cities were built.
That was why the Fremen had a chance, I suppose: they were superior close-quarters troops compared to the Sardaukar or the militias of the Great Houses.
Must go back and re-read those books again now I've got this in my head...
- shield technology is ubiquitous
- and shields repel anything moving faster than a slow fist*
- so missiles and machine guns etc. are largely useless
- leading to war being waged by infiltration of saboteurs on the one hand and massed hand-to-hand conflict on the battlefield,
- NOT rockets'n'guns'n'stuff.
- (* although lasgun-shield interactions were lethal to both victim and gunman.)
From what I can see, most units are armed with guns'n'bombs'n'missiles'n'flamethrowers'n'general[That said, the Harkonnen did defeat the bulk of the Atreides army on Arrakis by sealing them in caves with artillery - but this was something that would only ever work once.]
'nother point: on Arrakis nobody went out on the open sand other than the Fremen and the spice harvesters - the worms ate everybody else and any harvesters that weren't picked up by the carryall in time.
Do I get my trainspotter's badge now?
I suspect the ray tracers you're referring to were the ones people wrote for last year's ICFP programming contest. That contest was a free-for-all (imperative entries welcome) that lasted 72 hours from the time the spec. was posted to the time the binaries had to be in. Do you really imagine that a serious performance system is going to be coded in that time? Anyway, this is a straw man since (a) modern FPLs are fast - certainly competitive with C++ and Java - and (b) Perl is not what you use if performance is an issue. By the way, for the three years that the ICFP contests have been going, there have been Perl entries all along, but I don't believe any of them got past the basic correctness tests (I may be wrong about the 1998 entries - anybody know for sure how well they did?)
As for libraries, there I agree with you. Perl does indeed have a very large number of them. Loking at the module list on CPAN there are a large number of modules fixing up holes in the language (which I find astounding given the size of the language.) Surprisingly, I find little there that does not already exist for Mercury other than the systems support libraries (I'm not qualified to report on their quality; my colleagues give them mixed reviews).
But this is all rather beside the point - I don't seriously expect to garner any Mercury converts on this thread. The point is that if you are going to write non-trivial working programs then you should use a language which makes it hard to code bugs in and which is easy to maintain. Perl singularly fails on both these counts.
That said, what makes conferences and journals valuable is the peer review process that each paper has to go through - it cuts out huge amounts of chaff. People are, of course, quite at liberty to publish their papers on the web, but these works are typically not accorded the same respect as peer reviewed work.
Mercury (a pure, fast, functional/logic programming langauge) has a very simple performance model for the basic language. Some of the higher level aspects of the language, such as typeclasses and higher order code, have less obvious models, but as soon as the optimizer is turned on in any language you lose the simple performance model. That said, you can do much more in the way of optimization with a pure, referentially transparent language than you can with imperative stuff like C and (ugh...) C++.
...then take a look at Eric Meijer's CGI library in Haskell. Using Haskell gives you all the power of a modern, pure, powerful, strongly-typed functional language [oh well, that's lost 99.9% of the audience.] Read the paper here and you can find the source here. With the forthcoming .NET integration this should become easy to integrate with all the other stuff a web site has to deal with.
1. Of course we don't know that the poster isn't a nutcase, nor, if he is, whether that is due to reading pornography when younger (in the West, statistically speaking almost all males past puberty have some pornography stashed somewhere and, statistically, virtually none of them turn into dangerous types - rather poor grounds on which to posit a causal relationship.) In the same vein, we don't know that you're not some evil Bible-bashing fuitcake prepared to cause any amount of misery in order to protect other people's moral wellbeing. Your first point is nonsense.
2. While, no doubt, some people in the pornography business do get abused, we have to assume the vast majority don't otherwise it simply wouldn't (and couldn't) exist in anything like the scale it does. We all find the idea of children being exploited in sweatshops to make fashionable running shoes repugnant, yet those shoes still sell in their millions.
3. What has the original poster done that leads you to suspect that (a) somebody has suffered because of him and (b) that he has not taken responsibility for it?
To sum up, of course one posts one's own opinions. How, pray tell, is one supposed to prove objectivity?
Sorry, but contentless holier-than-thou rhetoric is just the lowest form of debate.