(More info and video at fsharpforfunandprofit.com/fourfromforty)
The 1970's were a golden age for new programming languages, but do they have any relevance to programming today? Can we still learn from them?
In this talk, we'll look at four languages designed over forty years ago -- SQL, Prolog, ML, and Smalltalk -- and discuss their philosophy and approach to programming, which is very different from most popular languages today.
We'll come away with some practical principles that are still very applicable to modern development. And you might discover your new favorite programming paradigm!
3. Four languages from 40 years ago
• A brief history of programming languages
• Hammers and toolkits
• Four (or five) languages:
– SQL (1974)
– Prolog (1972)
– ML (1973)
– Smalltalk (1976,1980)
– Language X (1979)
^or five
41. SQL Background
• Originally "SEQUEL" (Structured English
Query Language)
• Designed as part of IBM's System R, the first
practical relational database.
• Before SQL: the dark ages of proprietary and
custom database query APIs.
42. Learning from SQL #1:
A consistent model:
everything is a set of relations
43. TABLE PersonAge
| Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
TABLE ParentChild
| Parent | Child |
|---------|---------|
| Diana | Wills |
| Diana | Harry |
| Charles | Wills |
| Charles | Harry |
| Liz | Charles |
44. | Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
SELECT Name FROM PersonAge
The result is another set
of relations
45. | Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
SELECT * FROM PersonAge WHERE Age > 50
The result is another set
of relations
46. SELECT Parent,Age
FROM PersonAge
OUTER JOIN ParentChild
WHERE Parent = Person
"Set operations, huh?
I bet there's a way to do
cartesian products then."
Consistency => Predictability
Here you go:
52. void ifThenElseStatement(bool aBool)
{
int result;
if (aBool)
{
result = 42;
}
printfn("result=%i", result);
}
How many things could cause problems in this C-like code?
53. void ifThenElseStatement(bool aBool)
{
int result;
if (aBool)
{
result = 42;
}
printfn("result=%i", result);
}
How many things could cause problems in this C-like code?
54. void ifThenElseStatement(bool aBool)
{
int result;
if (aBool)
{
result = 42;
}
printfn("result=%i", result);
}
How many things could cause problems in this C-like code?
55. void ifThenElseStatement(bool aBool)
{
int result;
if (aBool)
{
result = 42;
}
printfn("result=%i", result);
}
How many things could cause problems in this C-like code?
56. void ifThenElseStatement(bool aBool)
{
int result;
if (aBool)
{
result = 42;
}
printfn("result=%i", result);
}
How many things could cause problems in this C-like code?
57. public void IfThenElseExpression(bool aBool)
{
int result = aBool ? 42 : 0;
Console.WriteLine("result={0}", result);
}
The same C-like code written in an expression-oriented way
58. public void IfThenElseExpression(bool aBool)
{
int result = aBool ? 42 : 0;
Console.WriteLine("result={0}", result);
}
The same C-like code written in an expression-oriented way
59. public void IfThenElseExpression(bool aBool)
{
int result = aBool ? 42 : 0;
Console.WriteLine("result={0}", result);
}
The same C-like code written in an expression-oriented way
60. public void IfThenElseExpression(bool aBool)
{
int result = aBool ? 42 : 0;
Console.WriteLine("result={0}", result);
}
The same C-like code written in an expression-oriented way
61. public void IfThenElseExpression(bool aBool)
{
int result = aBool ? 42 : 0;
Console.WriteLine("result={0}", result);
}
The same C-like code written in an expression-oriented way
int StandaloneSubexpression(bool aBool)
{
return aBool ? 42 : 0;
}
64. FILE *stream;
char *line = NULL;
size_t len = 0;
ssize_t nread;
stream = fopen(argv[1], "r");
while ((nread = getline(&line, &len, stream)) != -1) {
/* check what the age is */
if age > 50
fwrite(line, nread, 1, stdout);
}
free(line);
fclose(stream);
Example of "How" programming
65. SELECT * FROM PersonAge WHERE Age > 50
Example of "What" programming
67. SQL: Separation of concerns
• It's a QUERY language, doh!
– A Data Query Language
• Insert/Update/Delete is a different language
– A Data Manipulation Language
• Defining tables etc. is a different language again
– A Data Definition Language
• "SQL" now means all of these together.
68. What can we learn from SQL?
• Be predictable
– use a consistent model
• Expression-based
– means code is composable
• Declarative interface
– Focus on exposing the what not the how
• Separation of concerns
• Interactivity is important
– You can play and experiment
70. Prolog Background
• First mainstream logic programming language
• Designed in Marseille, France.
• From "programmation en logique"
• European answer to LISP for AI
• Big in Japan ("Fifth generation" project)
76. Q: "Would this make a good query
language as an alternative to SQL?"
A: "Yes, it exists and is called Datalog"
77. Get the names and addresses of employees who work for
at least one project located in Houston but whose
department does not have a location in Houston.
worksOnHoustonProj(Manager) :-
works_on(Manager,Proj,_),
project(_,Proj,'Houston',_).
notInHouston(Manager) :-
employee(_,_,_,Manager,_,_,_,_,_,Dept),
not dept_locations(Dept,'Houston').
answer(First,Middle,Last,Addr) :-
employee(First,Middle,Last,Mgr,_,Addr,_,_,_,_),
worksOnHoustonProj(Mgr), notInHouston(Mgr).
Datalog example
78. append([1], [2,3], X).
X = [1,2,3]
append(X, [2,3], [1,2,3]).
X = [1]
append(X, Y, [1,2,3]).
X = [] Y =[1,2,3]
X = [1] Y =[2,3]
X = [1,2] Y =[3]
X = [1,2,3] Y =[]
Bi-directional unification is awesome
80. What can we learn from Prolog?
• Be consistent and predictable (again)
• Declarative (again)
• Unification is very cool
– Bi-directional queries
– Ask both "is true?" and "what matches?"
• Interactivity is important (again)
82. ML
• "ML" for "Meta Language"
– Designed as part of a theorem-proving system
– Not to be confused with Machine Learning.
• An impure functional language
– Parent of Standard ML, OCaml, F#
87. let doSomething f x =
let y = f (x + 1)
"hello" + y
Inferred type of doSomething :
f:(int -> string) -> x:int -> string
88. // C# code
public IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
IEnumerable<TSource> source,
Func<TSource, TKey> keySelector
)
{
...
}
// F# code
let GroupBy source keySelector =
...
Benefits of type inference:
* Less typing
* Less noise, more logic
Here's a more complex example
90. Different defaults
• Immutable by default
– Mutable is a special case
• Non-null types by default
– Nullable is a special case
• Structural equality by default
– Reference equality is special case
• Everything must be initialized
92. New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
93. Example: pairs, tuples, records
FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
94. Snack = or or
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
96. Some requirements:
We accept three forms of payment:
Cash, Check, or Card.
For Cash we don't need any extra information
For Checks we need a check number
For Cards we need a card type and card number
97. type CheckNumber = int
type CardNumber = string
With an algebraic type system you would probably
implement by composing types, like this:
98. type CheckNumber = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
99. type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
100. type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
101. type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
type Payment = {
Amount : PaymentAmount
Currency : Currency
Method : PaymentMethod }
103. type Deal = Deck -> (Deck * Card)
type PickupCard = (Hand * Card) -> Hand
type Suit = Club | Diamond | Spade | Heart
type Rank = Two | Three | Four | Five | Six | Seven | Eight
| Nine | Ten | Jack | Queen | King | Ace
type Card = { Suit:Suit; Rank:Rank }
type Hand = Card list
type Deck = Card list
type Player = {Name:string; Hand:Hand}
type Game = { Deck:Deck; Players:Player list }
The domain on one screen!
104. type CardType = Visa | Mastercard
type CardNumber = string
type CheckNumber = int
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
105. A big topic and not enough time
More on DDD and designing with types at
fsharpforfunandprofit.com/ddd
107. What can we learn from ML?
• Expression-based (again)
• Type inference is awesome
– Makes adding complicated parameters easy
• Make bad things harder
– E.g. immutable by default
• Parametric polymorphism (aka generics)
• Algebraic types are awesome
110. Smalltalk Background
• Developed at Xerox PARC
– Along with the first PC, the first GUI, the first
laser printer, ethernet, and more.
• Smalltalk introduced
– Message-based OO
– Model-View-Controller
– A windowing IDE
– Also had aVM, generational GC, etc.
117. What can we learn from Smalltalk?
• A consistent model, again
• Minimize syntax and make the language
powerful
• Be awesome and make people fall in love with
you!
120. Language X (1979)
• In the 1980's people would pay thousands of
dollars just to use this language.
• Its descendants have been at the heart of the
software products that dominate their field.
• Its grandchild is the most popular
programming language in the world.
121.
122. A1 + B2 / 2
Why wasVisiCalc successful?
Like Smalltalk, a consistent model, a highly interactive
environment and a programming language: all fitting
together beautifully.
Like SQL, a domain-specific (expression-based!)
programming language that non-programmers could
understand:
Like ML, lots of expressive power in functions:
SUM(A1..A7)
Like Prolog, programming by filling in slots (aka "cells").
Like Smalltalk, no separate text files!
123. What can we learn fromVisiCalc?
• Programming languages appear in many guises.
• Programming is not just for programmers.
– People want to interact and explore.
– Programming for a specific domain is often more useful
than general purpose programming.
• Use the right tool for the job.
124. Summary
• There are many different approaches to
solving problems.
– A bigger toolbox is a good thing to have
• C-style syntax is not the only possible syntax.
– Sentences can end properly, with a period!
– No curly braces
– No dot syntax (not even Smalltalk)
125. A language that doesn't affect the way you
think about programming, is not worth
knowing – Alan Perlis
So go forth and expand your Galaxy Brain!
126. Slides and video here
fsharpforfunandprofit.com/fourfromforty
Thank you!
"Domain modelling Made Functional" book
fsharpforfunandprofit.com/books
@ScottWlaschin Me on twitter