Computational Expressions, the “standard” methods

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

So in a previous post I looked at my first attempt at creating a computational expression in F#. By anyone’s level this was basic. So I figured it was time to look at all the available “standard” methods available for a computational expression. By “standard” I means those which are implciitly recognized by F# as opposed to creating custom methods.

See Computation Expressions (F#) for more info.

There are plenty of posts on this subject from Microsoft or F# for fun or profit, so why am I writing yet another post – basically just to give my perspective and to help me remember this stuff.

Let’s start with the basics, we have a type SampleBuilder defined as

type SampleBuilder() =
   // our code will be filled is as required 
   // but an example might have just the following
   member this.Bind(m, f) = f m

We shall use the builder thus

let builder = SampleBuilder()

builder {
   // expressions, such as 
   let x = 100
}

and now to the various builder methods…

Bind

let! x = 100

// translates to

builder.Bind(100, (fun x -> expression))

So as can be seen, in essence the order of the arguments is reversed. So if we were to simply duplicate the way let binding works but in a computational expression we’d write something like

member this.Bind(m, f) = 
   f m

Return and ReturnFrom

At the time of writing this, I’m a little confused as to the difference between Return and ReturnFrom. Computation expressions and wrapper types states that the Return returns a wrapped type whilst ReturnFrom returns an unwrapped type. However it is seems it’s possible to pretty much return whatever I like as shown below

member this.Return(x) = x

member this.ReturnFrom(x) = x

Return is called when we have a return in the computation expression, i.e.

builder {
   return 100
} |> printfn "%A"

and ReturnFrom is used when return! exists, i.e.

builder {
   return! 100
} |> printfn "%A"

One slightly odd thing if you’re used to C# or the likes is that we can have multiple return and/or return! in a computational expression as per

builder {
   return 100
   return! 100
} |> printfn "%A"

As per multiple yield statements, we need a Combine method implemented in our builder to combine the return values. A return does not mean the rest of the computational expression is not executed, it means that the return values are combined to produce a value at the end of the workflow. So for example

builder {
   printfn "First"
   return 100
   printfn "Second"
   return 100
} |> printfn "%A"

Assuming our Return method and Combine are as simple as the following

member this.Return(x) = 
   printfn "Return"
   x

member this.Combine(a, b) = a + b

Then our output will look like the following

First
Return
Second
Return
200

In other words, the first printfn (actually the Delay builder method is called for each printfn) is called then the Return method, then the second printfn then the second Return, then the Combine is called. In this case Combine simply adds the return values together to produce the output of the workflow.

Combine

The combine method combines multiple values – so for example if you had something like the following

builder {
   yield 100
   yield 200
} |> printfn "%A"

without a combine method you’ll get the following compiler error This control construct may only be used if the computation expression builder defines a ‘Combine’ method. Simple enough to see the problem here. So we cannot yield more than once unless we implement a combine method. Here’s an example which implements the combine by creating a list and combining elements into a new list

member this.Combine(a, b) = a @ b

If we now compile this code we’ll get another error, “This control construct may only be used if the computation expression builder defines a ‘Delay’ method”. So we need to implement a Delay method. See the example listed for Delay below…

Delay

The Delay method allows the builder to delay the evaluation of a computational expression until it’s required. For example if we yield multiple times within a computational expression the idea is to combine the yields until we’re ready to invoke something.

The example above creates a list of the yields and then in the Delay we might want to do something with those combined yields. In this example below we’ll simply use the following code

member this.Delay(f) = f()

which essentially just invokes the function passed to the delay.

Run

Whilst the Delay method is used to delay evaluation, the Run method is mean’t to use the delayed expression, i.e. it might be to run something or the likes. An example which simply turns the list created by the combine into an array instead

member this.Run(f) = Array.ofList f

this is obviously a rather simplistic example, had our builder been creating the data for a web service call, for example, possibly run would make the call for us.

For

I again must point anybody reading this section to the excellent post Implementing a builder: The rest of the standard methods where an implementation of the For method is describe, for simplicity I’ll recreate it here

member this.For(sequence:seq<_>, body) =
   this.Using(sequence.GetEnumerator(),fun enum -> 
      this.While(enum.MoveNext, 
         this.Delay(fun () -> body enum.Current)))

The Using, While and Delay methods are described elsewhere in this post.

Here’s some sample code using the For method from our computational expression block

builder {        
   for i = 1 to 10 do
      printfn "%d" i
} 

TryFinally

An implementation of the TryFinally method is fairly straightforward

member this.TryFinally(body, compensation) =
   try this.ReturnFrom(body())
   finally compensation() 

and in usage within a computational expression block, we have

builder {        
   try
      let x = 1 / 0
      printfn "should not make it to here"
   finally
      printfn "exception"
} 

In the above code, when we step into the try block we will actually enter the TryFinally method and obviously this then takes over executing the body of the code and then executing the finally block.

TryWith

Very much like the TryFinally block, we have the following implementation

member this.TryWith(body, handler) =
   try this.ReturnFrom(body())
   with e -> handler e

and an example of the computational expression block might be

builder {        
   try
      let x = 1 / 0
      printfn "should not make it to here"
   with
   | :? DivideByZeroException -> printfn "divide by zero"
} 

Using

As the name suggests, this is used for IDisposable types. Here’s a sample of it’s implementation

member thisTryFinally(body, compensation) =
   try __.ReturnFrom(body())
   finally compensation() 

member this.Using(disposable:#System.IDisposable, body) =
   let body' = fun () -> body disposable
   this.TryFinally(body', fun () -> 
      match disposable with 
      | null -> () 
      | disp -> disp.Dispose())

The Using method relates to the use! keyword and hence we might have code such as

builder {        
   use! x = new MemoryStream()
   printfn "do something with the memory stream"
} 

So at the point use! is invoked our Using method takes over. We i

While

The example of a while loop in a computational expression was lifted from “Implementing a builder: The rest of the standard methods” and I highly recommend anyone visiting this post goes and reads the computational expression series on F# for fun and profit.

So our example code is as follows

let mutable i = 0
let test() = i < 5
let inc() = i <- i + 1

let builder = SampleBuilder()

builder {        
   while test() do
      printfn "%i" i
      inc()         
} |> ignore

It’s important to note that the three let statements at the top of the source must be global or you’ll get an error along the lines of “The mutable variable ‘i’ is used in an invalid way. Mutable variables cannot be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via ‘ref’ and ‘!’.”

So our builder code should look something like the following

member this.Bind(m, f) = f m

member this.Return(x) = x

member this.Zero() = this.Return ()

member this.Delay(f) = f

member this.Run(f) = f()

member this.While(guard, body) =
   if not (guard()) 
   then 
      this.Zero() 
   else
      this.Bind( body(), fun () -> 
         this.While(guard, body))  

So as can be seen, in the While method we are passed the guard and the body of the while loop and as expected we need to invoke these bits of code to evaluate them. When the guard completes we invoke the Zero method which in this case simply called the Return method. If the loop has not completed we simply keep looping.

Yield and YieldFrom

We can use yield or yield! from a computational expression, but to do so we need to implement the Yield and YieldFrom methods (respectively) on the builder, otherwise we’ll be greeted with the “This control construct may only be used if the computation expression builder defines a ‘Yield’ method”, here’s an example of the yield being used from a computational expression block

builder {
   yield 100
} |> printfn "%A"

// or

builder {
   yield! 100
} |> printfn "%A"

An example of the Yield and YieldFrom methods in the builder might look like the following

member this.Yield(x) = Some x

member this.YieldFrom(x) = x

Zero

You may have noticed, if you’ve written your own builder type that something like the following

builder {
}

// or

builder {
} |> ignore

doesn’t compile, this is because a computational expression must have something within the curly braces. So if instead we write the following

builder {
   printfn "Hello"
}

We’re get an altogether different error at compile time stating This control construct may only be used if the computational expression builder defines a ‘Zero’ method. Basically a computational expression must return something, either explicitly or implicitly. In this case Zero is used for any implicit return, so we could resolve this error using

member this.Zero() = ()

or ofcourse we might implicitly return the same thing we would with an explicit return such as

member this.Return(x) = x

member this.Zero() = this.Return ()

Properties, Binding, Property Wrappers and MVVM with Swift

Swift includes properties within the language (see Properties), but also supports (what we’d call in C#) property or data binding mechanisms.

Before we get started, I’m writing this post as a learning exercise, I’d suggest you checkout the references at the bottom of the post for a much more in depth look at this subject.

If you’re still reading, then let’s get started…

To begin with we’ll look at how we declare properties in Swift first. For those coming from C# or similar languages, then the simplest stored property looks just like a field

Property Declarations

struct MyModel {
    var id: String;
}

The above declaration is known as a stored property, in that we can store values with the specific instance of the MyModel type, this is really the equivalent of having a property with a default getter and setter.

We can also declare properties as readonly like this

struct MyModel {
    var id: String {
        return "SomeId"
    }
}

Both of the above examples are basically properties using “shorthand syntax”, like C# we can also create properties with get and set keywords – of course these are useful if the setting of the property (for example) does more than just assign a value, hence we have a form (notice you can use return or in these example we’re using implicit return

struct MyModel {
    private var _id: String = "SomeId"
        
    var id: String {
        get {
            _id
        }
        set {
            _id = newValue
        }
    }
}

Property Observer

Property observers allow us to monitor a property change. For example if you have a struct/class with the shorthand syntax for a property then we can willSet and/or didSet to our property, for example

struct MyModel {
    var id: String = "" {
        willSet(newTitle) {
            print("About to set value")
        }
        didSet {
            if title != oldValue {
                print("Set Value")
            }
        }
    }
}

Now when the property is about to be set, the willSet code is called and when a value changes didSet will be called. Obviously you wouldn’t want to do anything within these methods that could affect performance.

Property Wrapper

A Property Wrapper allows us to (well as the name suggests) wrap a property within a type that we can separate the storage of the property from functionality that acts upon that property. For example if our title has a length constraint, we might create a property wrapper to implement this functionality

@propertyWrapper
struct LengthConstraint {
    private var value = ""
    var wrappedValue: String {
        get { value }
        set { value = String(newValue.prefix(5)) }
    }
}

Property Binding

So what’s this got to do with binding/data binding/property binding? Well we’ve now seen how we declare propeties and can add property wrappers to the property. Within SwiftUI we can use the @Published property wrapper to our property which gets observed by a UI element and when the value changes updates the UI or in the case of TextField, when changes are made to the text field it’s placed into our property.

There are several different property wrappers for this type of functionality

  • @Published – this is used on property classes, such as ObservableObject subclasses.
  • @StateObject – this is used within a view to store an instance of an ObservableObject subclassed type
  • @State – this allows us to store bindable data within a view
  • @Binding – this is used in views which need to mutate a property owned by an ancestor view. In essences it’s like connecting to a parent’s property
  • @EnvironmentObject – this is a shared object stored within the environment and is used in situations where passing properties through a UI hierarchy or the likes becomes too cumbersome.
  • @Environment – this is used to connect to actual environment properties, such as reading whether the application is in dark theme or other SwiftUI properties

MVVM

We can declares @State and @Binding property wrappers (for example) within our view, but of course this can pollute the UI with view model state. If we prefer to go with a MVVM approach, i.e. separate the view from the view model, then we will start off by subclassing ObservableObject, for example here’s a minimal view model

@MainActor class ViewModel: ObservableObject {
    @Published var title: String = ""
}

@StateObject private var viewModel = ViewModel()

In the above code we declare and subclass of the ObservableObject and then we declare the properties that we wish to expose. The @StateObject line is what you’ll have in your ContentView to create an instance of the ObservableObject.

The @MainActor is used to denote that this class runs code on the main queue – essentially if you’re used to Windows UI programming this can be seen as equivalent to running code on the UI thread.

This of course might seem simpler to just declare properties like this, but then our model ends up more tightly coupled to the view than we might want

@State var title: String = ""

References

All SwiftUI property wrappers explained and compared
How to use @MainActor to run code on the main queue
What is the @Environment property wrapper?

Unit testing with Swift

Unit test classes in Swift derive from XCTestCase. You’ll need to import XCTest.

So for example

import XCTest

class MvvmTestTests: XCTestCase {
}

Test functions need to be prefixed with test so for example, if we assume we have a global function like this

func add(_ a: Int, _ b: Int) -> Int {
    return a + b
}

then we might have a test like this

func testAdd() throws {
    XCTAssertEqual(5, MyApp.add(2, 3))
}

Before we can test our add function we need to make the application code available to the test code, to do this after the import XCTest line add

@testable import MyApp

This actually allows our tests to access our code without having to mark all the code as public.

As you’ve seen we use XCTAssertEqual to assert our expectations against actual.

Measuring Performance

We can wrap our code, within a test, using

self.measure {
}

So for example (whilst a little pointless on our add function) we can measure performance like this

self.measure {
   _  = MvvmTest.add(2, 3)
}

We can also apply options to the measure function

let option = XCTMeasureOptions()
option.iterationCount = 100
self.measure(options: option) {
    _  = MvvmTest.add(2, 3)
}

In this case we’ll run the measure block 100 + 1 times. The iteration actually ignores the first run (hence the + 1) this tries to remove cold start times.

Running our tests

In Xcode, select the Test Navigator, this should show you all the tests found. Simply select either a single test or group of tests and right mouse click. Select the Run option and your tests will run.

Running Kafka within Docker

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

Kafka

Kafka is an event streaming service.

Let’s pull the image

docker pull confluentinc/cp-kafka

The docker image of Kakfa requires Zookeeper.

Putting it all together

Create yourself a docker-compose.yml (this one below is taken from Guide to Setting Up Apache.

version: '2'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:latest
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181
      ZOOKEEPER_TICK_TIME: 2000
    ports:
      - 22181:2181
  
  kafka:
    image: confluentinc/cp-kafka:latest
    depends_on:
      - zookeeper
    ports:
      - 29092:29092
    environment:
      KAFKA_BROKER_ID: 1
      KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
      KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1

From your server, you can now connect to Kafka using the docker name (hence replace the docker-name with the name you gave or docker gave to your Kafka instance)

docker exec -it docker-name /bin/sh

Postgresql in Docker

Let’s run up the Docker image with an instance of PostgreSQL

docker run --name mypostgres -d postgres

Now, connect to the instance so we can create a database etc.

docker exec -it mypostgres bash
createdb -U postgres MyDatabase

Note: if you find this error message psql: FATAL: role “root” does not exist, you’ll need to switch to the postgres user, see below.

Switch to the postgres user (su substitute user).

su postgres
psql

At which point, we’re now in the psql application and can create databases etc.

Creating a VSIX based project template

Note: This post was written a while back but sat in draft. I’ve published this now, but I’m not sure it’s relevant to the latest versions etc. so please bear this in mind.

In this post we’re going to create a Prism Project Template using VSIX (as opposed to the File | Export Template option in Visual Studio). This is a relatively simple project template which will create a simple Prism based WPF application, so will demonstrate creating the project template itself along with adding nuget packages etc. and can be used as a starting point for other, more complex Prism based applications.

  • Create New Project
  • Extensibility | VSIX Project
  • Delete index.html and stylesheet.css – no use for our project
  • Add New Project | Extensibility | C# Project Template
  • Double click source.extension.vsixmanifest
  • Select Assets tab
  • New, Type Microsoft.VisualStudio.ProjectTemplate
  • “Source” set to A project in current solution
  • “Project” set to the added C# project template
  • Remove Class1.cs and remove the following line from the vstemplate in the project
    <ProjectItem ReplaceParameters="true" OpenInEditor="true">Class1.cs</ProjectItem>
    
  • From ProjectTemplate.csproj also remove the line
    <Compile Include="Class1.cs" />
    

Now we have an empty class library template (in every sense).

Creating a very basic WPF Project template

  • In ProjectTemplate.csproj change OutputType from Library to WinExe
  • In ProjectTemplate.csproj in the ItemGroup with Reference elements add
    <Reference Include="System.Xaml">
       <RequiredTargetFramework>4.0</RequiredTargetFramework>
    </Reference>
    <Reference Include="WindowsBase" />
    <Reference Include="PresentationCore" />
    <Reference Include="PresentationFramework" />
    
  • To the Project template project add new item WPF | User Control(WPF) name it App.xaml
  • Replace the XAML with
    <Application x:Class="$safeprojectname$.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Application.Resources>
        </Application.Resources>
    </Application>
    
  • Change App.xaml.cs to
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace $safeprojectname$
    {
        /// <summary>
        /// Interaction logic for App.xaml
        /// </summary>
        public partial class App : Application
        {
            protected override void OnStartup(StartupEventArgs e)
            {
                base.OnStartup(e);
            }
        }
    }
    
  • For both files, show the properties (F4) window and set Build Action to None or the compiler will attempt to compile the code
  • Inthe project’s vstemplate add the following within the project element
    <ProjectItem ReplaceParameters="true" OpenInEditor="true">App.xaml</ProjectItem>
    <ProjectItem ReplaceParameters="true" OpenInEditor="true">App.xaml.cs</ProjectItem>
    
  • In the csproj file add the following to the ItemGroup with the line
    >Compile Include=”Properties\AssemblyInfo.cs” /<

        <Compile Include="App.xaml.cs">
          <DependentUpon>App.xaml</DependentUpon>
          <SubType>Code</SubType>
        </Compile>
    
  • Create a new ItemGroup in the csproject with the following
      <ItemGroup>
        <ApplicationDefinition Include="App.xaml">
          <Generator>MSBuild:Compile</Generator>
          <SubType>Designer</SubType>
        </ApplicationDefinition>
      </ItemGroup>
    

Adding Prism

At this point if you try to run this template it should create a valid project but it will not run as there’s no Main entry point. This was on purpose as we don’t need the StartupUri set in the App.xaml.

We’re going to need to load up nuget packages for prism

  • Add the following after the </TemplateContent>
      <WizardExtension>
        <Assembly>NuGet.VisualStudio.Interop, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</Assembly>
        <FullClassName>NuGet.VisualStudio.TemplateWizard</FullClassName>
      </WizardExtension>
      <WizardData>
        <packages repository="extension" repositoryId="productId">
          <package id="Prism.Core" version="6.3.0" />
          <package id="Prism.Wpf" version="6.3.0" />
          <package id="Prism.Unity" version="6.3.0" />
          <package id="Unity" version="4.0.1" />
          <package id="CommonServiceLocator" version="1.3.0" />
        </packages>
      </WizardData>
    

    Replacing the productId with the Product ID from your vsixmanifest

  • In your vsix add a folder named Packages
  • Goto https://www.nuget.org/packages/Prism.Core/ and press download to grab Prism.Core
  • As above for https://www.nuget.org/packages/Prism.Wpf/, https://www.nuget.org/packages/CommonServiceLocator/ and https://www.nuget.org/packages/Unity/
  • Copy/save the nupkg to your new Packages folder
  • Back in Visual Studio select show all files then right mouse click on the nupkg files and select include in project
  • Set the build action to Content in the Properties (F4) view on each file and Copy to output to Copy Always, also set Include in VSIX to True
  • Add the following to the Assets section in the vsixmanifest
        <Asset Type="prism.core.6.3.0.nupkg" d:Source="File" Path="Packages\prism.core.6.3.0.nupkg" d:VsixSubPath="Packages" />
        <Asset Type="prism.unity.6.3.0.nupkg" d:Source="File" Path="Packages\prism.unity.6.3.0.nupkg" d:VsixSubPath="Packages" />
        <Asset Type="prism.wpf.6.3.0.nupkg" d:Source="File" Path="Packages\prism.wpf.6.3.0.nupkg" d:VsixSubPath="Packages" />
        <Asset Type="unity.4.0.1.nupkg" d:Source="File" Path="Packages\unity.4.0.1.nupkg" d:VsixSubPath="Packages" />
        <Asset Type="commonservicelocator.1.3.0.nupkg" d:Source="File" Path="Packages\commonservicelocator.1.3.0.nupkg" d:VsixSubPath="Packages" />
    

Add the Boostrapper

For Prism to work we need to add the boostrapper so in your project template add a new CS file named ShellBootstrapper.cs and as we’re using Unity here, it should look like this

using Microsoft.Practices.Unity;
using Prism.Unity;
using System.Windows;

namespace $safeprojectname$
{
    class ShellBootstrapper : UnityBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }

        protected override void InitializeShell()
        {
            Application.Current.MainWindow.Show();
        }
    }
}

set the Build Action in the properties (F4) window to None. In the csproj add under the other Compile entry

    <Compile Include="ShellBootstrapper.cs" />

We now need a MainWindow, so add a UsecControl.xaml named MainWindow.xaml, set Build Action to None and changed the XAML from UserControl to Window and the same in the cs file, here’s the code

<Window x:Class="$safeprojectname$.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:cal="http://www.codeplex.com/prism"
             xmlns:local="clr-namespace:$safeprojectname$"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <ItemsControl cal:RegionManager.RegionName="MainRegion" />
</Window>

and the code is

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace $safeprojectname$.App
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }
}

