Tuesday, March 31, 2020

Learning F# - Step 4 Revisited

I know I should be writing about using F# to connect to a database, but I had to come back to working with files. (Learning the database interaction is taking me longer, and I'll explain why in that post.)

I had an opportunity to use F# at work to essentially "fold" a file at a certain number of characters. (This is a built-in function of *nix OSes, but I was on a Windows box and didn't have my normal set of tooling due to the quarantine.) I needed to read in a file as a string and break it into lines every 170 characters. The mechanism I posted earlier for reading files worked, but it wasn't doing exactly what I needed.

To suit my need, I found the ReadAllText method on the File object in the System.IO package. Below is the code that I put together:

open System.IO

let fileName = fsi.CommandLineArgs.[1]

let fileContents = File.ReadAllText(fileName)

let newString = ""
for i in 1..(fileContents.Length) do
    if i % 170 <> 0 then fileContents.[i-1].ToString()
    else fileContents.[i-1].ToString() + "\n"
    |> printf "%s"
Most of this should look familiar to the code I had in my last post. One big difference is that I actually wrote this as an F# script file (fsx) instead of a straight F# "program." This is why you don't see any actual function definitions in the code. Not being a "real" F# program, the command-line argument handling is different too (fsi.CommandLineArgs). I'll save those items for another post.

The main difference I want to point out is the file operation. In the code above, I read the entire contents of my file into fileContents using the File.ReadAllText method. This change allowed me to work on the contents of the file as a string. That "work" is to iterate over the characters in the file and insert a newline character after every 170 characters.

The fact that I used a FOR loop to do the iteration points to the fact that I have a LOT of learning to do in the functional programming world.

Saturday, March 28, 2020

Learning F# - Step 4

In this next step of learning F#, I want to interact with the file system. Once I can read and write files, I can use a programming language for day-to-day scripting needs, which helps me get more comfortable with the language's features.

Fortunately, F# uses the .NET System.IO library for interacting with files. This fact makes it easy to translate how to work with files in C# to F#. The first thing to do is to "open" the System.IO package in your file:

open System.IO
Now that you have the library available, you can work with files.

Let's start by reading a file. The following code reads a file line by line into a sequence of lines:

let readLinesFromFile fileName =
    seq { use reader = File.OpenText fileName
        while not reader.EndOfStream
            do yield reader.ReadLine() }
This code block reads lines from file fileName and puts them into a sequence. A sequence in F# is a logical series of elements all of one type. Since the last line of an F# function is the return value, the sequence is returned from this function.

To write strings to a file as separate lines, you would use code like:

let WriteLines fileName (lines: string seq) =
    use writer = File.CreateText fileName
    for line in lines
        do writer.WriteLine line
