I was addressing the GP AC's simplistic argument in his own terms.
Social democracy is the norm in most of Europe, with most people protected by a welfare safety net, and it has proved a good balance between pure market capitalism and pure state socialism. The issue in Greece, Spain and Italy is that the austerity measures are forcing those countries out of the continental European model and more towards the more market-oriented approach of the UK and USA. The current Greek government is trying to reestablish social democracy by instead targeting the real problem of corruption and greed in the rich. The problem with previous governments was that they were run by the corrupt and greedy rich, and hence weren't willing to address the issue.
of your 3 examples. The dust bowl and the credit crunch were not caused by voluntarism / capitalism.
The dust bowl was down to the practices of commercial farmers. The cotton plant wasn't the ideal crop for the soil, but it was in high demand. Other practices that left the ground unprotected were simply farmers trying to reduce labour effort (ie. production cost). It's all market forces and capitalism.
Taking the credit crunch alone, why do you think all those risky loans were made? Because the government forced banks to lend below their standards and also got in the lending game to the tune of what, 80% of all the housing loans in the US are owned by fanny and freddy.
That's all well and good inside the US. However, there was no regulatory pressure outside the US for non-US banks to buy up US sub-prime, and yet many of them did. Why? Because the more theoretical creditors they had, the more loans they could issue.
Recovery requires spending. Every penny put in the pockets of someone living in abject poverty is going to be spent in under a week. Meanwhile, middle classes and above reduce their spending out of prudence during crises. Austerity deepens the crisis by stopping money circulating. If Greece wants to shake off its woes, it has to dedicate all its resources to increasing consumer spending -- therefore money must go to the poor. And it's not just about money, either -- after WWII, the UK nationalised all the public mass transport firms, as access to transport (and therefore to workplaces and shops) was vital to keep the poor economically active.
If the middle class want to stand up and say "enough is enough" they should be addressing the upper classes and corporations, and their tax fiddles. When high earners can cook the books so as to pay a lower percentage of income tax than the middle classes, it's them that are not paying their way.
make people work for the state if on welfare (there are jobs that the state does, and pays workers good money to do, but could be done for much less)
What you're proposing is basically eliminating the minimum wage, then...?
We firmly reject any policies that might move us toward fiscal responsibility.
No, Greece rejects any policies that won't lead to recovery. Austerity economics is madness, ignoring all the evidence from economic theory and history that says that recovery is hastened by putting money in the hands of those who will spend it quickest (ie the poor). After WWII the UK nationalised a multitude of private industries under the Keynes plan, and we grew. Austerity economics proposes the exact opposite of what worked previously, looking at national infrastructure as liquid assets to be sold. It's the wrong way round.
How many failed socialist experiments do we need to see before it's written off as a failure?
I suppose as long as there's 1 more sucker, it will keep working.
How many failed capitalist experiments (the great dust bowl, tobacco marketing, the credit crunch) do we need to see before it's written off as a failure?
Funnily enough, TFA does not talk about free electricity at all....
Is electricity "stuff"? Or does it enable the use of stuff?
Anyway, I don't think they've looked far enough east for inspiration. I remember reading a few years ago that in one of the south-east Asian cities (Kuala Lumpur maybe? Singapore?) there was two-tier pricing on electricity -- dirt cheap up to X kWh so that everyone could have lighting and basic usage, but then ramping up to very expensive so that the rich buggers running air conditioning all day long were effectively subsidising the poor.
Although, on reflection, that's not really a solution for Greece seeing as it's not a matter of a large wealth gap as a severe lack of wealth....
Then you weren't doing it right. The whole point of the exercise is for them to get it wrong.
But that's not pedagogically sound. The first rule: don't set them up for failure. The point of the exercise is to show them that they already have some of the necessary skills, and to foreshadow future topics.
I have two (very different) responses to that:
1: If an accurate simulation of the process of compiled imperative code is pedagogically unsound, then surely that means that compiled imperative code is pedagogically unsound?
2: The beauty of the peanut-butter-jelly-sandwich task is failure is fun. Failure is intriguing and interesting. Or at least hopefully, because once you start coding, you're entering a whole world of debugging.
We do this because humans think declaratively.
That's a bit of a stretch, isn't it? You always start with 'what' before the 'how'. It's why top-down design has been such a useful and successful approach. (You even hint at that in the sandwich example with the need for further refinement.)
Surely then the pedagogically sound way to learn about coding is top-down -- starting with declarative languages, then working our way closer to the metal, naturally bringing in procedural languages.
In fact, many of the attempts to make kid-friendly programming environments are just collections of library functions that the kids can string together. But all that string is procedural-imperative, when black-box library functions are semantically declarative.
Ask a 4-year-old to tie their shoes (the what) and there's a good chance you'll hear them say "I don't know how". Given them a complicated toy and they'll quickly rush back to you with a "How do I make it do..." Even very young children seek out procedures. Dare I say, it's natural...
Even in the example that started this, you still include the "how" (as you can see by comparison to the C# and loop examples) it's just not in sequence and includes less information useful to the reader. (Hence, it's less readable.)
But this isn't possible. The differences between languages aren't just skin-deep. For instance, Haskell's lazy-evaluation really is a world away from the sequential-execution paradigm used in imperative languages. These differences run deep enough that they use quite different compiler frameworks.
Surely that's a matter for the compiler writer, and not for the person using the language? I mean, we already have the capability to cross-call from pretty much any language to any other (with varying degrees of difficulty), so we're already dealing with this to an extent. But cross-calling becomes a conscious act, and people tend to hack around with a single language rather than picking the right tool for the job.
While I'll admit I've never done any compiler work more serious that a trivial undergrad coursework task, I imagine that the constraints of pure FP would obviate a lot of the incompatibilities, as you would be able to call FP subsystem from anywhere, but the FP section would not be able to call out anything else (as that would break purity).
All you have to do is make sure a call into FP works, whether by typechecking immutability of arguments at compile time or actively "freezing" any mutable arguments at run time. (That could be a slightly altered call system from within the procedural system, but it should be essentially transparent to the coder.) Once you're in the FP system, the differences are perfectly OK as they don't make a bit of difference to the result you'll get when flow control returns to the procedural subsystem.
The point would be to encourage cross-calling wherever appropriate. I accept that this would open up the potential for programmers to overuse cross-calling, and that that could potentially introduce new inefficiencies, but I believe that would be a fair trade-off against the inefficiencies that would be eliminated by having enforced mutability and mathematical provability for various subsystems.
Similar fundamental incompatibilities exist for type-systems, memory-management strategies, approaches to concurrency and parallelism...
I may be missing something, but concurrency and parallelism seem trivial for immutable items, which means the functional subsystem would not need to interfere with the main system in that sense. Memory management is clearly a bigger issue.
I personally believe, and admit I may be wrong, that most of the difficulty in reconciling multiple languages is that they all attempt to do too much. If you strip away all of the hacks that allow you to do things that are not appropriate to the paradigm, integration would be simplified -- still not a trivially easy task, certainly, but maybe worth doing anyway.
The name had washed over me completely when I read TFS. Not only the name, but the fact that we were talking about a Dell device. This thread has now set the name in my head.
Come on, do you think that by repeatedly saying "Dell Venue 8 7000" he is making people who had never heard of the Dell Venue 8 7000 more aware of the Dell Venue 8 7000? Really? Because I'm now going to forget that name dead easily now, because he keeps saying Dell Venue 8 7000.
Stupid idea. People use desktops for completely different reasons than phones. And we can already run apps on smartphones and tablets, so Canonical is again walking backwards.
Yes, people use desktops for different reasons than phones. People use desktops for more things than phones. Most of the use cases for mobile apps are very restricted, and can be therefore encoded in a narrow set of runtime libraries. Why does Spotify take up 175MB on the iPad, even when you aren't caching any audio locally? It's unnecessary bloat, and the customer suffers. I wonder if they do it on purpose, to try to make sure you don't have space left to use competing services....
The same way it did for Apple - by scrapping the stupid idea in the next version in favor of native apps.
It didn't work for Apple because of the commercial nature of the app store -- everyone offering apps was looking for brand awareness. Ubuntu is Linux, and Linux is dominated by free software. Free software doesn't need brand awareness, because brand awareness is mostly about money. A great many apps unnecessarily tie function to the front end, when almost all the functionality is effectively a code library, and this is because they need brand awareness. Some Linux media apps still use a daemon for the actual grunt work and have a choice of lightweight GUIs, so the backend code is universal, and the user can chose how they want to interact with it.
Ubuntu Phone could kickstart a renaissance in the original Unix code ethos....
Except that developer time is expensive, and a heck of a lot of "native" apps are written in and bundled with some 3rd-party run-time environment that chews up memory and processor cycles anyway.
Cool spinmeistering, brah. But all I hear is someone making up excuses for why Ubuntu phone will have less developers and fewer apps than even Windows Phone. And that's no small accomplishment.
I don't know about you, but I for one am sick of downloading multiple megabyte apps from various websites to view what is essentially the same as what's on their webpages. Sometimes you end up getting 200Mb for a catalogue that doesn't even store offline data, which is frankly ridiculous. I've got an app for a TV station that weighs in at 20Mb, and I need it because the video on the web version is all Flash (and I'm on iOS) and even that seems too much (I can't imagine that they're using a codec that doesn't have native support on iOS.
I think they're making a smart decision here. What users want are services, and there's no reason for services to require their own apps, which is why 3rd party apps that collate information from multiple social media accounts (for example) are so popular.
That's ridiculous. Of course humans think procedurally. Don't know how to do something? Here's this step-by-step procedure! If you ask how to bake cookies or change your spark plugs, you'll find (and expect) that you're provided a handy list of steps.
Humans can cope with procedural instructions, but it's not our most natural mode of thought. But even within the steps of a recipe, there are lots of jumps where descriptions change or items aren't repeated. e.g. "Sift the flour, sugar and baking powder together into a bowl. Beat an egg and milk with 1 tablespoon of milk, then add to the dry ingredients and mix thoroughly". Notice that "the flour, sugar and baking powder" becomes "the dry ingredients". The fact that the egg/milk mix is being put into the bowl is an unstated assumption in the call to add the mix to the dry ingredients. Adding to the ingredients is declarative rather than imperative. The fact that an egg must be cracked and emptied before beating is omitted, which is again declarative as it's an unstated prerequisite. You could claim that proc beat(egg) includes if intact(egg) { crack(egg) } but that's a bit of a hack. It's still an assumed prerequisite, and all we're doing is trying to hack a bit of declarativity into the imperative paradigm. We do this because humans think declaratively.
Just think of the classic "peanut-butter and jelly" demonstration of trying to tell someone how to make a sandwich procedurally -- it's really hard, and even many programmers can't do it right first try.
I've used that and similar problems when teaching kids how to program. Not a single child has failed to get it right on the first try.
Then you weren't doing it right. The whole point of the exercise is for them to get it wrong. Your job is to take the slightest ambiguity and do it wrong. You don't ask them for clarification, you don't let them shout "STOP!" when you're doing it wrong. Almost nobody every thinks about the fact that you need to line up the corners/edges -- it's so much a natural part of our understanding of "sandwich" that it never strikes us as significant.
Have you really seen someone fail at this? Were they conscious?
(Just thinking about it, that's often how kids explain things to you when they're proud of some accomplishment. "I did x!... First I... then I... ")
So, without providing a list of steps, can you explain to me how to make a peanut-butter and jelly sandwich? Surely, there's a much more natural way to communicate that knowledge, yes?
Why? Because functional programming cannot do everything. The best toolbox doesn't contain one tool that can be used to do everything, but multiple tools that can be used together. I mean, you can tap a nail with a chisel, and you can cut a plank of wood it half with a chisel, but you'd be better with a hammer and a saw. If we try to make all of our languages do everything, we end up no specialised tools. So we need to focused on integrating muktiple tools into a single toolbox.
What I'm trying to suggest is that the whole idea of "a language" is wrong. Instead, I would like to see a multi paradigm "multi language" - ie a single type system and calling mechanism which unifies various syntaxes incorporating multiple programming paradigms. We already sort-of-kind-of do this, but our paradigms are all hidden in libraries, and we end up missing out on compile-time checks (eg cross-calling SQL from an unverified ad hoc string, rather than having properly mediated source code). But we kid ourselves on that we don't do this. We need to accept that we do and explicitly make tools that support it.
OCaml is an imperative language -- I was talking about FP as declarative. Haskell may be described as "pure" functional, but it still allows monads with side-effects, which means it still has order-of-execution issues and is therefore not declarative. So clearly I was not talking about OCaml or Haskell. This is a theoretical question, because "here in the real world", there is no declarative functional language to benchmark against.
My personal belief is that the problem with FP is the same problem as every other terse paradigm has: it can't do everything. Procedural programming is our default option, in a "a jack of all trades is a master of none" type way. Everything is clumsy, but everything can be done. The problem with multiparadigm languages is that they either make everything possible, so nothing is guaranteed (eg "Python can be used for functional programming", but it never enforces immutability) or everything descends into a morass of keywords, imperatives and classifiers. But more importantly, every language sticks to a single syntax, regardless of the paradigm, when individual paradigms really need their own syntaxes. If you can program in a statement-based style inside your functions, everything gets confused.
I strongly disagree. As you said: "you still need to break it down" which, adds to the cognitive load.
You either have to break down or build up, and either is a cognitive load. What I like about the Python list comprehension is that having the statement in brackets basically screams THIS IS A LIST and it's very hard to miss the intended meaning. The C# list comprehension doesn't have any similar visual indicators, and the readability relies more on meaningful variable names
The for loop is not only neatly broken down for you, but includes additional information to help you understand each part and the relationships between each part.
No, the thing that's most sorely lacking in imperative programming is structures that explicitly encodes relationships between statements. Consequentiality from one line to the next is almost entirely buried in the (unseen) state of variables.
Further, the components themselves are also "in order" making it read more "naturally". The order in the list comprehension example might as well be completely random. Consider the same example using list comprehensions in C#:
my_list = from x in list where x > 0 select x*x;
This is dramatically more readable than the Python example simply because those imperatives of imperative programming (direct sequencing, conditional branching, bounded iteration, and conditional iteration) are still applicable.
That assumes that imperative programming is natural, which it is not. People have great problems learning to program because human thought doesn't work that way. Just think of the classic "peanut-butter and jelly" demonstration of trying to tell someone how to make a sandwich procedurally -- it's really hard, and even many programmers can't do it right first try.
It's almost as readable as a for loop, though it still requires special/uncommon knowledge; just far less than in the Python example.
I suppose it doesn't really matter how much better or worse than other languages handle them. In every case that I'm familiar, they add complexity (without also adding value, an unforgivable sin). Complexity, naturally, harms readability.
Reductio ad absurdum: Complexity harms readability. Base 10 is more complex than base 2, therefore 11001 is more readable that 25. The flaw in this logic is simple -- although base 10 is more complex, base 10 is an integral part of our daily lives. Or to put it another way, base 10 is compatible with human thinking. Humans don't think procedurally, and we don't speak in strict chronological order -- "always wash your hands after going to the toilet".
Let's bring that back to a list comprehension. For the English "give me a list of the names of all the students in the class whose grades are above 50%", the pseudo-Python list comprehension would be = [ student.name() for student in class if student.grade() > 0.5]. And yes, there are multiple ways of issuing the same command in English, and I've selected the one that matches the Python syntax most closely. That isn't important, though -- Python's syntax models a possible human syntax, therefore has high compatibility with human thought. On the other hand, I'd struggle to produce a natural-sounding English analogue to the C# syntax. All the "for... if..." stuff doesn't imply "list" -- only the "select" does, and it's an odd word in the situation.
The Python starts with our goal in brief, then gives more information, which is human nature. In fact, if you think about it, assignment statements in most programming languages do. A few languages tried doing it the other way round, as this was a purer procedural way of doing things ( eg 3*x+2 => variable ), but programmers didn't like it that way round, because the variable is the goal, and the expression is more information.
As for FOR loops being the most readable, well, let's try a FOR loop in English. "Ma
I was addressing the GP AC's simplistic argument in his own terms.
Social democracy is the norm in most of Europe, with most people protected by a welfare safety net, and it has proved a good balance between pure market capitalism and pure state socialism. The issue in Greece, Spain and Italy is that the austerity measures are forcing those countries out of the continental European model and more towards the more market-oriented approach of the UK and USA. The current Greek government is trying to reestablish social democracy by instead targeting the real problem of corruption and greed in the rich. The problem with previous governments was that they were run by the corrupt and greedy rich, and hence weren't willing to address the issue.
of your 3 examples. The dust bowl and the credit crunch were not caused by voluntarism / capitalism.
The dust bowl was down to the practices of commercial farmers. The cotton plant wasn't the ideal crop for the soil, but it was in high demand. Other practices that left the ground unprotected were simply farmers trying to reduce labour effort (ie. production cost). It's all market forces and capitalism.
Taking the credit crunch alone, why do you think all those risky loans were made? Because the government forced banks to lend below their standards and also got in the lending game to the tune of what, 80% of all the housing loans in the US are owned by fanny and freddy.
That's all well and good inside the US. However, there was no regulatory pressure outside the US for non-US banks to buy up US sub-prime, and yet many of them did. Why? Because the more theoretical creditors they had, the more loans they could issue.
Corruption is at the top of society. It is very difficult for the top of society to pretend to be destitute.
Recovery requires spending. Every penny put in the pockets of someone living in abject poverty is going to be spent in under a week. Meanwhile, middle classes and above reduce their spending out of prudence during crises. Austerity deepens the crisis by stopping money circulating. If Greece wants to shake off its woes, it has to dedicate all its resources to increasing consumer spending -- therefore money must go to the poor. And it's not just about money, either -- after WWII, the UK nationalised all the public mass transport firms, as access to transport (and therefore to workplaces and shops) was vital to keep the poor economically active.
make people work for the state if on welfare (there are jobs that the state does, and pays workers good money to do, but could be done for much less)
What you're proposing is basically eliminating the minimum wage, then...?
We firmly reject any policies that might move us toward fiscal responsibility.
No, Greece rejects any policies that won't lead to recovery. Austerity economics is madness, ignoring all the evidence from economic theory and history that says that recovery is hastened by putting money in the hands of those who will spend it quickest (ie the poor). After WWII the UK nationalised a multitude of private industries under the Keynes plan, and we grew. Austerity economics proposes the exact opposite of what worked previously, looking at national infrastructure as liquid assets to be sold. It's the wrong way round.
No taxes and now no need to work.
You can't starve people into finding jobs when your country has record unemployment.
There will always be people who want a share of OTHER people's wealth.
I'm trying to work out which side of your equation is the employee, and which side the employer....
How many failed socialist experiments do we need to see before it's written off as a failure?
I suppose as long as there's 1 more sucker, it will keep working.
How many failed capitalist experiments (the great dust bowl, tobacco marketing, the credit crunch) do we need to see before it's written off as a failure?
Funnily enough, TFA does not talk about free electricity at all....
Is electricity "stuff"? Or does it enable the use of stuff?
Anyway, I don't think they've looked far enough east for inspiration. I remember reading a few years ago that in one of the south-east Asian cities (Kuala Lumpur maybe? Singapore?) there was two-tier pricing on electricity -- dirt cheap up to X kWh so that everyone could have lighting and basic usage, but then ramping up to very expensive so that the rich buggers running air conditioning all day long were effectively subsidising the poor.
Although, on reflection, that's not really a solution for Greece seeing as it's not a matter of a large wealth gap as a severe lack of wealth....
Then you weren't doing it right. The whole point of the exercise is for them to get it wrong.
But that's not pedagogically sound. The first rule: don't set them up for failure. The point of the exercise is to show them that they already have some of the necessary skills, and to foreshadow future topics.
I have two (very different) responses to that:
1: If an accurate simulation of the process of compiled imperative code is pedagogically unsound, then surely that means that compiled imperative code is pedagogically unsound?
2: The beauty of the peanut-butter-jelly-sandwich task is failure is fun. Failure is intriguing and interesting. Or at least hopefully, because once you start coding, you're entering a whole world of debugging.
We do this because humans think declaratively.
That's a bit of a stretch, isn't it? You always start with 'what' before the 'how'. It's why top-down design has been such a useful and successful approach. (You even hint at that in the sandwich example with the need for further refinement.)
Surely then the pedagogically sound way to learn about coding is top-down -- starting with declarative languages, then working our way closer to the metal, naturally bringing in procedural languages.
In fact, many of the attempts to make kid-friendly programming environments are just collections of library functions that the kids can string together. But all that string is procedural-imperative, when black-box library functions are semantically declarative.
Ask a 4-year-old to tie their shoes (the what) and there's a good chance you'll hear them say "I don't know how". Given them a complicated toy and they'll quickly rush back to you with a "How do I make it do ..." Even very young children seek out procedures. Dare I say, it's natural...
Even in the example that started this, you still include the "how" (as you can see by comparison to the C# and loop examples) it's just not in sequence and includes less information useful to the reader. (Hence, it's less readable.)
But this isn't possible. The differences between languages aren't just skin-deep. For instance, Haskell's lazy-evaluation really is a world away from the sequential-execution paradigm used in imperative languages. These differences run deep enough that they use quite different compiler frameworks.
Surely that's a matter for the compiler writer, and not for the person using the language? I mean, we already have the capability to cross-call from pretty much any language to any other (with varying degrees of difficulty), so we're already dealing with this to an extent. But cross-calling becomes a conscious act, and people tend to hack around with a single language rather than picking the right tool for the job.
While I'll admit I've never done any compiler work more serious that a trivial undergrad coursework task, I imagine that the constraints of pure FP would obviate a lot of the incompatibilities, as you would be able to call FP subsystem from anywhere, but the FP section would not be able to call out anything else (as that would break purity).
All you have to do is make sure a call into FP works, whether by typechecking immutability of arguments at compile time or actively "freezing" any mutable arguments at run time. (That could be a slightly altered call system from within the procedural system, but it should be essentially transparent to the coder.) Once you're in the FP system, the differences are perfectly OK as they don't make a bit of difference to the result you'll get when flow control returns to the procedural subsystem.
The point would be to encourage cross-calling wherever appropriate. I accept that this would open up the potential for programmers to overuse cross-calling, and that that could potentially introduce new inefficiencies, but I believe that would be a fair trade-off against the inefficiencies that would be eliminated by having enforced mutability and mathematical provability for various subsystems.
Similar fundamental incompatibilities exist for type-systems, memory-management strategies, approaches to concurrency and parallelism...
I may be missing something, but concurrency and parallelism seem trivial for immutable items, which means the functional subsystem would not need to interfere with the main system in that sense. Memory management is clearly a bigger issue.
I personally believe, and admit I may be wrong, that most of the difficulty in reconciling multiple languages is that they all attempt to do too much. If you strip away all of the hacks that allow you to do things that are not appropriate to the paradigm, integration would be simplified -- still not a trivially easy task, certainly, but maybe worth doing anyway.
The name had washed over me completely when I read TFS. Not only the name, but the fact that we were talking about a Dell device. This thread has now set the name in my head.
Come on, do you think that by repeatedly saying "Dell Venue 8 7000" he is making people who had never heard of the Dell Venue 8 7000 more aware of the Dell Venue 8 7000? Really? Because I'm now going to forget that name dead easily now, because he keeps saying Dell Venue 8 7000.
How do these "paper thin" devices feel in the hand?
I already find my iPad Mini quite uncomfortable to hold for any length of time. It's too thin.
Devices are now thin enough that it's only a pissing contest at this point.
Devices are now even thinner than a stream of piss...!
Stupid idea. People use desktops for completely different reasons than phones. And we can already run apps on smartphones and tablets, so Canonical is again walking backwards.
Yes, people use desktops for different reasons than phones. People use desktops for more things than phones. Most of the use cases for mobile apps are very restricted, and can be therefore encoded in a narrow set of runtime libraries. Why does Spotify take up 175MB on the iPad, even when you aren't caching any audio locally? It's unnecessary bloat, and the customer suffers. I wonder if they do it on purpose, to try to make sure you don't have space left to use competing services....
The same way it did for Apple - by scrapping the stupid idea in the next version in favor of native apps.
It didn't work for Apple because of the commercial nature of the app store -- everyone offering apps was looking for brand awareness. Ubuntu is Linux, and Linux is dominated by free software. Free software doesn't need brand awareness, because brand awareness is mostly about money. A great many apps unnecessarily tie function to the front end, when almost all the functionality is effectively a code library, and this is because they need brand awareness. Some Linux media apps still use a daemon for the actual grunt work and have a choice of lightweight GUIs, so the backend code is universal, and the user can chose how they want to interact with it.
Ubuntu Phone could kickstart a renaissance in the original Unix code ethos....
Except that developer time is expensive, and a heck of a lot of "native" apps are written in and bundled with some 3rd-party run-time environment that chews up memory and processor cycles anyway.
Cool spinmeistering, brah. But all I hear is someone making up excuses for why Ubuntu phone will have less developers and fewer apps than even Windows Phone. And that's no small accomplishment.
I don't know about you, but I for one am sick of downloading multiple megabyte apps from various websites to view what is essentially the same as what's on their webpages. Sometimes you end up getting 200Mb for a catalogue that doesn't even store offline data, which is frankly ridiculous. I've got an app for a TV station that weighs in at 20Mb, and I need it because the video on the web version is all Flash (and I'm on iOS) and even that seems too much (I can't imagine that they're using a codec that doesn't have native support on iOS.
I think they're making a smart decision here. What users want are services, and there's no reason for services to require their own apps, which is why 3rd party apps that collate information from multiple social media accounts (for example) are so popular.
If I can cut to the core of your argument:
Humans don't think procedurally
That's ridiculous. Of course humans think procedurally. Don't know how to do something? Here's this step-by-step procedure! If you ask how to bake cookies or change your spark plugs, you'll find (and expect) that you're provided a handy list of steps.
Humans can cope with procedural instructions, but it's not our most natural mode of thought. But even within the steps of a recipe, there are lots of jumps where descriptions change or items aren't repeated. e.g. "Sift the flour, sugar and baking powder together into a bowl. Beat an egg and milk with 1 tablespoon of milk, then add to the dry ingredients and mix thoroughly". Notice that "the flour, sugar and baking powder" becomes "the dry ingredients". The fact that the egg/milk mix is being put into the bowl is an unstated assumption in the call to add the mix to the dry ingredients. Adding to the ingredients is declarative rather than imperative. The fact that an egg must be cracked and emptied before beating is omitted, which is again declarative as it's an unstated prerequisite. You could claim that proc beat(egg) includes if intact(egg) { crack(egg) } but that's a bit of a hack. It's still an assumed prerequisite, and all we're doing is trying to hack a bit of declarativity into the imperative paradigm. We do this because humans think declaratively.
Just think of the classic "peanut-butter and jelly" demonstration of trying to tell someone how to make a sandwich procedurally -- it's really hard, and even many programmers can't do it right first try.
I've used that and similar problems when teaching kids how to program. Not a single child has failed to get it right on the first try.
Then you weren't doing it right. The whole point of the exercise is for them to get it wrong. Your job is to take the slightest ambiguity and do it wrong. You don't ask them for clarification, you don't let them shout "STOP!" when you're doing it wrong. Almost nobody every thinks about the fact that you need to line up the corners/edges -- it's so much a natural part of our understanding of "sandwich" that it never strikes us as significant. Have you really seen someone fail at this? Were they conscious?
(Just thinking about it, that's often how kids explain things to you when they're proud of some accomplishment. "I did x! ... First I ... then I ... ")
So, without providing a list of steps, can you explain to me how to make a peanut-butter and jelly sandwich? Surely, there's a much more natural way to communicate that knowledge, yes?
Why? Because functional programming cannot do everything. The best toolbox doesn't contain one tool that can be used to do everything, but multiple tools that can be used together. I mean, you can tap a nail with a chisel, and you can cut a plank of wood it half with a chisel, but you'd be better with a hammer and a saw. If we try to make all of our languages do everything, we end up no specialised tools. So we need to focused on integrating muktiple tools into a single toolbox.
What I'm trying to suggest is that the whole idea of "a language" is wrong. Instead, I would like to see a multi paradigm "multi language" - ie a single type system and calling mechanism which unifies various syntaxes incorporating multiple programming paradigms. We already sort-of-kind-of do this, but our paradigms are all hidden in libraries, and we end up missing out on compile-time checks (eg cross-calling SQL from an unverified ad hoc string, rather than having properly mediated source code). But we kid ourselves on that we don't do this. We need to accept that we do and explicitly make tools that support it.
OCaml is an imperative language -- I was talking about FP as declarative. Haskell may be described as "pure" functional, but it still allows monads with side-effects, which means it still has order-of-execution issues and is therefore not declarative. So clearly I was not talking about OCaml or Haskell. This is a theoretical question, because "here in the real world", there is no declarative functional language to benchmark against.
My personal belief is that the problem with FP is the same problem as every other terse paradigm has: it can't do everything. Procedural programming is our default option, in a "a jack of all trades is a master of none" type way. Everything is clumsy, but everything can be done. The problem with multiparadigm languages is that they either make everything possible, so nothing is guaranteed (eg "Python can be used for functional programming", but it never enforces immutability) or everything descends into a morass of keywords, imperatives and classifiers. But more importantly, every language sticks to a single syntax, regardless of the paradigm, when individual paradigms really need their own syntaxes. If you can program in a statement-based style inside your functions, everything gets confused.
I strongly disagree. As you said: "you still need to break it down" which, adds to the cognitive load.
You either have to break down or build up, and either is a cognitive load. What I like about the Python list comprehension is that having the statement in brackets basically screams THIS IS A LIST and it's very hard to miss the intended meaning. The C# list comprehension doesn't have any similar visual indicators, and the readability relies more on meaningful variable names
The for loop is not only neatly broken down for you, but includes additional information to help you understand each part and the relationships between each part.
No, the thing that's most sorely lacking in imperative programming is structures that explicitly encodes relationships between statements. Consequentiality from one line to the next is almost entirely buried in the (unseen) state of variables.
Further, the components themselves are also "in order" making it read more "naturally". The order in the list comprehension example might as well be completely random. Consider the same example using list comprehensions in C#: my_list = from x in list where x > 0 select x*x;
This is dramatically more readable than the Python example simply because those imperatives of imperative programming (direct sequencing, conditional branching, bounded iteration, and conditional iteration) are still applicable.
That assumes that imperative programming is natural, which it is not. People have great problems learning to program because human thought doesn't work that way. Just think of the classic "peanut-butter and jelly" demonstration of trying to tell someone how to make a sandwich procedurally -- it's really hard, and even many programmers can't do it right first try.
It's almost as readable as a for loop, though it still requires special/uncommon knowledge; just far less than in the Python example.
I suppose it doesn't really matter how much better or worse than other languages handle them. In every case that I'm familiar, they add complexity (without also adding value, an unforgivable sin). Complexity, naturally, harms readability.
Reductio ad absurdum: Complexity harms readability. Base 10 is more complex than base 2, therefore 11001 is more readable that 25. The flaw in this logic is simple -- although base 10 is more complex, base 10 is an integral part of our daily lives. Or to put it another way, base 10 is compatible with human thinking. Humans don't think procedurally, and we don't speak in strict chronological order -- "always wash your hands after going to the toilet".
Let's bring that back to a list comprehension. For the English "give me a list of the names of all the students in the class whose grades are above 50%", the pseudo-Python list comprehension would be = [ student.name() for student in class if student.grade() > 0.5]. And yes, there are multiple ways of issuing the same command in English, and I've selected the one that matches the Python syntax most closely. That isn't important, though -- Python's syntax models a possible human syntax, therefore has high compatibility with human thought. On the other hand, I'd struggle to produce a natural-sounding English analogue to the C# syntax. All the "for... if..." stuff doesn't imply "list" -- only the "select" does, and it's an odd word in the situation.
The Python starts with our goal in brief, then gives more information, which is human nature. In fact, if you think about it, assignment statements in most programming languages do. A few languages tried doing it the other way round, as this was a purer procedural way of doing things ( eg 3*x+2 => variable ), but programmers didn't like it that way round, because the variable is the goal, and the expression is more information.
As for FOR loops being the most readable, well, let's try a FOR loop in English. "Ma