add the following in after the last ProjectItem in the vstemplate

      <ProjectItem ReplaceParameters="true" OpenInEditor="true">MainWindow.xaml</ProjectItem>
      <ProjectItem ReplaceParameters="true" OpenInEditor="true">MainWindow.xaml.cs</ProjectItem>
      <ProjectItem ReplaceParameters="true" OpenInEditor="true">ShellBootstrapper.cs</ProjectItem>

Also add to csproj

<Compile Include="MainWindow.xaml.cs">
   <DependentUpon>MainWindow.xaml</DependentUpon>
</Compile>

within the ItemGroup in the template’s csproj that has the None Include App.xaml place

<Page Include="MainWindow.xaml">
   <Generator>MSBuild:Compile</Generator>
   <SubType>Designer</SubType>
</Page>

In the OnStartup of App.xaml.cs add

var bootstrapper = new ShellBootstrapper();
bootstrapper.Run();

If you now run the VSIX from Visual Studio, it should load up the Visual Studio Experimental instance and you should be able to create a project from the template which will build and run successfully.

Maven file structure basics

This is an old blog post that sat in draft for years, int looks complete, so I thought I’d publish it. Hopefully it’s still upto date.

As I’m working in Java again and using Maven a lot to get my projects up and running. Whilst I’ve covered some of this stuff in other posts, they’ve tended to be part of working with some specific code. So this post is mean’t to be more about using Maven itself.

