The two earliest macro systems that were clearly designed to be general purpose languages that I know of are Christopher Strachey's GPM[2] and Calvin Mooers TRAC[3] programming language. These languages appeared at roughly the same time, the mid 1960s. I prefer the syntax of TRAC, but otherwise they are almost isomorphic. TRAC was featured in Computer Lib/Dream Machines[4] by Ted Nelson where the author said it was one of the three important languages for programmers to learn. A good introduction to TRAC and it's implementation can be found in Études for Programmers[5].
Other more contemporary examples of macro programming languages are m4, and TeX. LaTeX is programmed in the TeX macro system.
[1] Daniel Weise and Roger Crew, "Programable Syntax Macros", ACM SIGPLAN, 1993, https://dl.acm.org/doi/pdf/10.1145/173262.155105
[2] Christopher Strachey, “A general purpose macrogenerator,” Computer Journal, 8(3), pp. 225-241, 1965
[3] Calvin Mooers, "TRAC, a procedure-describing language for the reactive typewriter", CACM, Vol 9(3), March 1966, pp. 215-219, https://dl.acm.org/doi/10.1145/365230.365270
[4] Ted Nelson, "Computer Lib/Dream Machines", 1974, Self-published. (There is a 2nd edition from Microsoft Press, but I'm only familiar with the 1st edition).
[5] Charles Wetherell, "Études for Programmers", 1978, Prentice Hall. (It's out of print and available from Amazon for $427. I'm going to have to start locking up my old books.)
Thanks for the tip on Études for Programmers, looks like I'll be able to look at it in a library at least, surprised archive.org didn't have it.
I would maybe add SQL as an ur-language as well. It's not quite general purpose like most of these, but it should have a place in this list, I think. It has some kinship with Prolog and the declarative style, but it's really it's own thing.
You could also maybe argue for something like LabView. Many programmers look down on purely graphical programming languages, but with Houdini, Unreal's Blueprints and the various node-based shader/material systems in gamedev, I think it probably deserves it's own little branch of this family tree.
For the signal transformation ones, there are also the hardware definition languages on the same category as LabView and animation languages.
Programming PLCs sometimes feels like going to, say, Australia or New Zealand, and being immersed in an environment which went down a different evolutionary tree very on in its development.
This is one of those things that seems to keep coming back - recently in the Ruby world with Cucumber.
Learning erlang made me definitely at least 10% smarter as a programmer. Highly recommend, even if you never use it in anger.
(I categorized the temporal declarative language TLA+ into the Prolog family in another comment -- a main distinction here is, though one can express reactive relationships in TLA+, the intent of the language and design of the TLC model checker is that such relationships are only usable for verification code, whereas implementation code must be written as state-succession pairs. A true reactive language permits and encourages both styles of coding for implementation code -- e.g. Verilog's = and <= operators. Vice-versa, a true logic language includes nondeterminism as a core construct, whereas reactive languages typically do not.)
[1] https://en.wikipedia.org/wiki/Synchronous_programming_langua...
IMHO* a distinguishing feature of Algol like languages (aka "procedural" languages) is the distinction between expressions and statements. Though personally I've never seen the appeal, that distinction seems to be popular for some reason.
* this isn't even a quibble -- the article is fine without it. Just something that has always seemed weird to me.
Listing Self rather than Smalltalk as the basis of OO languages is also a bit odd. Calling it a "purer form" I guess is a justification, but the other view is once you losen the definition as above, self is just the root of one small (albeit influential, via Javascript, branch of OO languages that almost all owe more to Smalltalk than Self. If another language than Smalltalk should be at the root, it should be Simula, for inspiring message passing, not Self.
If I were to put Ruby into one of these categories, I would place it first under Self (the object-oriented languages). Ruby is the most object-oriented language that I've ever used in that everything is an object that you send signals to. Even classes in Ruby are objects (they are instances of the `Class` class). Ruby was explicitly inspired by Smalltalk, one of the two exemplars cited by the post.
After the "Self" category, Ruby would fit better under the "Lisp" family than the "ALGOL" family because of Ruby's deep metaprogrammability.
I'm guessing the author was fooled by the availability of C-style `for` loops in Ruby, but that's generally not how Ruby programmers write a loop. It's much more common to write `list_of_things.map {…}` or use any number of other iteration methods available through the `Enumerable` module.
JavaScript to me fits better under the ML (functional languages) family than "ALGOL". The first-class nature of JavaScript functions is the core feature of the language. Of course, if you define "functional languages" by having static type systems this grouping wouldn't work for you. But for me it's all about the functions. You can pass functions around and return them from other functions. You can write utility functions to memoize or otherwise transform functions.
And while not everything in JavaScript is an object the non-object values in JavaScript have "object" versions. JavaScript still has some object-oriented chops. Functions are themselves objects, and while method calls are usually just reading a function off of an object and calling it, you can intervene in the property-reading step to enforce a more "message passing" style.
I'm guessing that most developers will have similar quibbles about the categorization in this article of the languages they are most familiar with. But this is still an interesting frame of reference. And if you only work in languages that fit squarely in the "imperative" category (or write code in an imperative way), I encourage you to explore some of the others.
I second this. I would consider myself an intermediate level programmer and learning Scheme (via the excellent book "Structure and Interpretation of Computer Programs") took my programming to a new level and made me think of programming from a completely different angle.
Algol -> C. Mostly because you can actually do things with C, and yet it remains a fairly small language that's a relatively pure exemplar of the Algol tradition.
Lisp -> Scheme. Also because it's a tiny language that tries to push the fundamentals of the Lisp family (code-as-data, recursion, functional programming, macros) as far as possible.
ML -> Haskell. ML is eager, Haskell is lazy. If you're going to learn about the ML family, you might as well learn the concept of lazyness, which results in a very different style of programming than FP of the Scheme variety (in the Lisp family).
APL -> J. The usage of special symbols is largely irrelevant to the concepts in APL, and it's a barrier to accessibility. You can learn all the important parts of array-oriented programming with J and use actual words to do it.
Self, Forth, and Prolog I would keep as exemplars of their type. I would also add TCL as another ur-language for string-based scripting languages (with Perl, PHP, and SNOBOL as other representatives of the category).
I would say the same about Lisp.
In fact, each list in Lisp is like its own little stack in Forth. Prepending an element to the front of a list is like pushing onto a stack. Separating the first element from the rest of a list is like popping from a stack.
Lists of lists & atoms are like stacks that can contain references to other stacks, as well as atoms.
[1] https://www.softwarepreservation.org/projects/FORTRAN/paper/...
* Shader code: is ostensibly C, but fundamentally different runtime characteristics.
* Dataflow (or Signals/Excel): Topological graph of computation.
* HCL (or Cloudformation/CDK/etc): Connecting execution via a different runtime.
* React Hooks
IDK it just seems like there is a lot.
And then there’s basic…. Maybe that is just pidgin, giving those who could not speak at all some words?
I disagree with this line since Lisp is not really a "language", but a family of them. If we consider Clojure and original Lisp to be the same language, we should also consider that to be true of Algol and Rust.
The Strongtalk technology also came from Self; it was thought that Self would be too hard to make fast, until it wasn't.
As for total beginners, it can be demeaning to explain why asking which language of the ALGOL descendants to learn is a pointless question. For their case, I don't bury the lead: I tell them "They all have the same lineage and are fundamentally similar, so just pick the one you'll learn the most robustly with. Most everything else is learning libraries."
- value semantics with both implicitly-copyable and move-only values
- unboxed generics with type classes/traits/protocols and associated types
- as little syntax and sugar as possible for everything else
With code example:
https://github.com/coq-community/coq-100-theorems/blob/maste...
Whenever I see a taxonomy I itch for some underlying logic that unifies them. If the explanatory scheme is successful then you might actually convert the taxonomy into a tree, where the root is some property that all of them ur-languages share etc.
"" Simula (1967) is generally accepted as being the first language with the primary features of an object-oriented language. It was created for making simulation programs, in which what came to be called objects were the most important information representation.
Also maybe command / shell languages deserve a mention?
;-)
They do not match any of the listed families, do they?