Programming Languages
Why Study Programming Languages?
You study programming languages to be able to
- Choose the most appropriate language for
a given task. A programming language lets you express
computational tasks in certain ways. Some do a great job expressing
some kinds of tasks and do a terrible job at others.
- Learn new languages more easily. Thinking in
terms of language independent concepts
(e.g. types, sequencing, iteration, selection, recursion,
concurrency, subroutines, parameter passing, naming, scope,
abstraction, inheritance, composition, binding, etc.) rather
than in one particular language's syntactic constructs enables
you to adapt to any programming environment.
- Use the languages you do use more productively.
If you know how and why a language was designed, you can
- choose the best way of doing a given task
- utilize some of its non-obvious powerful features
- simulate useful (and very powerful) features from other languages
if your language lacks them
- write elegant code
- impress others with your programming prowess
- understand obscure features
- understand weird error messages
- understand and diagnose unexpected behavior
- understand the performance implications of doing things a
certain way
- actually use a debugger effectively
- Design your own language. Yes, you might need to
write your own little language as part of a larger application, for example
- A query language for database access
- A query language for a search engine
- A calculator
- A console interface to an adventure game
- Learn things you might never have imagined.
Experience the enlightenment of actually understanding pattern matching,
type inference, closures, prototypes, introspection, instrumentation,
just-in-time compilation, ..
How to Study Programming Languages
You must BOTH:
- Look at a bunch of existing languages, and see how
they express and implement various concepts
- Look at a bunch of programming language concepts,
and see how they are expressed in a variety of languages
Languages
When studying actual languages, you should learn:
- Which languages are "significant" — that is, which
languages have come into widespread use or made a huge impact
on the design of future languages.
- The reason that each language was designed — that is,
what problems were its designers trying to solve?
Some significant languages are:
- Fortran (I, II, IV, 66, 77, 90, 95, 2003)
- Lisp, Scheme, CommonLisp (with and without CLOS)
- Cobol
- Algol (58, 60, W, 68), Pascal, Modula (2, 3), Oberon
- PL/I
- APL, J
- BASIC
- Clu, Alphard, Euclid, Mesa, Cedar, Turing
- Ada (83, 95, 2005)
- BCPL, B, C (K&R, 90, 99), C++, Objective C, D
- Java, C#, Scala
- Perl, PHP, Tcl, Python, Ruby, Groovy
- Simula, Smalltalk (72, 74, 76, 80), Object Pascal, Eiffel
- Self, JavaScript
- ML, Standard ML (90, 97), CAML, Objective CAML, F#
- Miranda, Haskell
- Prolog
- Snobol, Icon
- Id, Val, Sisal
- Concurrent Pascal, Occam, Linda, SR, Erlang
- SQL
- Postscript
- XSLT
- Intercal, Unlambda, Brainfuck, Malbolge, Befunge, ZT, Java2K
The motivation for some languages:
- Fortran — Numeric computation
- LISP — Symbolic computation, artificial intelligence
- COBOL — Business computation
- Algol 60 — Algorithmic description
- Algol 68 — Kitchen sink of programming language features
- Pascal — Teaching structured programming
- Modula — Modular programming
- C — Systems programming
- SQL — Database applications
- Scheme — To simplify Lisp
- Prolog — Expert systems; Natural language processing
- Smalltalk — Workstation GUI programming
- Ada — Megaprogramming; Embedded systems
- C++ — Simulation
- ML — Theorem proving
- Perl — Scripts, with a focus on text processing
- Ruby — To be the language Matz wanted (and better than Perl)
- Java — Compact downloadable executable components
- C# — To be the Java of the Microsoft (.NET) world
- JavaScrpt — Browser scripting
- Postscript — Formatting of printed documents
- XSLT — Hierarchical document transformation
Good sources to learn more:
Programming Language Topics
Topics that you come across in the study of languages:
- Language Design
- Programming paradigms
- Static (compile-time) vs. dynamic (run-time)
- Language specification: syntax, semantics, and pragmatics
- Lexical (micro-) vs. phrase-structure (macro-) syntax
- Concrete vs. abstract syntax
- Names and Bindings
- Scope, visibility, extent, storage class, linkage
- Defining and referencing occurrences
- Overloading and aliasing
- Modules, packages, namespaces, classes, units, etc.
- Object orientation
- Control Flow
- Kinds of control flow
- Operators
- Expressions and statements
- Exceptions
- Types
- Equivalence, compatibility, checking, coercion
- Systems: static vs. dynamic, strong vs. weak, manifest vs. inferential
- Subroutines
- Procedures (abstractions for commands)
- Functions (abstractions for expressions)
- Signatures
- Parameters and arguments
- Higher order functions
- Closures
- Concurrency
- Threads vs. processes
- Shared resources and synchronization
- Scheduling
- Introspection
Criteria for Evaluating Languages
Here are things you might need to look at when determining
which language to use:
Technical Criteria
Is the language
- Easy to read?
- Over 90% of programmer time is reading and modifying existing code
- Labor costs dwarf hardware costs
- If someone can't understand existing code, it will get thrown away
- Easy to write?
- If the learning curve is too high, who would bother to use it?
- Highly Expressive? Does it have
- Operators like A = B + C which adds whole arrays in Fortran 90?
- Abstract data types (with encapsulation)?
- Module and package structures to aid programming-in-the-large?
- A rich operator set, as in languages like APL and Perl?
- Rich type/object structures supporting inheritance, composition and
aggregation?
- Polymorphism, overloading, aliasing?
- Higher order functions?
- Pattern matching?
- Built-in control flow (e.g. unification, backtracking)?
- Facilities for symbolic computation?
- Support for concurrent and distributed programming?
- Designed to make it impossible to making (some) stupid mistakes? Examples:
- Designed to allow quick and incremental compilation?
- If compilation is a fast as you can type, development time and
cost can be greatly reduced
- If compilation can be incremental, there's no need to recompile
after making small changes
- If compilation can be quick, some compilation can be done at
runtime to adapt to changing conditions
- Amenable to efficient target code generation?
- Languages with static scope and type checking keep the runtime
system free from tons of work, e.g. no runtime variable lookup:
all variable references have already been resolved to machine
addresses.
- Languages with no first-class functions allow for stack-allocation
of frames
- Genuinely portable?
- Many languages have too many "implementation dependencies"
Non-Technical Criteria
Good and successful are not the same! Success comes from:
- Being the only language suitable for a specific problem
- Personal preference ("no accounting for taste")
- Good development environments
- Fast compilers (not necessarily a language issue!)
- Patronage (support from a government or big company)
- "Everyone else is using it"
- "The boss made me use it"
- Economics and Inertia — "we already invested too much in this to change"
- Laziness — "I'm too tired to learn a new language"
Exercise: What else can you think of that makes people want to use a particular language?
Understanding Evaluation Tradeoffs
You can't have everything, it seems:
- The expressive power of dynamic typing, polymorphic type systems,
functions as first-class values, higher-order functions, and
closures can sometimes impact performance.
- Automatic garbage collection saves billions of dollars
in programmer time, but isn't always a good idea in embedded,
life-critical, real-time systems.
- Languages that are intentionally designed to be horrible
(Brainfuck, Java2K, Malbolge, etc.) have some intellectual
and educational value (and offer amusement).
Exercise: Think up some other tradeoffs