Maven convention file structure

By default the following file structure is expected

/src/main/java
/src/main/resources
/src/test/java

Optionally we might have the test/resources

/src/test/resources

POM starting point

Maven (be default) expects a file name pom.xml to exist which contains version information and may include plugins, code generation, dependencies etc.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.putridparrot.common</groupId>
    <artifactId>JsonPatch</artifactId>
    <version>1.0-SNAPSHOT</version>
</project>

Naming conventions (see references)

groupId – “identifies the project uniquely across all projects” hence might best be represented by the package name.
artifactId – is the name of the JAR
version – standard numbers with dots, i.e. 1.0, 1.0.1 etc. This is a string so in situations where we want a version to include the word SNAPSHOT (for example)

Maven commands

Before we get into more POM capabilities, let’s look at the basic set of Maven command’s we’ll use most.

Compiling to specific Java versions

<properties>
   <maven.compiler.source>1.8</maven.compiler.source>
   <maven.compiler.target>1.8</maven.compiler.target>
</properties>

OR

<build>
   <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.7.0</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
</build>

References

Guide to naming conventions on groupId, artifactId and version
Setting the -source and -target of the Java Compiler

Parameterized unit testing in Java

Occasionally (maybe even often) you’ll need some way to run the same unit test code against multiple inputs.

