Could you please explain type signatures in the interface syntax?

I have created a simple interface and its implementation and I would like to understand the type signatures. I guess these are not obvious because some transformations happen under the hood.

In the code below I have marked type signatures emitted by VSCode in different parts of the code for give, because in different parts these are different.

module Interfaces where
import Daml.Script

data GiveableView =
  GiveableView {viewIssuer : Party,  viewOwner : Party, viewId : Text }

interface Giveable where

  viewtype GiveableView

  give : Party -> Update (ContractId Giveable)
  -- ^ give : Giveable -> Party -> Update (ContractId Giveable)

  choice Give : ContractId Giveable
      newOwner : Party
    controller (view this).viewOwner
      give this newOwner

template Token
    tokenIssuer : Party
    tokenOwner : Party
    tokenId : Text
    signatory tokenIssuer
    interface instance Giveable for Token where
      view = GiveableView tokenIssuer tokenOwner tokenId

      give newOwner = do 
      -- ^ give : Party -> Update (ContractId Giveable)
        tokenCid <- create this with tokenOwner = newOwner
        return $ toInterfaceContractId tokenCid

test : Script (ContractId Giveable)
test = do
  alice <- allocatePartyWithHint "Alice" (PartyIdHint "Alice") 
  bob <- allocatePartyWithHint "Bob" (PartyIdHint "Bob") 

  tokenCid <- submit alice do
    createCmd (Token alice alice "AliceToken")

  submit alice do
    exerciseCmd (toInterfaceContractId @Giveable tokenCid) (Give bob)

In general, I know that Haskell treats field names as functions and the field data types specified in the record declaration syntax are actually the return types of these functions, but there are some missing puzzle pieces for me here.

This isn’t quite true, as you see if you try to call give in the body:

Interfaces.daml:34:24: error:
    • Couldn't match expected type ‘Giveable’ with actual type ‘Party’
    • In the first argument of ‘give’, namely ‘(undefined : Party)’

I’ll point out another case of this that will illustrate my broader point:

-- but
view: HasInterfaceView i v => i -> v
-- here i = Giveable, v = GiveableView

The broader point is that definitions as declared with = are at best advisory, not the final word on the defined variables’ type signatures. Just as you do not mention the typeclass constraints anywhere in the definition, there can be other inferred elements to the definition. Since those constraints are ultimately implemented by passing extra arguments, this isn’t as exotic as it might at first seem.

If you compare interfaces to classes here (cast away any Java leftovers and think purely of Daml/Haskell here), you can see the analogy in syntax. While you declare

class Foo a where
  x : a -> Int

Yet x : Foo a => a -> int. Likewise when you declare

interface Foo where
  x : Int

Yet x : Foo -> Int. Setting aside the syntactic differences due to the general power of typeclasses, the difference is merely that => changed to ->.

1 Like

After re-reading the docs and some thinking I think I can answer my own question. The main point seems to be the difference between methods and functions.

The use of methods and functions becomes confusing because Haskell doesn’t have proper method syntax as opposed to function syntax, unlike some other languages.

Here we have methods and corresponding functions, expressed by the same name, with the same syntax, but with a different number of arguments. The “method syntax” is that we simply omit the receiver (I guess it’s inferred from the context).

In the interface definition I declare the give method signature in the following way:

give : Party -> Update (ContractId Giveable)

If I hover over give in VSCode, in the popup I can see the type signature for the corresponding function:

give : Giveable -> Party -> Update (ContractId Giveable)

In the Give interface choice definition in the do block I use the give function:

give this newOwner

In the interface instance declaration, that is in the interface instance Giveable for Token where block I declare the give method like this:

give newOwner = do 
  tokenCid <- create this with tokenOwner = newOwner
  return $ toInterfaceContractId tokenCid

If I hover here over give in VSCode, in the popup I can see the method type signature: : Party -> Update (ContractId Giveable).

Is the answer that when I declare, I use the method syntax, and when I use, I use the function syntax?

This might be the case, but the way how VSCode displays the function signature for the method declaration in one place, and the method signature for the method declaration in another place, is still confusing.