f# - why, how, and for what?...• programming language compiling to .net • functional-first, oo...
TRANSCRIPT
![Page 1: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/1.jpg)
F# - why, how, and for what?
Rune Ibsen – SimCorp – 11-12-2018
![Page 2: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/2.jpg)
![Page 3: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/3.jpg)
• Programming language compiling to .NET
• Functional-first, OO second
• Strongly typed
• Source code on GitHub, Don Syme,
Microsoft Research, is BDFL
• Visual Studio, VSCode, Windows, Mac
F#
Story
![Page 4: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/4.jpg)
Micro services
for music
streaming
REST APIs in
ASP.NET, C#
100.000+
simultaneous users
10 services
6 developers
No testers
10.000 unit tests
Continuous
delivery
MålHow we got
started…
Story
![Page 5: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/5.jpg)
• Code must be maintainable and evolvable for 10+
years
• Code must be continuously deployable
• Code must be of high quality
MålGoals
Story
![Page 6: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/6.jpg)
Code
satisfaction
Story
Time
Satisfaction
![Page 7: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/7.jpg)
Primitive
Obsessions
Primitive Obsession is using primitive data types to
represent domain ideas. For example, we use a String to
represent a message, an Integer to represent an amount of
money, or a Struct/Dictionary/Hash to represent a specific
object.
- Ward Cunningham
![Page 8: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/8.jpg)
Primitive
Obsessions
private bool CompleteTransaction(int businessTransactionId,int mongoDbTransactionId,int sqlDbTransactionId, string user)
{//...;
}
![Page 9: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/9.jpg)
public class TransactionId{
public int Value { get; set; }}
Primitive
Obsessions
![Page 10: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/10.jpg)
public class TransactionId{
public TransactionId(int value){
this.Value = value;}
public int Value { get; }}
Primitive
Obsessions
![Page 11: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/11.jpg)
public class TransactionId{
public TransactionId(int value){
this.Value = value;}public int Value { get; }
}
[Fact]public void ComparisonIsSane(){
TransactionId id1 = new TransactionId(123);TransactionId id2 = new TransactionId(123);
Assert.True(t1.Equals(t2)); //FailsAssert.True(t1 == t2); //FailsAssert.True(t1.Value == t2.Value); //Fails
}
Primitive
Obsessions
![Page 12: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/12.jpg)
public class TransactionId{
public TransactionId(int value){
this.Value = value;}
public int Value { get; }
public override bool Equals(object obj){
var other = obj as TransactionId;
if (other == null) { return false; }
return this.Value == other.Value;}
}
Primitive
Obsessions
![Page 13: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/13.jpg)
public class TransactionId{
public TransactionId(int value){
this.Value = value;}public int Value { get; }public override bool Equals(object obj){
var other = obj as TransactionId;if (other == null) { return false; }return this.Value == other.Value;
}
public override int GetHashCode() => this.Value.GetHashCode();public static bool operator ==(TransactionId t1, TransactionId t2) =>
t1.Equals(t2);public static bool operator !=(TransactionId t1, TransactionId t2) =>
!t1.Equals(t2);}
Primitive
Obsessions
![Page 14: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/14.jpg)
C#”C# is a very nice language – it is just that all the defaults
are wrong”
- Don Syme, creator of F#
![Page 15: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/15.jpg)
null
I call it my billion-dollar mistake. [...] But I couldn't resist the
temptation to put in a null reference, simply because it was so
easy to implement. This has led to innumerable errors,
vulnerabilities, and system crashes, which have probably
caused a billion dollars of pain and damage in the last forty
years.
- Tony Hoare
![Page 16: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/16.jpg)
Målnull
• null is the absence of a value
• null is not visible in the type signature
• When is null a valid value?
• Nullable<T> is only for value types
Maybe<T>
![Page 17: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/17.jpg)
null
public struct Maybe<T>{
private readonly T _value;public Maybe(T value){
if(value == null){
HasValue = false;_value = default(T);
}else{
_value = value;HasValue = true;
}}public static Maybe<T> Empty() => new Maybe<T>();public bool HasValue { get; }public T Value =>
HasValue? _value: throw new Exception("Cannot access Value when Maybe is empty.");
}
![Page 18: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/18.jpg)
null
Maybe<TransactionId> ParseTransactionId(string s);Transaction GetTransaction(TransactionId id);
Maybe<TransactionId> transactionId = ParseTransactionId(s);if (transactionId.HasValue){
Transaction transaction = GetTransaction(transactionId.Value);
/* Do stuff with transaction */}
![Page 19: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/19.jpg)
null
public static Maybe<R> Map<T, R>(this Maybe<T> @this, Func<T, R> mapper) =>
@this.HasValue? new Maybe<R>(mapper(@this.Value)): Maybe<R>.Empty();
Maybe<Transaction> transaction = ParseTransactionId(s).Map(id => GetTransaction(id));
![Page 20: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/20.jpg)
null
Maybe<TransactionId> ParseTransactionId(string s);Maybe<Transaction> GetTransaction(TransactionId id);
Maybe<TransactionId> transactionId = ParseTransactionId(s);if (transactionId.HasValue){
Maybe<Transaction> maybeTransaction = GetTransaction(transactionId.Value);if (maybeTransaction.HasValue){
Transaction transaction = maybeTransaction.Value;
/* Do stuff with transaction */}
}
![Page 21: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/21.jpg)
null
Maybe<Maybe<Transaction>> transaction = ParseTransactionId(s).Map(id => GetTransaction(id));
![Page 22: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/22.jpg)
null
public static Maybe<R> Bind<T, R>(this Maybe<T> @this, Func<T, Maybe<R>> binder) =>
@this.HasValue? binder(@this.Value): Maybe<R>.Empty();
Maybe<Transaction> transaction = ParseTransactionId(s).Bind(id => GetTransaction(id));
![Page 23: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/23.jpg)
null
Maybe<Order> order =ParseTransactionId(s).Bind(GetTransaction).Map(transaction => transaction.OrderId).Bind(GetOrder);
![Page 24: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/24.jpg)
null
Maybe<Order> order =from id in ParseTransactionId(s)from transaction in GetTransaction(id)from o in GetOrder(transaction.OrderId)select o;
![Page 25: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/25.jpg)
ResultExceptions are not visible in method signatures
Errors can be genuine business scenarios
Result<TSuccess,TFailure>
![Page 26: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/26.jpg)
Result
public struct Result<TSuccess,TFailure>{
public bool IsSuccessful { get; }
public TSuccess Success =>this.IsSuccessful? _successValue: throw new Exception("Cannot access Success on failed Result.");
public TFailure Failure =>this.IsSuccessful? throw new Exception("Cannot access Failure on successful Result."): _failureValue;
}
Implementation details
![Page 27: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/27.jpg)
Result
Result<Order, string> order =ParseTransactionId(s).Bind(GetTransaction).Map(transaction => transaction.OrderId).Bind(GetOrder);
Result<Order, string> order =from id in ParseTransactionId(s)from transaction in GetTransaction(id)from o in GetOrder(transaction.OrderId)select o;
![Page 28: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/28.jpg)
Code
satisfaction
Time
Satisfaction
![Page 29: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/29.jpg)
Result
![Page 30: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/30.jpg)
Code
satisfaction
Time
Satisfaction
![Page 31: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/31.jpg)
F#
type TransactionId = TransactionId of int
![Page 32: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/32.jpg)
F#
type TransactionId = TransactionId of int
let t1 = TransactionId(123)let t2 = TransactionId(123)
t1 = t2 //true
![Page 33: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/33.jpg)
F#
type TransactionId = TransactionId of inttype OrderId = OrderId of inttype Name = Name of stringtype CardNumber = CardNumber of stringtype Amount = Amount of decimaltype PaymentMethod =
| CreditCard of name : Name * number : CardNumber * expiry : DateTime| DebitCard of name : Name * number : CardNumber * expiry : DateTime| Cash of Amount
type CatalogNumber = CatalogNumber of stringtype ISRC = ISRC of stringtype LMID = LMID of stringtype Product =
| Album of label : string * catalogNumber : CatalogNumber| Track of ISRC| Video of LMID
![Page 34: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/34.jpg)
F#
let processPayment(paymentMethod, product) =match product, paymentMethod with| Album(label, catalogNumber), CreditCard(_)| Album(label, catalogNumber), DebitCard(_) -> Ok (TransactionId 123)| Album(_), Cash(_) -> Error("Cannot pay for an album with cash")| Track(isrc), CreditCard(_, number, _) -> Ok (TransactionId 321)| Track(isrc), DebitCard(_) -> Ok (TransactionId 789)| Track(isrc), Cash(amount) -> Ok (TransactionId 987)
Incomplete pattern matches on this expression.
For example, the value '(Video(_),_)' may indicate a case not covered by the pattern(s)
![Page 35: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/35.jpg)
F#
let processPayment(paymentMethod, product) =match product, paymentMethod with| Album(label, catalogNumber), CreditCard(_)| Album(label, catalogNumber), DebitCard(_) -> Ok (TransactionId 123)| Album(_), Cash(_) -> Error("Cannot pay for an album with cash")| Track(isrc), CreditCard(_, number, _) -> Ok (TransactionId 321)| Track(isrc), DebitCard(_) -> Ok (TransactionId 789)| Track(isrc), Cash(amount) -> Ok (TransactionId 987)
let myCreditCard = CreditCard(Name("Rune Ibsen“), CardNumber("12345678"), DateTime(1, 1, 2020))
let backInBlack = Album("Epic", CatalogNumber("5099751076520"))
let result = processPayment(myCreditCard, backInBlack)
let transactionId =match result with| Ok(transactionId) -> transactionId| Error(msg) -> failwith msg
![Page 36: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/36.jpg)
F# / C#
var myCreditCard =PaymentMethod.NewCreditCard(
Name.NewName("Rune Ibsen"),CardNumber.NewCardNumber("12345678"),new DateTime(1, 1, 2020));
var backInBlack = Product.NewAlbum("Epic", CatalogNumber.NewCatalogNumber("5099751076520"));
var result = processPayment(myCreditCard, backInBlack);
if (result.IsOk){
int transactionId = result.ResultValue.Item;/* Do stuff */
}else{
throw new Exception(result.ErrorValue);}
![Page 37: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/37.jpg)
F#
type Maybe<'T> = | Some of 'T| None
val parseTransactionId : string -> Maybe<TransactionId>val getTransaction : TransactionId -> Maybe<Transaction>val getOrder : OrderId -> Maybe<Order>
let tryGetOrder (s : string) : Maybe<Order> =maybe {
let! transactionId = parseTransactionId(s)let! transaction = getTransaction(transactionId)let orderId = transaction.OrderIdlet! order = getOrder(orderId)return order
}
![Page 38: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/38.jpg)
F#
type Result<'TSuccess, 'TFailure> = | Success of 'TSuccess| Failure of 'TFailure
val parseTransactionId : string -> Result<TransactionId, string>val getTransaction : TransactionId -> Result<Transaction, string>val getOrder : OrderId -> Result<Order, string>
let tryGetOrder (s : string) : Result<Order, string> =result {
let! transactionId = parseTransactionId(s)let! transaction = getTransaction(transactionId)let orderId = transaction.OrderIdlet! order = getOrder(orderId)return order
}
![Page 39: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/39.jpg)
F#
val parseTransactionId : string -> Async<Result<TransactionId, string>>val getTransaction : TransactionId -> Async<Result<Transaction, string>>val getOrder : OrderId -> Async<Result<Order, string>>
let tryGetOrder (s : string) : Async<Result<Order, string>> =asyncResult {
let! transactionId = parseTransactionId(s)let! transaction = getTransaction(transactionId)let orderId = transaction.OrderIdlet! order = getOrder(orderId)return order
}
![Page 40: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/40.jpg)
Code
satisfaction
Time
Satisfaction
![Page 41: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/41.jpg)
Getting
started
• Continuous transition from C# to F#
• Start with one F# project in a larger solution
• Critical mass of enthusiastic developers
• Peer review proces
![Page 42: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/42.jpg)
Conclusion”C# is a very nice language – it is just that all the defaults
are wrong”
- Don Syme, creator of F#
![Page 43: F# - why, how, and for what?...• Programming language compiling to .NET • Functional-first, OO second • Strongly typed • Source code on GitHub, Don Syme, Microsoft Research,](https://reader035.vdocuments.us/reader035/viewer/2022062610/61151fcfe28f1069ff6ae824/html5/thumbnails/43.jpg)
Thank you
• F# can be adopted gradually
• F# is well suited for modelling
• F# makes certain prevalent concepts explicit
• Make the world a better place
• copenhagensoftware.com/simcorp@cphsoft