For example, you might have some code that iterates over a string counting certain characters (let’s say it counts the letter Z), the unit test would be exactly the same for testing the following scenarios

  1. When no characters of the expected type exist
  2. When characters of the expected type exist
  3. When the string is empty
  4. When the string is null

The only difference would be the input to the unit test and the expectation for the assert. In such situations we would tend to use parameterized unit tests, in C#/NUnit this would be with TestCase attribute. In Java with JUnit 5 (org.junit.jupiter.*) this would be with the @ParameterizedTest annotation.

We’re going to need to add the following dependency to our pom.xml (change the version to suit).

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter-params</artifactId>
  <version>5.8.1</version>
  <scope>test</scope>
</dependency>

We could write two unit tests for the above scenario, one for success and one for failure, such as when no characters exist (i.e. the string is null or empty we expect a 0 return from our system under test), a second test would maybe check a known return value. In such situations we can simply use something like

@ParameterizedTest
@ValueSource(strings = {"", null, "aaabbb" })
void noZExists_ShouldReturn_Zero(string input) {
    assertEqual(0, CharacterCounter.countZ(input));
}

Now we’d have another unit test for successful cases, for example

@ParameterizedTest
@ValueSource(strings = {"aaaaZZZ", "ZZZ", "ZZZaaa" })
void zExists_ShouldReturn_Three(string input) {
    assertEqual(3, CharacterCounter.countZ(input));
}

