Template with a single case of a data definition

Suppose I have something along these lines

data Foobar
    = Foo with
      f: Int -> Int
    | Bar with
      b: Int

Would it be somehow possible to have a template definition where a Bar (but not a Foobar) is a field of a template?

If I try to add this data definition to the basic template for create-daml-app and then add a field of type Bar to the User template I get the following error:

  daml/User.daml:16:10: error:
  • Expecting one more argument to ‘Bar’
  Expected a type, but ‘Bar’ has kind ‘Int -> Foobar’
  • In the type ‘Bar’
  In the definition of data constructor ‘User’
  In the data declaration for ‘User’

Out of sheer curiosity, since the error seemed to point out at the need to add an integer to the type definition, I’ve done it by defining the type of the field to be Bar 42 and the following error comes up

  daml/User.daml:16:10: error:
  • Expected a type, but ‘Bar 42’ has kind ‘Foobar’
  • In the type ‘Bar 42’
  In the definition of data constructor ‘User’
  In the data declaration for ‘User’

Bar is not a separate type in Daml, it only exists at the value level. The only type is Foobar. So you cannot have a field of type Bar. You can only have a field of type Foobar. This is different from language like scala where you define separate types that extend the sealed trait/class instead of purely value-level constructors.

Note that this is not true in Daml-LF. The compiler automatically creates a type called Foobar.Bar here but you cannot access this in Daml. This is documented in How Daml types are translated to Daml-LF — Daml SDK 2.0.0 documentation

I see, thanks. This means that in practice it’s impossible to observe a value of type Foobar over the Ledger API if any of its cases is not serializable, would that be correct?

Yes, if one case is not serializable the whole variant is not serializable.

1 Like

If you want to emulate that in Daml, you’ll have to make Bar its own standalone type, and then “wrap” it in FooBar:

data Bar = Bar (Int -> Int)
data Foo = Foo Int
data FooBar
  = FooBar_Bar Bar
  | FooBar_Foo Foo

This can get a bit cumbersome and verbose though, so depending on the use-case it may not be worth it.