This function takes a fileName and a sequence of lines and writes them into a file. (The parameter for the sequence of lines is contained in parentheses because the code is assigning a type of sequence of strings to the parameter lines. If this wasn't in parentheses, each word would be considered a parameter of the function.)

This is all great, but not very useful. To make sure I know how to employ file IO for a useful purpose, I created a little program to read the lines from a file, find all the lines that contain a word, and print them to the console output. Below is the program I created:

open System.IO

let readLinesFromFile filename =
    seq { use reader = File.OpenText filename
          while not reader.EndOfStream
              do yield reader.ReadLine () }

let CheckPhrase (x: string) =
    x.Contains("test")
    
[<EntryPoint>]
let firstMain argv =
    let fileLines = readLinesFromFile "testfile.txt"
    
    fileLines
        |> Seq.filter CheckPhrase
        |> printfn "Line with test -> %A"

    0

This program utilizes the functions I described above, plus one additional function. The additional function, CheckPhrase, takes a string parameter and returns true or false depending on when the input string contains the word "test." The other tidbit that is different, is the use of the Seq.filter function and the |> operator. The Seq.filter function creates a new sequence by passing one sequence (fileLines) through a "filter" function, in this case CheckPhrase. The the Seq.filter function adds an item from the first sequence into the new sequence if the passed in predicate returns true, otherwise it skips the element.

The other new piece of syntax is the pipe operator: |>. This operator "pipes" the output of the expression on the left to the expression on the right. In my program above, I am piping the fileLines variable into the Seq.filter CheckPhrase expression, whose result is piped into the printfn function.

Learning how to work with files in a new programming language is a way to gain practical experience with a new language. It also tends to expose new constructs or paradigms of the language to learn.

Wednesday, March 25, 2020

Learning F# - Step 3

This next step for me is an important one. Unit testing. I use unit testing, especially test driven development, a lot. For me TDD is a design tool that helps me design good code. Unit tests provide an awful lot of feedback about code that helps a developer learn, grow, and get better. (I'll try to create a separate post about the benefits of unit testing.)

All that being said, I like to know how to approach unit testing in a new language. Many people like to go after language constructs and idiomatic patterns first. These are important, but I like knowing how to test my code first. I won't always write unit tests as I'm learning and exploring, but understanding the approach to testing in a new language uncovers a LOT about the language itself.

F# makes unit testing easy, for a C# developer. F# supports NUnit and xUnit. I've been using xUnit for most of my C# projects, so I decided to try xUnit with F#.

To get started, I created a unit test project in F# using the following call in the .NET CLI:

dotnet new xunit --language f#
This call created a unit test project with the xUnit reference baked in. I then modified the Tests.fs file to be the following:
module Testing

open System
open Xunit

let AddOne x =
    x + 1

[<Fact>]
let TestAddOne () =
    let result = AddOne 5
    Assert.Equal(result, 6)

I immediately see some things that are familiar, and some things that are new. The module definition seems very much like the namespace structure from C#. Turns out, it is very similar. The module keyword packages the code that follows (because F# uses indentation and spacing instead of curly braces to separate code) into a coherent unit, just like the namespace keyword does in C#. The open System and open Xunit lines also look like import statements in C#. These are just like import statements from C#! The other familiar elements are the [<Fact>] attribute and the Assert.Equal() call. These are familiar elements of XUnit and work as expected.

To exercise my test, I created a function, AddOne, that takes a parameter and adds 1 to it. My test calls AddOne and captures the return value in the variable result. I then assert that my result is what I expect it to be. When I run the command:

dotnet test
I see that my unit test passes!

If you are following along at home, you've noticed that the default contents of the Tests.fs file is different from mine. It is useful to look at it as well. The default file contains a sample unit test with a strange name. The name is contained within a set of ``. This construct turns the contents contained within the `` set into an identifier that would not normally be a legal identifier. This "trick" allows one to create names in F# that can be used as a Domain Specific Language (DSL) or to create more readable output. That's a handy feature when doing a lot of unit testing!

Now that I have created my Hello World program, understand the build and project structure, and can create some basic unit tests, I'm itching to do something real with the language. That's next!

Monday, March 23, 2020

Learning F# - Step 2

My second step in learning a new programming language is understanding the build system for the project: how to get an actual working program from my code.

My approach to this step for F# in particular is interesting. It isn't interesting because I don't understand it. It is interesting because I have an emotional reaction to it. I'll explain that later.

The fundamental component of the F# build system is the FSPROJ file. This is automatically created when you use the CLI to create a new project. An FSPROJ file is just an XML file telling the .NET SDK which SDK to use, which files to compile, and what other packages are needed for this project to build correctly. Below is the default FSPROJ file from the default Hello World project:

<project sdk="Microsoft.NET.Sdk">

  <propertygroup>
    <outputtype>Exe</outputtype>
    <targetframework>netcoreapp3.1</targetframework>
  </propertygroup>

  <itemgroup>
    <compile include="Program.fs">
  </compile></itemgroup>

</project>

The first thing to know about F# project files is that they are part of MSBuild. MSBuild is the build utility that is used for C# and F# projects in the .NET space. To really dig into the project file, one needs to fully understand MSBuild. This post will not cover MSBuild.

The basics of the FSPROJ file are pretty easy to understand. The very first line specifies the SDK that should be used when building this project. The default entry will use the "default" SDK that you have specified on your workstation. (For the purposes of getting introduced to the language, this is fine.) Next up in the file you have the <PropertyGroup> tag. This grouping of elements tells the SDK what type of output to create (i.e. an executable, class library, etc.) along with the version of the framework to target. (If you are familiar with C# projects, you realize that there are many other options for this grouping. For the purposes of starting with F#, this is sufficient.) The last grouping is the <ItemGroup> section. This section lists the files that are included in this particular project.

I noticed that the FSPROJ file differs from the C# CSPROJ file in that the F# file lists the code files that are included in the project, where a CSPROJ does not. It turns out there are some peculiarities with having multiple F# code files in a project. I have not yet gotten that aspect figured out, so I will plan on an additional post once I understand that better.

The other oddity that I've noticed is that the only difference that I can see on the surface between an FSPROJ file and a CSPROJ file are the names (although the paragraph above points to another difference). I'm not sure why the two languages have differently named project files that come from the same build system. A quick internet search didn't reveal an obvious answer, so I'm still trying to figure that out.

And here begins my emotional reaction. <rant>The following paragraph is a mini-rant. Feel free to skip to the end.</rant> I am still getting over the removal of project.json from .NET Core! I completely understand why they did it, but I don't like, and I don't think I agree with it. Had they left project.json, it could have been a universal project file for both C# and F#. How cool would that be?!? Ok. I'm done.

For a basic application, the default project file works well. Most of the interaction I'm going to have with it is through the CLI tools for building, running, and adding references to my projects. This cursory understanding is enough to dive into the other areas of learning, but I know where to look if I need to do something more sophisticated.

Saturday, March 21, 2020

Learning F# - Step 1

With COVID-19 forcing everyone inside and cancelling events, I suddenly find myself with a lot of extra time. For the first few days, I just enjoyed having my weeknights free. Now, I want to use that time to learn something new. There are several things that I may bite off, but I've decided to start by learning F#.

F# is the functional programming language created by Microsoft. I was surprised to find out that it is baked into the .NET SDK that you download to create .NET Core applications! That fact is what prompted me to learn F#.

To get started with F#, you need to download the latest .NET Core SDK. Once you have .NET Core installed, you can get started!

Before I dive in, I wanted to share a little bit about how I approach learning a new programming language. I like to learn technology by doing things. With programming, I like to write code that solves problems. Quite often they are problems that I've solved over and over again, but they are still problems. When I approach a programming language, I want to do the following things:

  1. Create a Hello World program.
  2. Understand how projects are set up in the language.
  3. Learn unit testing in the language.
  4. Learn to work with the file system in the language.
  5. Learn to work with a database in the language.
  6. Learn to make web API calls in the language.
  7. Start learning the "particulars" of the language.
Using this approach allows me to start using the new programming language for real-life tasks, which helps my brain learn better.

Now that we know what language we are going to learn and how we are going to learn it, let's get started!

I have the latest .NET Core SDK installed on my box. To create the "Hello World" program, create a directory named FSharpHelloWorld. Change directory into FSharpHelloWorld, then all I have to do is:

dotnet new console --language f#
This simple command-line call creates a basic F# program that prints "Hello World" to the screen. Unfortunately, Microsoft created the Hello World program for me. In the directory, you should see the following 3 files listed:
obj
FSharpHelloWorld.fsproj
Program.fs
The FSharpHelloWorld.fsproj file is the "project" file that tells the SDK what to build and how to build it. (I'll dive into this file more in my next post.) The obj directory holds build artifacts. The Program.fs file is the code file that will get compiled and run. Inside the Program.fs file, you should see:
// Learn more about F# at http://fsharp.org

open System

[<EntryPoint>]
let main argv =
    printfn "Hello World from F#!"
    0 // return an integer exit code
The words "main" and "argv" look familiar to me as a C# developer, but the rest is a little foreign. I assume the "printfn" is something like a Console.WriteLine statement. The comments give me hints about the other line of the program. Since I have to feel like I've written code, I modify the text after "printfn" to read "Hola Mundo!" Next, I run the program by issuing the following command in my folder:
dotnet run
Lo and behold, I see
Hola Mundo!
printed on the screen!

So, what did I really accomplish? First, I was able to set up the basic SDK and get a simple environment up and running. Second, I was able to generate a simple program and make it run. Third, I was able to modify the program and have it run without compilation or runtime errors. I would say I have accomplished a lot!

Future posts will track my progress learning F#!