This would be far better if we simply wrote one unit test but could pass in both the input as well as the expected result, hence combine all values into a single test. The only option I found for this was to use the @CvsSource annotation, so for example we write the input followed by the comma separate followed by the expectation – ofcourse we could supply more than two args per call of the unit test, but this is adequate for our needs – this means our test would look more like this

@ParameterizedTest
@CsvSource({ "\"\",0", "aaabbb,0", "aaaaZZZ,3", "ZZZ,3", "ZZZaaa,3" })
void zExists_ShouldReturn_Three(string input, int expectation) {
    assertEqual(expectation, CharacterCounter.countZ(input));
}

Localization in SwiftUI

Let’s create a simple little Swift UI application (mine’s a Mac app) to try out the Swift UI localization options.

Once you’ve created an application, select the project in the Xcode project navigator. So for example my application’s name LocalizationApp, select this item in the project navigator. From the resultant view select the project (not the target) and this will display a section labelled Localizations. This will show your Development Language, in my case this is English. Beneath this you’ll see a + button which we can use to add further languages.

Click on the + as many times as you like and add the languages you want to support. I’ve just added French (Fr) for my example.

Adding localizable strings

Add a new file to the project, select a Strings file and name it Localizable (hence it will be Localizable.strings). This file will have key value pairs, where the key will be used as the key to the localised string and, as you probably guessed, the value will be the actual localised string, for example

