Detecting Generic Type in Motoko

I want to do something like the following. Is it possible? age : Nat is listed on the pattern matching page at Pattern matching :: Internet Computer but it doesn’t seem to work/compile here. I tried just using the type, but that didn’t work either. Is there any way to programmatically deduce the type used in a generic?

public func test<T>(x : T) : async Text {
      switch(x){
          case(x : Nat){
              return Nat.toText(x);
          };
          case(x : Text){
              return x;
          };

      };
  };

I don’t think so. You could create a variant with cases for Nat and Text though, if that’s acceptable for your use case.

Something like:

type TextConvertible = {
  #nat: Nat;
  #text: Text;
};

public func toText(x : TextConvertible) : Text {
  switch (x) {
    case (#nat(nat)) {
      return Nat.toText(nat);
    };
    case (#text(text)) {
      return text;
    };
  };
};

The call it with toText(#nat(42)) or toText(#text(“Hello”))

Alternatively you could take the approach described in this blog post by @nomeata: Making dictionary passing explicit in Haskell – Blog – Joachim Breitner's Homepage

I did something experimental along those lines in Motoko a while back. It could get quite verbose at times though.

Unfortunately I think it’s in a private repo somewhere.

2 Likes

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”:

2 Likes

The short answer is no. Motoko’s polymorphism is parametric, and there is by design no way to test the identity of a type parameter.

Type annotations on patterns are not dynamic type tests:

In Haskell, people use type classes to work around this limitation in some cases - though expressible in Motoko, it quickly gets ugly without Haskell style inference of dictionaries:

Your best bet is to have the call site pass in the desired toText function as an extra argument test.

2 Likes

This is exactly the thing I’m trying to get a value out of. I was hoping to have a getRawValue(x : TextConvertable) : T{} that would unwrap that value but it looks like there is little to no reflection capability.

I wonder if a typeOf() function is possible in motoko that returns the type. Seems like a reasonable thing to add(edited because claudio says it isn’t reasonable as the language just doesn’t support it.).

1 Like

Thank you for providing so many great examples on this forum :grin:

Originally I was quite frustrated with all these custom objects but now I see that they are so helpful for all these undocumented canisters services; the more public input and output data guidance there is directly on the API the better.

I tried this a long time ago but revisited it recently and it’s definitely an improvement thanks to some recent language features.