Functional Programming in F# für .NET – Kursinhalte

Die Kurs Inhalte können variieren, je nach Wissensstand, Zeitrahmen und Trainingsschwerpunkten.
Es wird Wert gelegt auf die Grundlagen und dass man das Gelernte sofort anwenden kann.

Sofort Produktiv

  • einfache und mächtige F# Syntax, wenig Code, einfaches Refactoring
  • Code ausführen während man ihn schreibt
  • effiziente und gut verständliche Datenmodellierung (Domain Driven Design (DDD)) mit Algebraischen Daten Typen die automatisch Strukturellen Vergleich und Hashing bieten.
  • Masseinheiten werden vom Compiler bei Übergabe und Berechnungen auf Korrektheit geprüft (Meter, Kilogramm, Sekunde, Pixel, Dollar, SelbstDefiniert, etc.)
  • mit F# Type Providern Ihre Daten automatisch typisiert im Code mit IntelliSense anwenden. Type Provider sind ein einzigartiges Feature von F# (seit 2010, ich konnte es kaum glauben als ich es das erste mal 2010 gesehen habe, It’s magic!), das keine andere Programmiersprache bisher ermöglicht (mit Ausnahme von IDRIS seit März 2015).
  • Erstellen von eigenen Domain Specific Languages (DSL)
  • F# ist in Visual Studio (seit 2010) schon enthalten
  • Kompatibilität, .dll’s können von C#, VB.NET und umgekehrt verwendet werden.

Wichtige Grundlagen der Funktionalen Programmierung (FP)

  • Immutability: verstehen warum Immutability gut ist und hilft Probleme einfacher zu lösen und Code besser zu verstehen. Immutable Daten Strukturen
  • Type Inference : verstehen und Nutzen erkennen
  • Partial Application und Curring
  • Rekursion: rekursive Funktionen und rekursive Datentypen
  • Higher Order Functions : map, reduce, filter, etc.
  • Pattern Matching
  • Referential Transparency
  • Lazyness: Seq, lazy
  • Memoziation
  • Algebraischen Daten Typen (ADT) (sind keine POCOs (Plain-Old CLR Objects))