"hello-world" = "Hello World";

Note: if you forget the semi-colon, you’ll get an error such as “validation failed: Couldn’t parse property list because the input data was in an invalid format”.

Now if you’ve created the default Mac application using Swift UI, go to the ContentView and replace the following

Text("Hello, world!")

with

Text("hello-world")

Wait a minute, we seemed to have replaced one string with another string, why isn’t the Text displaying “hello-world”?

The Swift UI Text control (and other controls) support LocalizedStringKey. This essentially means that the code above is an implicit version of this

Text(LocalizedStringKey("hello-world"))

So basically, we can think of this (at least in its implicit form) as first looking for the string within the .strings file and if it exists, replacing it with the LocalizedStringKey. If the string does not exist in the .strings file then use that string as it is.

We can also use string interpolation within the .strings file, so for example we might have

"my-name %@" = "My name is %@";

and we can use this in this way

Text("my-name \(name)")

The %@ is a string formatter and in this instance means we can display a string, but there are other formatters for int and other types, see String Format Specifiers.

What about variables and localization?

We’ve seen that Text and the controls allow an implicit use of LocalizedStringKey but variable assignment has no such implicit capability, so for example if we declared a variable like this

let variable = "hello-world"

Now if we use the variable like this (below) you’ll simply see the string “hello-world” displayed, which is predictable based upon what we know

