Recently, i had to understand the design of a small program written in a language i had no idea about (ABAP, if you must know). I could figure it out without too much difficulty.

I realize that mastering a new language is a completely different ball game, but purely understanding the intent of code (specifically production standard code, which is not necessarily complex) in any language is straight forward, if you already know a couple of languages (preferably one procedural/OO and one functional).

Is this generally true? Are all programming languages made up of similar constructs like loops, conditional statements and message passing between functions? Are there non-esoteric languages that a typical Java/Ruby/Haskell programmer would not be able to make sense of? Do all languages have a common origin?

The basics of most procedural languages are pretty much the same.

They offer:


Scalar data types: usually boolean, integers, floats and characters
Compound data types: arrays (strings are special case) and structures
Basic code constructs:  arithmetic over scalars, array/structure access, assignments
Simple control structures: if-then, if-then-else, while, for loops
Packages of code blocks: functions, procedures with parameters
Scopes: areas in which identifiers have specific meanings


If you understand this, you have a good grasp of 90% of the languages on the planet.
What makes these languages slightly more difficult to understand is the incredible variety of odd syntax that people use to say the same basic things.  Some use terse notation involving odd punctuation (APL being an extreme).  Some use lots of keywords (COBOL being an excellent representative).  That doesn't matter much.  What does matter is if the language is complete enough by itself to do complex tasks without causing you tear your hair out.  (Try coding some serious string hacking in Window DOS shell script: it is Turing capable but really bad at everything).

More interesting procedural languages offer


Nested or lexical scopes, namespaces
Pointers allowing one entity to refer to another, with dynamic storage allocation
Packaging of related code: packages, objects with methods, traits
More sophisticated control: recursion, continuations, closures
Specialized operators: string and array operations, math functions


While not technically a property of the langauge, but a property of the ecosystem in which such languages live, are the libraries that are easily accessible or provided with the language as part of the development tool.  Having a wide range of library facilities simplifies/speeds writing applications simply because one doesn't have to reinvent what the libraries do.  While Java and C# are widely thought to be good languages in and of themselves, what makes them truly useful are the huge libraries that come with them, and easily obtainable extension libraries.

The languages which are harder to understand are the non-procedural ones:


Purely functional languages, with no assignments or side effects
Logic languages, such as Prolog, in which symbolic computation and unification occur
Pattern matching languages, in which you specify shapes that are matched to the problem, and often actions are triggered by a match
Constraint languages, which let you specify relations and automatically solve equations
Hardware description languages, in which everything executes in parallel
Domain-specific languages, such as SQL, Colored Petri Nets, etc.


There are two major representational styles for languages:


Text based, in which identifiers name entities and information flows are encoded implicitly in formulas that uses the identifiers to name the entities (Java, APL, ...)
Graphical, in which entities are drawn as nodes, and relations between entities are drawn as explicit arcs between those nodes (UML, Simulink, LabView)


The graphical languages often allow textual sublanguages as annotations in nodes and on arcs.  Odder graphical languages recursively allow graphs (with text :) in nodes and on arcs.  Really odd graphical languages allow annotation graphs to point to graphs being annotated.

Most of these languages are based on a very small number of models of computation:


The lambda calculus (basis for Lisp and all functional languages)
Post systems (or string/tree/graph rewriting techniques)
Turing machines (state modification and selection of new memory cells)


Given the focus by most of industry on procedural languages and complex control structures, you are well served if you learn one of the more interesting languages in this category well, especially if it includes some type of object-orientation.

I highly recommend learning Scheme, in particular from a really wonderful book:
Structure and Interpretation of Computer Programs.  This describes all these basic concepts.  If you know this stuff, other languages will seem pretty straightforward except for goofy syntax.
