I stated above that the new form of the UpdatePosition method helps prevent bugs of the type mentioned. The pattern essentially provides a framework for writing safer code, but does not provide an instant cure. To illustrate this, say that UpdatePosition was called somewhere in code in the following manner:

string accountRef = ...; string stockId = ...; int positionChange = ...; int newPosition = (int)_accountDb .UpdatePosition((AccountRef)accountRef, (StockId)stockId, (PositionChange)positionChange);

This is a minor improvement over the equivalent call and at least the casts force the programmer to think a bit more. However, the full benefit will only be accrued should these types be used throughout the code, except where impossible to do so - for example, when interacting directly with a database, or UI controls or another system that does not understand these types. In such cases, conversion to the strong type should take place as soon as possible, and no API of any kind - even if it’s just an internal class - should use anything other than strong types.

The benefits of strong typing go far beyond simply reducing ambiguity in method signatures. The act of encapsulation allows one to alter the underlying data type much more easily than would otherwise be the case. If it were decided that a position were better represented using a double or long rather than an int as it has been above then doing so by changing the data member in Position would be considerably less impactful than needing to change everywhere that an int is used to store a position. There might be places where casting to or from an int might need to be addressed, but finding those places should be straightforward using a modern IDE.

Another benefit of encapsulating is the ability to perform constraint checking. If, for example, an account reference were expected to be three uppercase letters followed by three digits, then the constructor of AccountRef could be made to check that. Clearly, such a check can be made somewhere against a raw string . But the question is what is then responsible for performing that check. If just a string were used then any method handling account references would need to perform the constraint checking or just hope the value is in the correct format. On the other hand, if AccountRef is used by such methods then the correct format is guaranteed by contract. This approach also guarantees that format errors are detected as soon as they are made and not embedded deeper in the code - if, for instance, the text from a text-entry UI control is immediately cast to an AccountRef after a user has entered it, then the error will be presented to the user there and then rather than materialising deeper in the process or in another process.

Yet another advantage of encapsulation is implied by the provision of the Position.Adjust method. Though there is nothing to prevent a developer from casting to int , doing the maths and then constructing a new Position instance, the presence of this method defines the correct usage pattern when adjusting positions.

Further ways in which strong typing can help with changing existing code can be illustrated by way of an example. Say there is an interface to a reporting system, which, among other things, allows for the reporting of overall position changes for a stock:

namespace Demo { public interface IPositionReporter { void ReportPositionUpdate(StockId stockId, Position newPosition); } }

Now let’s also say that we start trading futures contracts as well as stocks, and we represent futures using the strong type FutureId that, like StockId , uses an underlying type of string . Adding a method for reporting futures position updates is as straightforward as providing an override to ReportPositionUpdate that takes a FutureId instead of a StockId . If both IDs had been represented by a type of string , then a new method name would be required (e.g. ReportFuturesPositionUpdate ). Not only would the code become more verbose, there would also then be a decision required as to whether or not to rename the stock-reporting method to be consistent with the naming of the new method. Renaming would possibly widen the impact of adding the new method particularly if this were a public API. Not renaming would make the existing method usage ambiguous - there’s nothing to say it’s only for stock position reporting. And, again, either way we have the now-familiar issue that there’s nothing the compiler can do to stop you from calling the wrong method.

A different modification to the reporting system might be that there’s a request to display a stock using a friendly name rather than an ID (e.g. "Google Inc." instead of "GOOG"). A new type of StockName could be added, again with an underlying type of string , and the interface adjusted to:

namespace Demo { public interface IPositionReporter { void ReportPositionUpdate(StockName stockName, Position newPosition); } }

This would break existing code such that it would no longer compile. Had a string been used for stock ID and stock name, then that would not be the case. However, the break is a good thing as it makes it a lot easier to analyse existing code and determine the changes required so that the correct data is reported.

The downsides of strong typing Adding these new types will clearly increase the size of your codebase and binaries. How much of a real issue this is though is a moot point, and unless you have a very large number of these types then the benefits will almost definitely outweigh this negative. Remember that using them will reduce the amount of repeated constraint-checking code required should string or int be used instead. Probably the biggest barrier to using these types is generating them in the first place, especially if you want the types to be comparable as well as equatable. Once generated, they tend to be very low maintenance. But the initial generation can be a pain, particularly if you have a number of them and particularly in C#. Below we look at possible ways of defining these types without having to write too much boiler-plate code. However, even if you find yourself having to write this boiler-plate code, I would argue that the improvements to your code-base you get from using strong typing are worth it. In addition, using strong typing will reduce code required elsewhere to check constraints and reduce the amount of unit-testing required.

The definition of strong types in different languages Both Scala and C++ have language features that can reduce the amount of work involved in defining these types. In Scala you could perhaps use case classes which provide default definitions of certain operators in terms of the class parameters provided: package Demo case class AccountRef(private val value: String) Whilst in C++, Boost’s BOOST_STRONG_TYPEDEF will allow you to define a type in terms of another, giving equatability and comparability. This is shown below with the addition of a hash_value function which will allow the type to be used in std::unordered_set or as a key in std::unordered_map when used in conjunction with boost::hash . #include <boost/functional/hash.hpp> #include <boost/serialization/strong_typedef.hpp> namespace Demo { BOOST_STRONG_TYPEDEF(std::string, AccountRef); std::size_t hash_value(AccountRef const& accountRef) { boost::hash<std::string> hasher; return hasher(static_cast<std::string>(accountRef)); } } However, although BOOST_STRONG_TYPEDEF will define a type which will prevent a string being passed to a method expecting an AccountRef , implicit conversions in other circumstances (such as assignment) are possible. Defining a variation on BOOST_STRONG_TYPEDEF that ensures that explicit conversions are required should be straightforward, however, and such a macro could probably include a standard definition of the hash_value function. In C#, though, there are no handy short-cuts. However, the pain can be alleviated to a degree by using code templates for generation, and to this end you’ll find ready-made templates for use in Visual Studio and Visual Studio Code in our code templates repository on GitHub.