Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
F# High Performance

You're reading from   F# High Performance Increase your F# programming productivity and focus on performance optimization with best practices, expert techniques, and more

Arrow left icon
Product type Paperback
Published in Jan 2017
Publisher Packt
ISBN-13 9781786468079
Length 338 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Eriawan Kusumawardhono Eriawan Kusumawardhono
Author Profile Icon Eriawan Kusumawardhono
Eriawan Kusumawardhono
Arrow right icon
View More author details
Toc

Table of Contents (9) Chapters Close

Preface 1. Performing Common Optimizations in F# FREE CHAPTER 2. Performance Measurement 3. Optimizing Data Structures 4. Introduction to Concurrency in F# 5. Advanced Concurrency Support in F# 6. Optimizing Type Provider 7. Language Features and Constructs Optimization 8. Optimizing Computation Expressions

Understanding the nature of F# code

Understanding the nature of F# code is very crucial and is a definitive prerequisite before we begin to measure how long it runs and its effectiveness. We can measure a running F# code by running time, but to fully understand why it may run slow or fast, there are some basic concepts we have to consider first.

Before we dive more into this, we must meet the basic requirements and setup.

After the requirements have been set, we need to put in place the environment setting of Visual Studio 2015. We have to set this because we need to maintain the consistency of the default setting of Visual Studio. The setting should be set to General.

These are the steps:

  1. Select the Tools menu from Visual Studio's main menu.
  2. Select Import and Export Settings... and the Import and Export Settings Wizard screen is displayed:

    Understanding the nature of F# code

  3. Select Reset all Settings and then Next to proceed.
  4. Select No, just reset my settings overwriting my current setting and then Next to proceed
  5. Select  General and then click on Finish:

    Understanding the nature of F# code

After setting it up, we will have a consistent layout to be used throughout this book, including the menu locations and the look and feel of Visual Studio.

Now, we are going to scratch the surface of F# runtime with an introductory overview of common F# runtime, which will give us some insights into F# performance.

F# runtime characteristics

The release of Visual Studio 2015 occurred at the same time as the release of .NET 4.6 and the rest of the tools, including the F# compiler. The compiler version of F# in Visual Studio 2015 is F# 4.0.

F# 4.0 has no large differences or notable new features compared to the previous version, F# 3.0 in Visual Studio 2013.

Its runtime characteristic is essentially the same as F# 4.0, although there are some subtle performance improvements and bug fixes.

For more information on what's new in F# 4.0 (described as release notes) visit: 

https://github.com/Microsoft/visualfsharp/blob/fsharp4/CHANGELOG.md

Note

At the time of writing this book, the online and offline MSDN Library of F# in Visual Studio does not have F# 4.0 release notes documentation, but you can always go to the GitHub repository of F# to check the latest update.

These are the common characteristics of F# as part of managed programming language:

  • F# must conform to .NET CLR. This includes the compatibilities, the IL emitted after compilation, and support for .NET BCL (the basic class library). Therefore, F# functions and libraries can be used by other CLR-compliant languages such as C#, VB, and managed C++.
  • The debug symbols (PDB) have the same format and semantics as the other CLR-compliant languages. This is important because F# code must be able to be debugged from other CLR-compliant languages as well.

From the managed languages perspective, measuring the performance of F# is similar when measured by tools such as the CLR profiler. But from an F# unique perspective, the following are the unique characteristics of F#:

  • By default, all types in F# are immutable. Therefore, it's safe to assume it is intrinsically thread safe.
  • F# has a distinctive collection library, and it is immutable by default. It is also safe to assume it is intrinsically thread safe.
  • F# has a strong type inference model, and when a generic type is inferred without any concrete type, it automatically performs generalizations.
  • Default functions in F# are implemented internally by creating an internal class derived from F#'s FSharpFunc. This FSharpFunc is essentially a delegate that is used by F# to apply functional language constructs such as currying and partial application.
  • With tail call recursive optimization in the IL, the F# compiler may emit .tail IL, and then the CLR will recognize this and perform optimization at runtime. More on this in Chapter 7, Language Features and Constructs Optimization.
  • F# has inline functions as options. More on this in Chapter 7, Language Features and Constructs Optimization.
  • F# has a computation workflow that is used to compose functions. This will be described in more detail in Chapter 8, Optimizing Computation Expressions.
  • F# async computation doesn't need Task<T> to implement it.

Note

Although F# async doesn't need the Task<T> object, it can operate well with the async-await model in C# and VB. The async-await model in C# and VB is inspired by F# async, but behaves semantically differently based on more things than just the usage of Task<T>. More on this in Chapter 4, Introduction to Concurrency in F#.

All of those characteristics are not only unique, but they can also have performance implications when used to interoperate with C# and VB.

Relation between F# code and its generated assembly

The F# assembly (commonly known as DLL or executable EXE in .NET running on Windows) is the same as the C#/VB assembly upon compilation. The end product of the compiler is a .NET assembly.

An assembly may contain multiple namespaces, and each namespace may contain multiple files of modules, classes, or a mix of both.

The following table describes the F# relation of code and compiled code (assembly):

F# code

Description

Compiled code

Project

An organization of an F# project. It may contain F# script (FSX) and F# source files (FS).

In the conceptual layout, a project may contain multiple namespaces that spawn across multiple files of FSX and F# script.

An assembly of either executable EXE or DLL class library

Namespace

A logical organization of modules and classes to help organizing within an organization, company, or functionality.

For example: the System.Web namespace that contains many classes related to enable browser/server communication, including HTTP and HTTPS.

A namespace may spawn across different assemblies instead of a namespace for only one assembly

Module

A module in F# is equal to a C# static class or module in VB. An F# FS file may contain multiple modules, although it is not recommended to have this practice.

Part of a generated assembly

Classes and interfaces

A file can contain multiple classes and interfaces under different namespaces. It is recommended to have not more than one namespace for each file as this also minimizes compilation time when it tries to resolve references.

Part of a generated assembly

Immutability versus mutability

F# implementation of types and collection types are immutable. Immutable in this sense means it is read-only, and we can only initialize the object with an initial value and we can't change it afterwards.

Mutability means once we initialize an object, it can be changed afterwards. This is why it is sometimes called a mutating object value instead of a changing object value.

For example consider the following:

let anynumber = 0 

By default, anynumber is immutable and the value of it will always be 0.

To mark a variable as mutable, F# has the mutable keyword and we can use mutable in the let declaration, as in this example:

let mutable anymutablenumber = 0 

However, changing the value requires the use of the <- symbol in F#, for example:

anymutablenumber <- anymutablenumber + 1 

Since the nature of F# is functional, a symbol can be both a data and a function. The content of the symbol is read-only, so does a function in it.

Immutability also has another advantage: it scales well across multiple threads or even in parallel, no matter whether it's a value or a function. The immutability guarantee means that it is free of side effects. It is then safe to spawn multiple symbols in parallel because the result of an execution will be guaranteed to have the same result. This is also simply called thread safe.

The fact that F# has a mixed support for functional and OOP at the same time (including having support for the inherent mutable state of OOP) may lead to bottlenecks as described next.

You have been reading a chapter from
F# High Performance
Published in: Jan 2017
Publisher: Packt
ISBN-13: 9781786468079
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime