First concepts
Expression vs Statement
A statement will produce a side effect. An expression will produce a value... and a possible side effect (that we should avoid).
F♯ is a functional, expression-based language only.
In comparison, C♯ is an imperative language, based on statements, but includes more and more syntactic sugar based on expressions:
Ternary operator
b ? x : yNull-coalescing operator
??in C♯ 8 :label ?? "(Empty)"Expression-bodied members in C♯ 6 and 7
switchexpression in C♯ 8
⚖️ Benefits of expressions over instructions
Conciseness: less visual clutters → more readable
Composability: composing expressions is like composing values
Understanding: no need to know the previous instructions to understand the current one
Testability: pure expressions are easier to test
Predictable: same inputs mean same outputs
Isolated: shorter Arrange/Setup phase in tests, no need for mocks
Everything is an expression
A function is declared and behaves like a value
We can pass it as parameter or return it from another function (1)
The control flow building blocks are also expressions
if … then/else,match … withfor … in,for … to,while … dojust return "nothing" (2)
Consequences
No
void→ Best replaced by theunittype 📍No Early Exit
In C#, you can exit a function with
returnand exit afor/whileloop withbreak.In F♯ these keywords do not exist.
Early exit alternatives
The most questionable solution is to raise an exception 💩 (see StackOverflow)
One solution in imperative style is to use mutable variables 😕
The most recommended and idiomatic solution in functional programming is to use a recursive function 📍
Typing, inference and ceremony
The ceremony is correlated to the typing weakness
JS
Low (dynamic typing)
×
Low
C♯
Medium (static nominal)
Low
High
TS
Strong (static structural + ADT)
Medium
Medium
F♯
Strong (static nominal + ADT)
High
Low
🔗 Zone of Ceremony by Mark Seemann
Type inference
Goal: write type annotations as little as possible
Less code to write 👍
Compiler ensures consistency
IntelliSense helps with coding and reading
Type inference in C♯
Method parameters and return value ❌
Variable declaration:
var o = new { Name = "John" }✔️Lambda as argument:
list.Find(i => i == 5)✔️Lambda declaration:
var f3 = () => 1;✔️ in C# 10 (limited)Array initialisation:
var a = new[] { 1, 2 };✔️Generic classes:
constructor:
new Tuple<int, string>(1, "a")❌static helper class:
Tuple.Create(1, "a")✔️
C♯ 9 target-typed expression
StringBuilder sb = new();✔️
Type inference in F♯
Hindley–Milner method
Able to deduce the type of variables, expressions and functions in a program without any type annotation
Based on both the implementation and the usage
Example:
Automatic generalization in F♯ inference
If something can be inferred as generic, it will be → Open to more cases 🥳
Inference vs type annotation
Pros:
code terser
automatic generalization
Cons:
we can break code in cascade
inference limited:
an object type cannot be determine by the call to one of its members (1) → exception: Record types 📍
sensible to the order of declaration (2)
(1) Example:
(2) Example:
Last updated
Was this helpful?