Wesentliche Unterschiede von F# zu C#

  • null als ungültiger Wert (nicht als gültiger default Wert von Referenz Typen in C#)
  • unit als leerer Wert (nicht void als kein Wert wie in C#, denn void und async vertragen sich nicht gut in C#)
  • async als Library (nicht als async und await Sprachkonstrukte wie in C#)
  • lock als Funktion (nicht als Statement wie in C#)
  • choice für Exception Handling (Exception free programming)

Automatisiertes Testen

  • interaktives Testen im REPL
  • automatisches Erzeugen von Testdaten und Ermittlung des kleinsten Datensatzes, der die Fehler-Analyse vereinfacht mit FsCheck
  • Testen von Webseiten mit Canopy (Automatisiertes Surfen)

Parallel Programming und Asynchronous Programming (Concurrent Programming)

  • Parallelen Code schreiben, dem man trauen kann (immer richtiges Ergebnis)
  • Async Code composition
  • Actors (F# MailboxProcessor)

Web Programmierung (wird im Grundkurs nur gestreift)

  • F# Code zu JavaScript compilieren (mit FunScript oder WebSharper)
  • Client- und Server-Code in F# schreiben (Code Reuse) und automatisch zu .NET für Server und JavaScript für Client compilieren (mit WebSharper)
  • IntelliSense in F# für JavaScript Library Funktionen dank automatischer TypeScript Definitions File Auswertung.


Zu F# Inhouse Schulungskurse

Der HeartBleed Software Fehler

Und wieder ist, heute am 8 April 2014, ein kapitaler Software Fehler publik geworden. Mich interessiert, wie es zu solchen Fehlern kommt, warum sie so lange nicht erkannt wurden, wie sie zu erkennen sind und am aller wichtigsten, wie man solche Fehler vermeiden kann. Hier kann man übrigens testen ob ein Server von HeartBleed betroffen ist http://filippo.io/Heartbleed/.

Analyse des HeartBleed Bugs

Die beste bisher aufgetauchte Beschreibung des Fehlers habe ich hier gefunden https://news.ycombinator.com/item?id=7549943 von drv und darin die interessanten Stellen fett markiert : TLS heartbeat consists of a request packet including a payload; the other side reads and sends a response containing the same payload (plus some other padding). In the code that handles TLS heartbeat requests, the payload size is read from the packet controlled by the attacker:
1: 
2: 
n2s(p, payload);
pl = p;
Here, p is a pointer to the request packet, and payload is the expected length of the payload (read as a 16-bit short integer: this is the origin of the 64K limit per request). pl is the pointer to the actual payload in the request packet. Then the response packet is constructed:
1: 
2: 
3: 
4: 
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
s2n(payload, bp);
memcpy(bp, pl, payload);
The payload length is stored into the destination packet, and then the payload is copied from the source packet pl to the destination packet bp. The bug is that the payload length is never actually checked against the size of the request packet. Therefore, the memcpy() can read arbitrary data beyond the storage location of the request by sending an arbitrary payload length (up to 64K) and an undersized payload. I find it hard to believe that the OpenSSL code does not have any better abstraction for handling streams of bytes; if the packets were represented as a (pointer, length) pair with simple wrapper functions to copy from one stream to another, this bug could have been avoided. C makes this sort of bug easy to write, but careful API design would make it much harder to do by accident.

Vorkehrung

Die genannte Vorkehrung wäre eine einfache Datenstruktur, ein Tupel (pointer, length), um die zusammengehörenden Daten zu vereinen, damit es nicht zu Verwechslungen kommen kann. In F# Syntax sähe das so aus
1: 
let buffer = (pointer, length)
oder man erzeugt einen Record
1: 
type Buffer = { pointer : int64;  length : int64 }
Ja aber wenn wir schon bei Verwechslungen sind, wie vermeidet man hier dass die length und pointer nicht aus versehen vertauscht zugewiesen werden?
1: 
2: 
let buffer = { l; p }   // Vertauscht! Compiler reklamiert nicht :-(
let buffer = { p; l }   // pointer, length  
Eine Verwechslung der Parameter kann der Compiler so nicht erkennen, es sind ja in diesem Beispiel beides long ! Was kann man dagegen tun? F# hat dazu die sogenannten Units of Measures, also Maßeinheiten, wie Kilogramm und Meter, die ganzen SI-Einheiten sind schon vordefiniert, das nur am Rande, denn wir brauchen hier was anderes. Wie wäre es mit den Einheiten Pointer und Length ? Diese kann man sich wie folgt definieren
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
// Units of Measures
type [<Measure>] Pointer
type [<Measure>] Length

// Record Type
type Buffer = 
    { pointer : int64<Pointer>
      length  : int64<Length> }

let p = 123456L<Pointer>
let l =    512L<Length>

let buf  = { pointer = p;  length = l }
//    val buf : Buffer = {pointer = 123456L;
//                        length = 512L;}

// Verwechslung bei der Zuweisung
let buf  = { pointer = l;  length = p }
//    error FS0001: Type mismatch. Expecting a
//        int64<Pointer>    
//    but given a
//        int64<Length>    
//    The unit of measure 'Pointer' does not match the unit of measure 'Length'
Als Kommentar sind die Compiler Meldungen angehängt, dort ist schön zu sehen wie F# reklamiert, dass dem Pointer keine Length zugewiesen werden kann.

Noch mehr Bugs?

Interessant ist auch, dass genau da wo der HeartBleed Bug die Ursache hat, schon einmal etwas gefixt wurde am 27 Feb 2012,
“This patch fixes two padding related bugs for the Heartbeat Response messages. For DTLS, the wrong pointer was used, which may overwrite the payload with the random padding. For TLS, there was no random padding at all.” http://marc.info/?l=openssl-dev&m=133035562503173
Das gibt der alten ungeschriebenen Regel wiedereinmal mehr recht:
Da wo ein Bug ist, sind noch mehr.

Fazit

Wichtig war es mir hier anhand aktueller echter Probleme aufzuzeigen, wie man dies elegant und besser lösen kann. Und mit dem Potential das F# mitbringt ist es bestens geeignet um komplexe Probleme einfach und korrekt zu lösen. Man denke dabei auch daran, wie viele Unit-Tests man einsparen kann, wenn der Compiler so strikt prüfen kann.
Multiple items val int64 : value:’T -> int64 (requires member op_Explicit)Full name: Microsoft.FSharp.Core.Operators.int64——————– type int64 = System.Int64Full name: Microsoft.FSharp.Core.int64——————– type int64<‘Measure> = int64 Full name: Microsoft.FSharp.Core.int64<_>
Multiple items type MeasureAttribute = inherit Attribute new : unit -> MeasureAttributeFull name: Microsoft.FSharp.Core.MeasureAttribute——————– new : unit -> MeasureAttribute