Tag Types in Typescript with taghiro

You can leave Feedback and follow me on Twitter.

Typescript has brought types in Javascript to the mainstream. With TS it’s easier to write correct code and code that’s easier to understand.

One step further are tag types. With them you can tag other types and you express refined types with richer constraints. I’ve written about them before in Scala here and here. For example NotZero is a tag type preventing b to be 0 in this example.

I’ve written a tag type library in Typescript with a number of ready to use tag types to make your code richer and cleaner. It’s called taghiro and can be found on Github. It’s mission is to prevent bugs and make code more readable to developers.

Ready to use tag types

Some examples of the many ready to use tag types included in taghiro are

  • MinSize
  • NonEmpty
  • Sorted
  • Positive
  • UpperCase

Tag types can easily be used with Typescript Union types and type guards. Suppose we have a function that lists all product categories and takes a category as a parameter. In our system all categories have to be uppercase, e.g. ELECTRONICS.

To make sure the parameter is uppercase we declare it as string & UpperCase.

Developers easily can see the constraint of category: It must be uppercase. Compare this to a method signature where the constraint is in the documentation. Failure to adhere to the constraint is not detected at compile time but at runtime and depending on the error handling in listProductCategory the system might crash.

A method with tag types can be used with type guards. Type guards in Typescript ensure a variable has a certain type. After the check Typescript assumes the variable has the corresponding type without casting.

isUpperCase is defined by taghiro

Handling the case that category is not uppercase now lays in the responsibility of the caller, who is much better equipped to handle the case as there is more context. In most systems the transformation from string to string & UpperCase happens a the edges, while inside the system every method uses string & UpperCase and needs no more error handling code.

Now on to a second complex example. Suppose we want to write an API to send emails.

Here several things could go wrong. First the to array could be empty. Second html could be empty, not contain any HTML or contain unsafe HTML. With tag types we can make sure the paramaters are save.

Now the caller needs to ensure that the parameters satisfy the tag types.

Another way would be to use custom types for the parameters. This has the drawback in Typescript that it doesn’t prevent using the wrong type.

Or we could use ReceiverList and Html classes, which is the usual way to use OO and then use the same type guards to check for NonEmpty.

The downside here is you need more classes and in a large project this leads to hundreds of smaller helper data classes. These need to be maintained and kept in your mind when you develop new parts of the system or change existing parts. One other drawback is that you can’t put these values into methods that take string and Array<string> while you can do this with the tag types.

But the major downside is the OO argument of encapsulation. ReceiverList encapsulates Array<string>. This indirection is aimed to make it easier to understand systems while in reality this indirection adds another layer you need to be aware of. Array<string & Email> & NonEmpty can be understood by everyone new to the project without looking into more classes. Compare this to an ReceiverList constructor

were we still don’t know without looking in the documentation the constraints on theEmails (non-empty and being emails).

Custom tags

With taghiro you can write your own Tags. By leveraging libraries for checking emails and HTML we can easily implement Email and SafeHtml to make the method even safer.

Custom tag types

Beside using the supplied tag types, it’s adviced to use your own. Tag types can be used to define custom domain concepts. One example is id. Here is an example based on string Uuid ids.

This way it’s impossible to put the wrong ids into a method.

will only take a CustomerId. Compare this to

where in complex projects it’s easy to put the wrong id into the findCustomer method, producing a hard to find bug.

One can define a custom Tag type to define more than one id tag.

Tag types are an easy way to build on the already excellent type system of Typescript. taghiro supplies ready to use tag type so you will need to write less code. And it will help you write less bugs.

taghiro is Open Source and licensed under a MIT license.

Reordering Futures in Java Streams

Futures are an interesting concept in concurrent and parallel programming. I’ve written about them several time, the last time in Advanced Futures With Play Framework. Streams are a concept which came with Java 8 to operate on a stream of objects, transform and filter them. Combining Futures and Streams in Java sometimes isn’t easy. Some time ago a problem arised in code where slow futures in a stream were blocking other objects in the stream to be processed. Usually you’d use parallel streams in this case, but for operations concerns parallel streams had the wrong thread characteristic. Therefor I’ve thought about ways to unblock streams.

Lets start with a simple example. We have a simple asynchronous API call and a Stream of items and want to call an external API potentially with IO which takes some time:

We iterate over the stream and make the call. The call returns CompletableFuture so our stream becomes a Stream of Futures. In the end we collect the items of the stream into a List with a stream collector, in this case Collectors.toList(). As a minor challenge the collect call returns List<CompletableFuture<T>>, but we would like to have CompletableFuture<List<Integer>> for easier consumption. Luckily the futures library from Spotify provides an allAsList call which turns a List of Futures into a Future of List.

When running the code it outputs

The stream processes all items without blocking (4x Stream 1), then all API calls finish (Done) and afterwards the results are printed as 301, 1001, 102, 21. As the stream operates on Futures which do not block, our code immediatly runs after creation of the stream without waiting for the stream processing to end. Only when we call join() in the last line, our code blocks and waits until all futures have finished.

Streams are not only mapping but also support filtering. We now want to filter on the values of futures. As our Stream needs to deal with the value of a future, we need to wait on the future to complete, pull the value from the Future context into the Stream context with f.join():

Running this code is not as nice as before. The stream processes one item, then blocks until the call finishes, then processes the next item.

As can be seen from the output, the longer running task (1000) blocks (join) processing of futher stream items. Most often this is solved by using parallel streams. A parallel version would look like this

As expected the output again processes all items, the 1000ms API call does no longer block processing of other items:

If we want to have more control over when and how many threads are used at what time, and we also want single threaded Stream, we can implement a custom stream collector. With a custom collector, we can reorder the futures of the stream and move those that have completed to the front. Our custom collector is called FutureReorderCollector. It gathers all Futures and creates a new stream with a new ordering. Finished futures are now moved forward and running futures are kept back.

Output now is as before, although we are not using parallel streams and have a long running (1000ms) API call.

The long running Thread is moved to the end of the stream. Stream execution is blocked only as much as needed.

Our collector needs an executor to process those Futures. An optimized version could work with the executor already used by the futures. But in this case we provide a custom ExecutorService which we need to shut down after we finished work.

Implementation of the custom collector is simple. It collects all futures into a custom FutureCompletionService and creates an new Stream in the finisher with Stream.generate(f::take).limit(f.size()).

The collector uses a custom completion service, were we add futures to a JDK CompletionService and block on polling finished futures in take. One implementation detail is the counting of submitted tasks with AtomicInteger. This is used to limit the Stream generated in FutureReorderCollector.

Streams and futures are powerful concepts in Java. Sometimes it’s not easy to combine them. With this code you can implement your own collector to change how streams process their items.

Advanced Futures With Play Framework

Some time ago I wrote A Little Guide on Using Futures for Web Developers to explain how to use Futures in web development to speed up page delivery with parallelism.

Futures in Play

Lately I’ve played a little with the Play Framework using its async actions so I want to add to this guide. Play controllers can return async actions in the form of Future[Action[...]] which then are executed.

Asynchronicity is not for free. It creates more complicated code and is harder to detect. Why would we use it then? Mainly to speed up requests by parallelizing code to several cores, do other work during IO waits or parallelize waits.

For an example we have three IO calls and two html fragments renderings. Together our request takes 80ms.

When we asynchronize IO and parallelize rendering to more cores we reduce request time to just 50 ms. This is nearly a 50% speed up. And the more database IO your code has and the more you can parallelize rendering parts of a page and the more cores you have, the higher the speedup.

There are some pitfalls though. If your CPU is highly congested, rendering time may have outliers and take longer, because in the example above render2() might be blocked on the second core. So your request waits for the task on the second core to finish. If you use 16 cores then only one needs to be congested and your request is hold up (depending on your threadpool / executor implementation). Async code might also take up more memory, because threads are blocked waiting for IO. This is the case if you do not use real async IO (database) drivers and most “async” drivers are not async to the core but use threads themselves to achieve asynchronicity.

Using asynchronous code also takes a little time and thinking, because you can easily by mistake add some blocking part and all your nice parallelism goes out the window.

One Play action in one of my side projects uses Futures for asynchronous code and looks like this:

The code has three database operations with each returning a Future[..]. First all() returns a list of all urls of type Future[Seq[String]]. The double map calls get into the list and iterates over every item. The calls to byUrl and history return their own Futures of type Future[Option[Page]] and Future[Seq[String]].

Our code looks more complicated than a simple for comprehension but with a simple for comprehension there are some pitfalls e.g.

The code can be written with nested fors though if we translate our working example from before from nested maps to nested fors. You can recognize the Future.sequence and flatten calls from above.

Though complicated looking this code is pure parallelism bliss as the controller method returns immediatly without blocking or waiting with a Future for Play to execute. Also byUrl and history get called in parallel as they do not depend on each other. Suppose all() returns a list of 10 urls the code will then create 20 Futures which are worked on in parallel (depending on the number of cores/hyperthreads and the threadpool used). The code does not create 2 Futures sequentially for one url after another waiting for each Future to succeed but creates Futures for all 10 urls in one swoop.

Expressed in dependencies

instead of

Blocking Threads

You can test this construct of nested fors by running

run with

You will see something like

Why isn’t the code running all 2×5 Futures at once as promised above? We use the global standard Scala ExecutionContext. The context limits the running threads to your number of cores. When we have blocking Futures e.g. because of IO, no more threads are executed. Fortunately we can tell Scala if our Future is blocking. When we change the code to

we get the expected results:

Database access with Future

The byUrl method which returns a Page by its url looks like this:

In our usecase we use getOrElse for working with the Option to get the title. If empty results should be sorted out in our for chain, this gets more complicated. But there is some help working with Future[Option[...]] in A Little Guide on Using Futures for Web Developers.

The method executeWithRSF uses

for parallelism. This can be changed to use a native asynchronous database driver.

More than one Future depends on result of previous Future

Sometimes you have more than one Future that depends on a previous Future and we can generalize our case from above. If you just call Futures one after each other, as before the Futures are created sequentially and not executed in parallel.

Here b is executed after a has finished, c is executed after b is finished.

With this code all three are executed at the same time:

Asynchronous Write/Database IO after Form Validation

How do you use Action.async with Form Validation? This code uses async futures to receive a webpage for an url the user has entered. Then the title and description is inserted into a database where insert returns Future[Option[Int]] with the new primary key of the inserted page.

We need to use a monad transformer FutureO because otherwise we’ll end up with Future[Option[Future[Option[Int]]]] which isn’t flatable. FutureO[FutureO[Int]] is flatable to FutureO[Int] which then can be transformed to Future[Option[Int]]. The monad transformer takes Future[Option[...]] as a constructor argument.

Moving to asynchronous request handling code has sped up many of my projects. Getting into thinking with Futures is a steep learning curve at first but pays of. You can finde more about Futures in my A Little Guide on Using Futures for Web Developers.