strong abstraction from the details of the computer
and more specifically
includes concepts from the problem domain instead of those of the machine used
What are "details of the computer"?
There are too many to list. The are generally either details of the computer architecture (generally solved by the core language) or interface and protocol details that are outside the problem domain (solved mostly by libraries).
Computer architecture examples:
- Registers, the stack, the instruction pointer and jumps - almost all languages other than assembly abstract these, generally into function or method invocation.
- Linear execution and program flow - Abstracted by logic languages, lazy functional languages and langauges with continuations; not so much by anything else.
- Memory locations and memory management - The reason why C, C++ and Objective-C are not completely "high-level". Very HLLs provide garbage collection.
- How big is a machine register, or a word/byte of storage? How many bits are in an "Integer?" What's a "floating-point number"? What's the biggest or smallest one I can have? Java and C# (and many others) expose this to the programmer; this one bothers me.
- How many processors does the computer have? How do I divide large tasks between them? Again, most supposed high-level languages leave you on your own here.
- What physical inputs and outputs does this computer have? To mice and keyboards, screens, printers, a network?
- File formats, file locations and filesystem layout. Varying support.
- Operating System calls - Mostly wrapped in built-in libraries. Occasionally (C family) available directly but avoided.
- Network protocols - What details aren't handled by the OS are either handled by libraries or not at all (HTTP, SMTP, etc.).
- GUI APIs, CLI APIs, service APIs... Both consuming and providing.
- Too many more to mention
What are "concepts from the problem domain"?
Depends on who you ask, and how they choose to view the problem.
Most major programming languages take a singe general view of all problems and how to produce solutions; these tend to align with one or more of the major paradigms (procedural, functional, OO, logic, array, etc.). General programming languages thus view the problem domain as "almost everything".
Some languages work especially hard at allowing the user to create domain-specific languages, either by allowing direct extension of the syntax (Common Lisp, Scheme, OCaml) or through other means like metaclassing (Python, Ruby) or combinators (Scala, Haskell).
There are true specialized languages that approach a smaller problem, but you mostly see them inside a host language. There's XSLT for formatting, Regular expressions for string mangling, SQL for (somewhat) relational data, and XML-based languages for just about everything.
Whoops, that wasn't the question.
Here's my rough division of 3 subdivided "heights" of language level, from highest to lowest. This is based on the above ideas, sort of. Oddly, the languages at the very top are the least powerful and general; some may not even be turing complete!
In my opinion, the most high-level languages are those that almost entirely throw out how the surrounding computer works. There are really about three categories of these:
- Business domain specific, e.g. languages specific to phone systems or dolphin research or DSP. These are more rare than they used to be (say, per programmer alive). These "include specific details of the problem domain", as above.
- Task-specific Little Languages like XPath, XSLT, smaller SQLs, Regex, Make, dc or m4 macros. See link for many more (mostly Unix-related). These mitigate specific "details of the computer", as above.
- Very high-level general languages that are divorced from the underlying computer to a specific end. The languages I consider in this category take one or more language paradigms to a useful extreme: J, Prolog, Haskell, Oz, IO, and perhaps some concurrency and dataflow languages. These attempt to completely eliminate "details of the computer" and also clearly have the ability to approach all problems that are not bound to hardware.
The remaining languages that I consider high-level languages are those that provide a straightforward way to build DSLs or other very clear, compact interfaces. (These interfaces, in function, qualify as "little languages" as above!) These I separate again into (ranked-ish) categories:
- Lisp dialects and other systems with syntactic macros (Dylan, Metalua)
- Languages that strongly encourage DSLs and compact APIs. This means simple syntax and "late binding in every aspect". Here I include Python, Ruby, Smalltalk, IO, and many others.
- Other languages, when equipped with text macros or code generation systems. Not ideal, but better than nothing.
Below this is everything else. They vary by level, but they are not high level anymore. This includes languages like C, C++, Java, C#, Cobol, VB6, VBScript, PL/1, Ada, perhaps the Algol family... You name it.
Specifically Java and C# (and even C++) may impress others as "high-level", but for me they have too many strikes against them. I feel the class systems and type systems are still dictated by the hardware and speed concerns in much the same manner as C functions and structs. In particular, those languages force the programmer to be needlessly concerned with how many bits or bytes are in everything.
TL;DR: From highest to lowest, business domain-specific languages, then little languages, then very high-level functional/array/OO/concurrency languages, then Lisps, then expressive dynamic languages, then expressive static languages, then everything else.