Text(variable)

Ofcourse we can simply replace the variable initialization with

let variable = LocalizedStringKey("hello-world")

Adding other languages

Let’s now create a new language for our application by clicking on the Localizable.strings file and in the file inspector you’ll see a Localize button. As we’d already added a language view the project navigator (at the start of this post). You’ll now see both English and French listed. The Localizable.strings file now appears a parent to two Localizable files, one named Localizable (English) and one named Localizable (French).

In the French file we’ve added

"hello-world" = "Bonjour le monde";
"my-name %@" = "Mon nom est %@";

Note: What you’ll actually find is the within the application directory there will be two folders, one named en.lproj and fr.lproj each will have a Localizable.strings file.

Testing our localizations

Ofcourse if we now run our application we’ll still see the default language,, in my case English as that’s the locale on my Mac. So how do we test our French translation?

We can actually view the translations side by side (as it were) by amending our code like this

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            ContentView()
                .environment(\.locale, .init(identifier: "en"))
            ContentView()
                .environment(\.locale, .init(identifier: "fr"))
        }
    }
}

Or (much more likely) we can go to the application code and replace the WindowGroup with the following

var body: some Scene {
   WindowGroup {
      ContentView()
         .environment(\.locale, .init(identifier: "fr"))
   }
}

Actually, there’s also another way of change the locale.

