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
with
newOwner : Party
controller (view this).viewOwner
do
give this newOwner
template Token
with
tokenIssuer : Party
tokenOwner : Party
tokenId : Text
where
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.
-- ^ give : Party -> Update (ContractId Giveable)
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:
view = GiveableView tokenIssuer tokenOwner tokenId
-- 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 ->.
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.