Yep, Programming Is Borked
evincarofautumn.blogspot.com
evincarofautumn.blogspot.com
With an Euler integrator, you say? (every frame, p=p+time_scaled(v), v=v+time_scaled(a) ). Note there's an implied time, as well as frames per second, in there, but a compiler can know about time. Unless when you're saying "acceleration" you're not talking about real time, but calculating where something will be at a future time...but I digress.
What about a Verlet integrator? [1] Maybe you'll also want to add springs, and Verlet works better for springs. Or maybe a Runge-Kutta [2] integrator? You can get more accuracy out of one of those. Though some people claim that a higher frequency Euler integrator can do as good of a job, possibly with more stability.
And how many times per frame should the system run the integrator? Because the stability of a system can depend a lot on the interval size. In fact, you might want to experiment with different integrators, and different time intervals, to get the result that's best for your application.
These are all choices that a PROGRAMMER typically needs to make, and they can be different for every problem. More than that, unless your compiler can DERIVE all of the above equations and more, at least one and probably several would need to be built in to the compiler.
This "problem" hasn't been solved because, short of creating strong AI, it's not solvable. This can only work when you're writing something like a "game builder" app: A domain-specific problem solver that is designed to deal with a very specific problem -- and which is coded using a traditional approach.
[1] http://en.wikipedia.org/wiki/Verlet_integration [2] http://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods
So when you've got to write a sort, you probably start in our hypothetical dream language by saying:
"sort permutes a list so that a < b implies list[a] < list[b]."
Now "permute", with predicates, is probably built into the system and the constraint solver probably turns this into a variant of bubble sort, O(n^2). [That is, when you now query list[0] it does a reverse bubble-sort by looking for the least element rather than the greatest element, moving that to the lowest position.]
Now you come into this and say "hey, I've got a huge list, I need O(n log n) power." What do you use? Perhaps merge sort.
"sort zips together, least-element first, the sorted first half of input and the sorted second half of input -- unless len(input) < 2, in which case it just returns the input." Zipping together on predicate p may or may not be a fundamental design element of the language.
If you can establish a consistent syntax for these sorts of claims which a constraint solver can follow, then the simplicity of the constraint solver, and your ability to guess what it will do, will allow you to determine which algorithm you use to perform the same task.
So it doesn't require strong AI and the programmer is still making the choice -- that's what I'm trying to say. The programmer is merely making the choice in a different framework: rather than making the choice in some wrapper for blocks of assembly language, you are making the choice in some wrapper for a constraint solver.
Now let me turn from where I think you're wrong to where I think you're right: I have the feeling that you're going to see something less revolutionary than claimed, because it will be like C's inline assembler support; in this hypothetical language you can probably "drop back down" to the pre-constraint-solver level when you can't figure out how to articulate the problem with constraints. (Something like "The constraint is, it has to come from applying this function to those lists!")
If you're defining the algorithm to that level of detail, then I submit that you're writing the algorithm. What you just described looked almost exactly like how it would be written in one of the more advanced current functional languages, and the OP and previous OP that he was responding to both considered functional languages to be Not Good Enough. What they're asking for is pretty much just Sufficiently Advanced Technology to Do What They Want (i.e., Magic, or strong AI).
Aside from that, sort IS something that's so common that it tends to be implemented in every high level programming environment in one way or another. Baking several sorts into a language isn't odd, so I don't think "sort" is a good example, because I ALREADY can say "take this list and sort it" in any language I use.
An Euler integrator isn't built in to anything but a DSL for animations or games, though. And it's one of THOUSANDS (millions?) of algorithms that a program might need -- most of which are more easily described (by the programmer) in a traditional language than by trying to jump through hoops to describe what you want in a way that you'll actually get what you want.
So yes, the trivial problems could be solved by such a language -- but they're already solved by CURRENT languages. It's the hard problems where it would be hard to know how to even start to create a "describe the results" language. I think all you'd end up with is a DSL for each of the cases you thought to describe -- which, depending on the domain, could be useful for that domain. DSLs are great when they're well designed. But as someone else pointed out, you don't write a game in SQL.
In the real world, you write programs that connect to databases, transform parameters, perform a bunch of linear algebra calculations, invalidate caches, and output results to a webpage (for example).
The overall specification of what the webpage is, from start to finish -- is simply the program you wind up writing! You have to specify what information you're getting from the DB (the query), with what parameters, the equations to perform after it returns (using a numerical library), how to invalidate which caches (a bunch of specific function calls), and how the webpage should be constructed (the HTML template).
Writing all this in a "declarative" way seems to make as much sense as throwing away your cake recipes and just using cake photos instead, because that's the "result" you want.
The cake photo is useful for two things only:
1) Mentally, having an overall idea of what it is you want to make (lacking many details, however) 2) After you baked the cake, making sure it looks like the photo
Analagously, declaring things at a higher level in a programming project works marvelously in two areas:
1) Designing what you want to build, in a big picture 2) Testing that what you built satisfies the top-level constraints
When artificial intelligence is a smart as humans, they'll we'll have computers that can write our programs for us, and we'll have "declarative" programming. But of course, we'll blame the computers when the programs don't work, just like users blame programmers now... :)
“The overall specification of what the webpage is, from start to finish—is simply the program you wind up writing!”
This is not true; the implementation is very far removed from the specification. It is not easy to look at a bunch of SQL and PHP code and deduce precisely what the requirements of the site are. But in a different sort of language, it could be.
With DSLs and advanced programming techniques (FP, macros, AOP, well composed OOP, etc.) you can reach a state where the intention of high-level code is stated clearly, but you're never going to be saved from getting your hands dirty with the details.
This "programming sucks" thing could get old quickly. Most of the problems mentioned in these articles are already solved in some language or another. And many of them are too specific. Like wouldn't it great to eliminate for loops? Well, yes, for the specific cases where the alternative would work.
More pressing problems include lack of a REPL as a primary development environment, no decent way in most languages to organize and update libraries in a seamless manner without breaking anything, no good way for multiple programmers to collaborate in real time, lack of run-time interactivity and in-place replacement of components of a running program, etc.
In other words, I applaud your motivation, but if you want to reinvent programming, please don't reinvent Lisp, Prolog, or Haskell. It's just syntax, and that's been done to death. Reinvent Smalltalk and Erlang instead.
Edit: By the way, Microsoft Excel has many of the features these blog posts talk about. Type in Jan, Feb, Mar, then draw a box around those and drag to the right. Magic! However, the utility of these things in a small number of cases doesn't mean the idea can scale to a more general solution. The same idea in MS Word is the awful numbered list creator that never does what you want. I think you'll run into those edge cases much more quickly than you think.
And now, as a programmer, I don't just have to remember foreach..., I have to remember 1500 different ways to iterate through a list. I'd much rather have the general foreach tool and write my own "pairs" function. It takes one minute.
Furthermore I think the author dismisses the performance problem too easily. The code examples don't give any indication of the algorithmic complexity. I suppose I could determine it, possibly quite easily, if I understood how the compiler works but why would I want to know that?
I expect that this abstraction will make debugging performance problems a nightmare or it will leak the information. I will have to change perspective from "what" to "how" quite frequently which would distract me from my real goal.
I hope to be proven wrong though, this does look interesting.
I confess to linkbaiting a little with the title. Where we are now isn’t utterly broken, but the way we think about programming can always improve, and this is one direction I can envision improvement. Also, I wanted to tie it in to the article I was referencing.
Performance is obviously important, but it’s a large topic and I didn’t have strong enough examples on hand to make the point I want to make. I’ll definitely go into more detail on that point in a future article. The gist is that high-level languages don’t need to sacrifice performance if they are constructed in such a way that the program contains enough meaning for the compiler to intelligently optimise it, a property which existing languages tend to lack.
And if I may say so, I hope to prove you wrong too! ;)
Sometimes, "what" I want is a program to do this that and the other thing in this given order. ie the "how". Other times, I don't care, I just want these properties to hold. Yet other times, I have no idea what I want at all and have to experiment and see what happens.
I want a language that solves the composition problem between these distinct solution spaces. The best programming language for any given task is the one who's world view best matches the preconceived spec in the programmer's head.
Most research languages take a key idea (everything is a list! or no side effects! or something like that) to a logical extreme. That's a great way to study a set of phenomenon in a particular little universe, but most practical languages find a happy median of thought-pure and just-fucking-works. We need to get some of these wins from high concept languages back into just-fucking-works languages.
And yet, from a practical standpoint, Haskell is not pure. The underlying abstractions are pure, sure, but the language makes working with impure computation feel just like writing an impure program. The magic of Monads and do-notation may sound complex, but in reality it's just a neat way to write impure code in a pure way (sounds like a paradox, but it isn't).
Look at this snippet:
main = do name <- getLine
putStr $ "Your name is " ++ name
This trivial program is technically purely functional. And yet it is also imperative from the programmer's point of view! It looks just like something you might write in Python with slightly different syntax.So you say, what is the advantage to writing a program this way rather than using an impure language? The answer is simple: Haskell lets you mark impure code using the type system. This is similar to the Scheme/Ruby convention of 'do!' functions being unsafe, but actually enforced.
This sequestering helps you avoid bugs by not having implicit mutation and IO everywhere and it helps the compiler do clever optimizations like running your code in a different order. And yet, if you need it, you have IO and State and fancy things like STM right there, with only a little bit of complication.
Of course, learning to think in this admittedly roundabout way is tricky. But learning is a one-time cost; using a less expressive or harder-to-maintain language is a recurring cost.
In other words, there is no reason why a language focusing on one idea can't be a "just-fucking-works" language as well. In my experience, Haskell and Lisp are just as practical as others; the only difference is in the initial learning period. Look at Common Lisp: you can't get more "just-fucking-work"ing than that!
I think that one should usually ignore a one-time cost like learning in favor of recurring benefits, but others naturally disagree.
It's complicated as all hell to implement some very simple, and well known algorithms which rely on mutation and explicit memory management.
Take, for example, QuickSort:
"sorta looks like quick sort" http://www.haskell.org/haskellwiki/Introduction#Quicksort_in...
"actual quick sort w/ in place memory mutation" http://www.haskell.org/haskellwiki/Introduction/Direct_Trans...
The short, few-liner Haskell version is beautiful. It's also not the same algorithm. So then you whip out the larger "direct translation" version and, suddenly, you're wishing for C.
This story repeats itself over and over again. For example, try implementing the Fisher-Yates shuffle.
Now, in practice, you don't need in-place swaps. And you can argue code style and YAGNI and pre-mature optimization and practical implications and day to day use and parallelization and whatever etc. Yada yada yada.
I'm not saying there is anything wrong with Haskell. I'm saying that foundation of Computer Science lies in the study of data structures, algorithms, and computability.
Software Engineering basically boils down to a search and optimization problem: Find the data structures and algorithms which (1) minimize the weighted average of costs and (2) maximize the value that the solution generates.
Haskell's approach to Software Engineering presupposes the cost savings to isolating mutation (and other purity concerns) as a requirement. I'm simply advocating future language developers consciously address the problem of finding those optimal data structures and algorithms in minimal time, with an eye for the fact that data structures and algorithms are a fundamental law of computation.
It is not inherent that Haskell's quickSort is harder than quickSort in C.
Take a look at Augustusson's imperative language DSLs in Haskell:
http://augustss.blogspot.com/2011/07/impredicative-polymorph...
Haskell is so versatile at this, augustusson managed to implement an old BASIC DSL!
http://augustss.blogspot.com/2009/02/more-basic-not-that-any...
I think Haskell can be a great vehicle for all our current day imperative programming needs (even if due to some library issues it's not quite as nice for all tasks yet).
http://zackarymorris.tumblr.com/post/10973087527/the-state-o...
I'm thinking that if you chop a program up into many small pieces, each part is simple enough that it can easily be solved by the compiler with something like genetic programming (or better yet, methods in languages like Prolog that already work for small problems).
So much of what we work on now is a waste of time (I'd say well over 90%), things like syntax errors, makefiles, DLL hell, code repo weirdness, managing web servers, concurrent programming, just on an on and on, that I gave up on working on real problems over a decade ago (the kind we learn in school in lisp/Matlab/Mathematica etc).
I would really like to write an entire program sometime as a big tree, that would be convertable back and forth to something simple like JSON. Then the compiler would go through and convert my simple statements like "when this sprite touches this sprite, give them opposite speeds) into the underlying code so I don't have to waste my time with it. I know we think that we work on more complex stuff than that, but I think if most programmers audit their time, they'll find that very little of it goes into the mathematics of solving problems (10%). I realize the logic may not be solved anytime soon, but maybe the minutia can be. If we don't obsess on finding the perfect algorithms, but allow ourselves a floor of say O( n^2 ), I think our productivity could go up substantially.
Maybe it's time for a bunch of geeks like us to be willing to unlearn what we have learned, basically scrap everything, and try working backwards from what the solution will look like (what people will be using in a few decades).
That would be Lisp.
> convert my simple statements like "when this sprite touches this sprite, give them opposite speeds) into the underlying code so I don't have to waste my time with it.
That's function application (if at runtime) or macro expansion (if at compile time).
I think I'm talking more about readability than sophistication. I want to write in a high level language like Hypertalk (from the HyperCard days) and let the compiler create a series of permutations under the hood that I could review and say "yes that one works, use it" and then maybe the compiler could annotate my code with more precise limits on what I said. So for example I tell it I want to sort a list, it shows me algorithms that sort numbers, strings and objects, and I say "yes strings are good enough" and it shows me the updated version of my code showing that it requires strings.
I know that sounds a little weird but this is 90% of the minutiae that I deal with on a daily basis and I am thoroughly disgusted with how myopic and restrictive tools have become today. They break when I forget a semicolon, when I would much rather have them show me an edge case of my algorithm that is incorrect.
I use Lisp by preference because it's so much easier to express my ideas without whacking on the syntax mole.
They had come up with a neat solution involving really tight depth of field and doubly exposed file with two different colour filters a short time apart. So we had a slice though the droplet cloud.
I was told oh we have brought an A0 digitizer (costing about twice my salary at the time) work out how to interface to that PDP and develop a system to locate the droplets in the xy plane.
To solve that you actually have to know real engineering to get this to work the actual programming is the easy bit. I also had to work out how to write a interrupt driven driver to interface the tablet to the computer – Luckily RT11 did have some basic multitasking functionality built into it.
PS we did also use prolog on other projects so it does have its uses
First, they wrote their programs in the form of what they want it to do. Then they left the dreary how part to a sufficiently smart new compiler called "Outsource" that was generally available only in India and other low-cost-but-technically-competitive countries. After sending the source code to "Outsource", the first compiler pass would start. It might come back asking some clarifications and details for ambiguous cases and they refined their program as needed. Finally, after waiting for a few weeks they got back some results.
The resulting program was tested and any problems written down, and more refinitions followed by a set of new iteration rounds to and from the "Outsource" compiler suite.
Turns out, to describe the hard parts of a problem in sufficient detail equals more or less writing the program itself. It's just that instead of the laid off local programmers, the development managers and technical leads that hadn't have to code much earlier had to do the programming. They could describe their programs in English but they couldn't escape detailing the hard parts of their problems. And then again, the easy parts of programming never were a significant cost-factor in the first place.
Then some people figured that instead of having people program the smart remote programmers without domain knowledge to do what was needed, they could employ nearly as smart local programmers with domain knowledge to do the whole programming. The upfront costs would be higher but on the other hand the hard process of explaining the hard parts of a problem, which was needed regardless of the programming scheme, was much easier because communication was almost instant and the programmers both held local domain knowledge and programming skills.
While the local programmers still had to spend expensive time writing some unavoidable boilerplate, it was left unclear whether using "Outsource" saved any money at all because the terms of programming with it were also so different.
Agreed, but there are good reasons that one hasn't been built yet, and they have nothing to do with lack of motivation.
[1] Sufficient for all possible measures of sufficient.
Wait, you're saying that I could make an imperative results-oriented language as easily as a declarative one? Perhaps the author meant "is not identical to" rather than "orthogonal"?
I think there are other caveat of specifying only the results.
You posted earlier on the halting problem
http://evincarofautumn.blogspot.com/2011/10/solving-halting-...
That post also contains a statement which I believe to be false. You state that the "Haltability problem" (where you are given a program P and want to determine if there exists an input on which it halts) is decidable but its not.
Basically, I can just hardcode any input I of my choosing into P so that it always does the same thing (run P on I) regardless of the actual input I' you provide it. Thus, I can use an algorithm for the Haltability problem to solve the halting problem.
I know that does not pertain to this post directly but the halting problem does. Given a program written in this new language, how can you determine if what the programmer specified can even exist as a program?
In fact, suppose you specify the properties of this new language you current wish to construct (in say, English and assume that everything is interpreted correctly). How do you know such a language could potentially exist (never mind implementing it)?
I also don't even want to think about debugging in such a language. More specifically, I would rather have a library for the example you described because if I make a mistake in my specification, I have ways to find the error in it. But I guess this goes back to my previous question: what does your compiler produce on an incorrect (or outright impossible) specification (i.e., piece of "code")?
Its certainly interesting to read about thoughts on potential new languages but I wish there were more solid theoretical foundations for posts like these. Otherwise, I feel that the same energy would be better spent on improving existing languages with some subset of the features you want.
If you come up with some sufficiently-liberating declarative language, you still need an amazingly smart compiler to use it. People will invent new types of these languages, as the style catches on, and there will be lots of people writing the runtimes and the algorithms that you (the one taking the declarative route) depend on to get a reasonably-performing program out of the whole process.
Your post would be strengthened by omitting that detail.
I'm not trying to judge your experience, rather just commenting on the statement itself.
Prog : which (1..10) > 5
LISP : (remove-if #'(lambda (n) (<= n 5)) '(1 2 3 4 5 6 7 8 9 10))
Prog : each (1..5) 2
LISP : (mapcar #'(lambda (n) (expt n 2)) '(1 2 3 4 5))
So, using research into how people best solve problems, I’m making a tool that helps people solve the problem of having an idea and not being able to make it a reality.
Novices will still have lots of problems. They don't really think about how sprites move in a game, they think they want to make a game kinda like Asteroids or more like Mario. What will really help them is a well organized, well documented template.
The problem is with documenting, organizing and making available the multitude of libraries and solved problems. Making them accessible through visual examples and natural language.
http://blog.wolfram.com/2010/11/16/programming-with-natural-...
The Wolfram approach of writing a query, seeing the output, confirming or rejecting it is the right direction. Memorizing syntax is a big problem.
[1,2,3].byPairs == [[1,2]];
[1,2].byPairs == [[1,2]];
[1].byPairs == [];
This doesn't solve syntax memorization. split array by pairs == arrayPairTransform([1,2,3]) == [[1,2]]
make array of pairs == arrayPairTransform([1,2]) == [[1,2]]
This is closer imho. You don't really have to worry about the [1,2].byPairs being prettier than splitArrayIntoPairs([1,2]). You can use your queries as the pretty documentation. You can choose which lower level language to use in the code column, without having to remember its particular syntax. You don't have to worry about naming as much, you're using tags instead.A lot of novice programming is looking up code samples and libraries, getting them to run. Organizing existing code in libraries and samples for a specialized natural language search engine like in Mathematica seems like it would change some design decisions of the lower level language.
It's not as important if the lower level language is a bit more verbose. Your priorities for it would be performance, control, parallelism/concurrency, regularity. Expressiveness/verbosity can matter less if you offload it to another layer.
http://spottedsun.com/why-cc-sucks/
I removed the fundamentals and only posted a core problem I found with c/c++: prerequisites
http://en.wikipedia.org/wiki/Fifth-generation_programming_la... (Fifth-generation programming language)
It was led by Japan.
http://en.wikipedia.org/wiki/Fifth_generation_computer_syste... (Fifth generation computer)