(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!
9. Does your DIY toolkit look like this?
For hammering nails:
For screwing things in:
For cutting wood:
For tightening bolts:
I hope not! That would be silly!
10. Does your programming toolkit look like this?
For domain modeling:
For complex business rules:
For querying data:
For live coding:
Hmmmm...
22. SQL background
• Part of IBM's System R, the first practical
relational database.
• Before SQL: the dark ages of proprietary and
custom database query APIs.
23. Learning from SQL #1:
A consistent model
Everything is a set of relations
24. TABLE Person
| Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
TABLE ParentChild
| Parent | Child |
|---------|---------|
| Diana | Wills |
| Diana | Harry |
| Charles | Wills |
| Charles | Harry |
| Liz | Charles |
25. | Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
SELECT Name FROM Person
The result is another set
of relations
26. | Name | Age |
|---------|-----|
| Liz | 92 |
| Charles | 69 |
| Wills | 35 |
| Harry | 33 |
SELECT * FROM Person WHERE Age > 50
The result is another set
of relations
27. SELECT Parent,Age
FROM Person
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:
28. Learning from SQL #2:
Composability
It's an expression-oriented language
30. And embed it as a subquery
SELECT Child
FROM ParentChild
WHERE Parent IN
(SELECT Name
FROM Person
WHERE Age > 50)
31. And embed *that* as a subquery
SELECT Child as Grandchild
FROM ParentChild
WHERE Parent IN
( SELECT Child
FROM ParentChild
WHERE Parent IN
(SELECT Name
FROM Person
WHERE Age > 50))
33. There's another reason to prefer
expressions over statements…
They eliminate many types of error
34. 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?
35. 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?
36. 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?
37. 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?
38. 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?
39. 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
40. 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
41. 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
42. 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
43. 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;
}
46. 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
47. SELECT * FROM Person WHERE Age > 50
Example of "What" programming
49. 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.
50. What can we learn from SQL?
• Consistent model
– And predictable
• Composable
– Because expression-based
• Declarative interface
– "What", not "how"
• Separation of concerns
– Reinvented as Command-Query Separation
• Interactivity is important
– You can play and experiment
52. Prolog background
• First mainstream logic programming language
– Designed in Marseille, France.
– From "programmation en logique"
• European answer to LISP for AI.
– But now just as esoteric
58. % what is [1] followed by [2,3] ?
append([1], [2,3], X).
X = [1,2,3] % only one answer
% what do you prepend to [2,3] to make [1,2,3]?
append(X, [2,3], [1,2,3]).
X = [1] % only one answer
% how many ways can you make [1,2,3]?
append(X, Y, [1,2,3]).
X = [] Y =[1,2,3] % multiple answers
X = [1] Y =[2,3]
X = [1,2] Y =[3]
X = [1,2,3] Y =[]
Bi-directional unification is awesome
60. What can we learn from Prolog?
• Consistent model (again)
• Declarative (again)
– "What" not "how" in the Sudoku example
• Unification is very cool
– Bi-directional queries
– Ask both "is true?" and "what matches?"
• Interactivity is important (again)
62. ML background
• "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#
63. Learning from ML #1:
A consistent model
Functions are "normal" things
just like ints, strings, bools, etc.
68. let doSomething f x =
let y = f (x + 1)
"hello" + y
Inferred type of doSomething :
f:(int -> string) -> x:int -> string
69. // 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
71. Sensible defaults
• Immutable by default
– Mutable is a special case
• Non-nullable types by default
– Nullable is a special case
• Structural equality by default
– Reference equality is special case
• Everything must be initialized
72. Learning from ML #4:
Algebraic type system
NB: Technically not part of original ML but
now a standard part of "ML family"
73. New types are built from smaller types by:
Composing with “AND”
Composing with “OR”
74. Example: pairs, tuples, records
FruitSalad = One each of and and
Compose with “AND”
type FruitSalad = {
Apple: AppleVariety
Banana: BananaVariety
Cherry: CherryVariety
}
75. Snack = or or
Compose with “OR”
type Snack =
| Apple of AppleVariety
| Banana of BananaVariety
| Cherry of CherryVariety
77. 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
78. type CheckNumber = int
type CardNumber = string
With an algebraic type system you would probably
implement by composing types, like this:
79. type CheckNumber = ...
type CardNumber = …
type CardType = Visa | Mastercard
type CreditCardInfo = {
CardType : CardType
CardNumber : CardNumber
}
80. type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
81. type CheckNumber = ...
type CardNumber = ...
type CardType = ...
type CreditCardInfo = ...
type PaymentMethod =
| Cash
| Check of CheckNumber
| Card of CreditCardInfo
type PaymentAmount = decimal
type Currency = EUR | USD
82. 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 }
83. 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 }
85. 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!
89. What can we learn from ML?
• Consistent model (again)
• Expression-based (again)
– Everything is composable
– Also prevents bugs
• Type inference is awesome
• Sensible defaults make accidents harder
– E.g. immutable by default
• Algebraic types are awesome
92. Is a simulation of a teletype really the best interface
for interacting with an operating system?
-- @gambler on HN, Jan 2019
93. 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.
102. 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!
104. What can we learn from the 1970's?
• Many great ideas were developed 40 years ago
– They should be more widely known
• There are many different approaches to solving
problems.
– A bigger toolbox is a good thing to have
– Use the right tool for the job
105. And one more thing…
C-style syntax is not the only possible syntax!
– No curly braces
– Sentences can end properly, with a period!
– No dot syntax (not even in OO Smalltalk)
106. "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!
107. Slides and video here
fsharpforfunandprofit.com/fourfromforty
Thank you!
"Domain modelling Made Functional" book
fsharpforfunandprofit.com/books
@ScottWlaschin Me on twitter