As Languages Evolve...
naph writes "It seems that as programming languages have developed there has been a steady increase in the level of abstraction they use. Early languages were all very low-level, but successive generations have become higher and higher. Is this trend going to continue, or do you think we've reached a kind of happy medium between power and abstraction? Would developers prefer higher level languages, or is the direct control of things good? I was just wondering what other developers out there thought of this."
One thing that has happened in PL design is that they constrain the programmer more. This tends to increase the expressiveness, unlike what one qould expect at first.
The dangers of excessive individualism are nothing compared to the oppressiveness of excessive collectivism
As long as the compiler is efficient and very good at optimizing, more abstraction is OK. But if abstraction comes at the price of too much speed (Or executable bulk), then the compiler should not exist.
Even though i am just starting programming, I would prefer a language that is more abstract. I think it allows for faster programming. Just tell me if I am wrong.
"What we have here is a failure to communicate"
The Warden, Cool Hand Luke
The entire point of computers is to do things much faster than we can do them manually (or even make things possible that weren't before).
By making programming easier and faster with higher-level languages, this contributes to that goal.
There IS a trade-off in speed by doing things at such a high level versus, say, machine language, but considering the scope of most apps these days, it wouldn't be economically viable to create everything that way. Optimising certain bottle necks in low level languages is probably about the only common use programmers will have for low level stuff in the future, except for certain special cases or very small applications.
If you have a project that needs super-duper optimization, it might be better to concentrate on improving the compiler's optimization rather than writing your app in a low-level language. Keep in mind you have to maintain your code!
It seems to me that any language, be it Java, C++ or plain old C will become more abstract on their own as people begin to use libraries and reuse classes and methods. Once someone writes some basic classes, he will write classes which use those, and so on until the classes which he writes are many steps above the original class in abstraction.
I don't really think that its a trade off between power and abstraction. It's more a case of expressiveness vs efficency. All languages have the same power - as long they're universal and not some subset of a universal language.
Expressiveness is slightly different though, as you move up through the levels of languages; from machine code up to imperative languages like C++ and then up to functional or logic languages like Haskell or Prolog - you lose control over telling the machine how to do something and focus more on what it should do.
Potentially this gives the compiler more scope for optimisation and leaves the programmer able to reason about more complex systems. Yes you could write something like, say a datamining or visualisation app in assembly language. But how much more effort would it be than doing the same in Haskell?
These nicer abstractions actually make it easier and quicker to write more complex code (theres a hell of a lot less of it for a start). I would think that theres still a level higher that we could go that would give a useful impact in productivity. The holy grail of language research is an abstract specification of what a program should do, from which an actual program can be generated automatically. This would allow complex systems to be verified more easily (and correctly) which are the kind of qualities that you need to move software from a scientfic (artistic?) discipline into a mature school of engineering.
Hopefully that would lead to more realiable systems but comes back to my original point about efficiency. In the longterm it may be more efficient rather than less to use these levels of abstraction as the large complexity of the types of systems that we will be designing will stop anyone from 'coding them by hand'.
Slashdot: where don knuth is an idiot because he cant grasp the awesome power of php
When it comes to languages, the answer is use the right tool for the job. Low level languages will always coexist with high level ones.
there has been a steady increase in the level of abstraction they use
So, C is more abstract than LISP? And C# is more abstract than Haskell? Or is this "steady increase" just an artifact of how you choose your examples?
Imagine you are hosting a party. The first person to show up will either be taller than you, or shorter. And (if the people are showing up in a random order) there is a non-zero chance that the next person to show up will either be shorter than both of you, or taller than both of you. As new guests continue to arive, we should expect the height of the tallest person present to go up, and the height of the shortest person present to go down.
I would argue that the same thing is happening with programming languages. We are not just seeing higher and higher level languages, we are also seeing lower and lower level languages (e.g. so-called programable hardware, PLAs, etc.) at the low end. More than anything, we are seeing a steady increase in the number of FORTRANistic languages that dwell somewhere between BASIC and C.
But no grand trend in any particular direction.
-- MarkusQ
Early languages were all very low-level, but successive generations have become higher and higher.
The first language was FORTRAN. The second was LISP. Your premise is fundementally flawed -- languages have not been getting higher and higher level. And before I get any spelling flames, I should point out that back in 1959, the names of both languages were still capitalized like that.
What has been happening is that generic support for useful abstractions has been slowly creeping into our languages. It seems that about once every 10 or 15 years the limitations of the current languages to express those abstractions becomes severe enough that people are willing to make a jump to the next generation of languages.
During the 70's and early 80's, ALGOL-like languages, like Pascal, C, and FORTRAN 77 predominated. From the mid 80's through the late 90's, C++ apparently reigned supreme. Now, in the late 90's and early part of the 00's, we're seeing Java and C# move into the forefront of the developer's mind.
I am loath to call any of those languages high level. C++ added generic support for several OO ideas. Java and C# have added garbage collection and much better support for runtime linking.
But in the end, all of these languages are still fairly low level. The biggest thing that has changed is the overwhelming size of the languages standard libraries, and each Operating System's runtime libraries. We've learned a lot about what programmers need to do in the last 50 years, and we've encapsulated a lot of that knowledge into standard, reusable libraries. In return, those libraries have grown huge.
Think about the size of the libraries available to us -- the KDE libraries, the Win32 runtime library, the suite of standard ActiveX controls available on Windows, the huge Java standard library, CPAN, or the new DOT.NET framework. These are where the advances have been made in the last 50 years, but with a price.
In the 70's, one programmer working a few months could have implemented an entire robust optomized copy of the C library himself, down to the syscall level. A good programmer could intimately understand the entire library in a matter of weeks. Today, it would take dozens of programmers working years to implement the Java or DOT.NET libraries. There is probably no-one who can honestly claim an intimate understanding of any of them. We've reached a point where the standard library is bigger than any one person can understand. At that is probably the biggest thing that is going to impede the development of more complex, useful libraries in the near future...
Slashdot is jumping the shark. I'm just driving the boat.
OK, wild speculation follows...
I think we're going to see languages move in two directions: higher and wider.
The "higher" languages will be designed for bigger abstractions. A lot of these will compile down to today's high- and medium-level languages. Most will be domain-specific. We've always had examples of this (e.g. parser compilers such as yacc, ASN.1 compilers and so on; there are plenty of these for high-level languages like Haskell, such as happy and Strafunski too), but I think we'll see more as we go on.
The "wider" languages will be designed to support higher-level abstractions directly by providing the basic building blocks to the library writer. We see this in C++ template libraries, Haskell combinator libraries, Lisp macro libraries and so on. They will not be as good as "high" languages in their specific domains, but they will be generic enough for "normal" applications, plus they will have the benefit of not requiring a whole other compi.
sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
Early languages were all very low-level, but
:directory '(:absolute "etc" "monkey")
:name "settings"
:type "conf"))
:if-does-not-exist :create
:if-exists :rename
:direction :output)
// is static initialization order even guaranteed?
// get the old one out of the way
// file descriptors aren't garbage collected
// now put back the old file
successive generations have become higher and
higher.
I don't buy this. Explain why Common Lisp lets
me do this, for example:
(defparameter *settings-file-location*
(make-pathname
(defun save-settings ()
(with-open-file (settings-file *settings-file-location*
(prin1 *settings*))
Java, 18 years later, requires code like the
following to approach the functionality of the
previous snippet:
/* We have to shove EVERYTHING into a class.
A singly-inherited one, no less. */
class Settings {
static File settingsFile = new File("etc" + File.separator +
"monkey" + File.separator +
"settings.conf");
static File settingsFileBackup = new File(settingsFile.getName() +
".bak");
public void saveSettings() {
boolean backedUpSettings = false;
if (settingsFile.exists()) {
settingsFile.renameTo(settingsFileBackup);
backedUpSettings = true;
}
FileOutputStream fow;
BufferedOutputStream bow;
try {
fow = new FileOutputStream(settingsFile);
bow = new BufferedOutputStream(fow);
dumpSettings(bow);
close(bow);
} catch (Exception e) {
if (bow && fow.getFD().valid()) {
close(bow);
}
if (backedUpSettings) {
settingsFileBackup.renameTo(settingsFile);
}
}
}
}
Note that this Java code loses on systems like
Mac OS, which store the file type somewhere
besides the filename.
Or how about Common Lisp's condition system,
which allows execution to actually continue
where it left off once an error is corrected?
What about MAPCAR, or DO and DO*? Heck, what
about first-class function objects?
Of course, try getting a job using Common Lisp,
or any other decently abstracted general-purpose
programming language today...
BTW, Slashdot inserted the spurious semicolons
in this post, not me.
TO BUY A NEW CAR WOULD MAKE YOU SEXUALLY ATTRACTIVE.