When writing generic code in C++, it’s easy to imply constraints in the generic type when developing a template. For example:
template<class T> class Announcer{ public: static void announce( const T& t ) { std::cout << "And now from " << t.country << ", we have: "; bool first = true; for ( auto person : t.people ) { std::cout << person; if (!first) std::cout << "\n"; first = false; } } };
Here, we’re assuming that T has two properties, ‘country’ and ‘people’, with the latter being enumerable (i.e. supports begin/end methods and iterators). This is one of the attractions of C++ for generic code – although, in the future, concepts will enable you to document the constraints in order to make it easier for developers to use your library, and for the compiler to give clearer errors.
What about something similar in F#? I found Tomas Petricek’s post from StackOverflow very useful.
type IHasCountryProperty = abstract Country : string type Announcer<'T when 'T :> IHasCountryProperty>( item : 'T) = member this.Announce() = printfn "And now the party from %s" item.Country let inline countrifiedItem<'T when 'T : (member Country : string)> (item : 'T) = { new IHasCountryProperty with member this.Country = (^T : (member Country : string) item) } type London() = member this.Country = "England" // Use it let city = London() Announcer( countrifiedItem city ).Announce()
The Announcer class uses a member constraint with statically resolved type parameters which bind to the Country property. Then, the inline static function ‘countrifiedItem’ uses static member constraints to capture the existing Country property on any other type, even if like ‘London’ it doesn’t support the IHasCountryProperty. The consensus seems to be that this approach is encouraged because it documents the requirements on ‘T in an interface.