Instead of coding the change, select the application name in Xcode’s top bar and a drop down will show “Edit Scheme”. Select the “Run” option on the left and then the tab “Options”. Locate the “App Language” picker and select French (or whichever language you added as non-default). Now run the application again and you’ll see the application using the selected language localization file.

Exporting and Importing localizations

Whilst we can use google translate or other online translation services, we might prefer to export the localization files so we can send them to a professional translation service.

Select the application within the project navigator, then select Product | Export Localizations… this will create a folder, by default named “<Your application name> Localizations” (obviously where Your application name is replaced by your actual app name). This folder contains en.xcloc and fr.xcloc files in my case.

After your translation service/department/friends complete the translations, we can now select the root in the project navigator (i.e. our application) then select Product | Import Localizations… from here select the folder and files you want to import. Click the “Import” button.

What happens if I run this command in Powershell

As Powershell allows us to do things, like stop process, move files and more, we might prefer to check “what if I run this command” before actually executing it.

Whatif

Let’s assume we want to stop several processes, but before executing the command we’d like to see some output showing what the command will do.

For example

Get-Process *host | Stop-Process -whatif

Instead of actually stopping the processes found via the wildcard *host this will output a list of “what if” statements, showing the operation which would take place against which target (process).

So we might notice that our wildcard includes unintended consequences and can thus save ourselves the headache unwanted changes.