A more ergonomic approach might be to have your function accept any type with a toText method as its argument, and then create your own wrapper classes for Nat, Text, and so on that implement that interface.
Something like this:
Or in your case:
type ToText<A> = {
toText : A -> Text;
};
func toText(x : ToText) : Text {
return x.toText();
};
This example seems a bit pointless but it can be quite powerful when you implement multiple interfaces in a single type and then deal with abstract values.
I’m not sure if Motoko supports something like func toText<A : ToText, OtherInterface>(x : A) : Text { these days but that would make it more practical.
I was resorting to this hack in the past but it doesn’t help with accepting function arguments that are super types of multiple types or “implement multiple interfaces”: