How does the query function used like query @BankAccount bank
fit to the type (Template t, HasAgreement t, IsParties p) => p -> Script [(ContractId t, t)]
(as defined in the docs) ? I don’t understand how this type maps to the usage.
First, a couple important pieces of documentation that you should take a look at if you have not yet had a chance to:
- Basics on constraints (worth reading the whole 101 page if you have not seen it before)
- more about what the part before
=>
means
With that background, you’ll be well-equipped to understand the following: query @BankAccount bank
sets the type argument t
to BankAccount
, and the first function value argument to bank
.
The underlying concept is called Visible type application and allows to provide explicit type arguments to a function. This was discussed earlier in this forum here: I've just discovered what the `@<template_name>` notation in functions like `fetchByKey` et al means
In this particular case, the function query
comes with two type parameters t
and p
, which can be specified with the @
-notion and correspond to the order defined by the function. You could technically write query @BankAccount @Party bank
, resulting in the same, although that is not necessary since only t
is ambiguous when not defined.
So, in the function call query @BankAccount bank
, the type constraint (Template t, HasAgreement t, IsParties p)
applies to the whole function (not just a parameter), and bank
is an instance of IsParties
, which satisfies the last type constraint. Because we need to satisfy the first two constraints, we add @BankAccount
in front of the argument bank
which points to the BankAccount
template and that is of type Template BankAccount
and an instance of HasAgreement BankAccount
. Does that sound right?
Rather, bank
’s type has an instance of IsParties
. Constraint resolution is 100% static. Types are members of typeclasses; expressions and values are not, but they are related to types in other ways.
While we need to satisfy the first two constraints, the real reason is that t
is usually difficult to infer here. For example, if later in the function you pass the payload to a function that is declared explicitly to take a BankAccount
, or you destructure the payload using the BankAccount{..}
form, then that’s enough information to let you remove the @BankAccount
argument.
But typically you are merely accessing properties with .prop
syntax or exercising choices, and these aren’t enough to disambiguate what type your code could be referring to.
By contrast, consider that the type variable p
is very easy to infer from context.