Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide contract choice metadata as constants in contract's class #14329

Closed
StephenOTT opened this issue Jul 2, 2022 · 13 comments · Fixed by #15116
Closed

Provide contract choice metadata as constants in contract's class #14329

StephenOTT opened this issue Jul 2, 2022 · 13 comments · Fixed by #15116
Assignees
Labels
component/java-ecosystem Java development experience ledger clients facade enriching the ledger API by bindings/codegen, JSON API, custom view team/ledger-clients Related to the Ledger Clients team's components.

Comments

@StephenOTT
Copy link
Contributor

StephenOTT commented Jul 2, 2022

What is the problem you want to solve?

The upcoming deprecated exercise by key command currently hard codes the choice name such as:

...

  public static ExerciseByKeyCommand exerciseByKeyCreateManager(String key,
      CreateManager arg) {
    return new ExerciseByKeyCommand(Organization.TEMPLATE_ID, new Party(key), "CreateManager", arg.toValue());
  }

..

The choice name is hard coded and cannot be referenced / re-used.

If I create the command manually I would use:

ExerciseCommand(Organization.TEMPLATE_ID, "someContractId", "CreateManager", args)

But again I have to know about the choice name and if the choice name changed in the future, compile time errors would not appear.

What is the solution you would propose?

Could we get the choice names on a contract as constants (or some equivalent) so we can insert them as references?

It would also be helpful to have some contextual information about choices, such as is it a consuming or non-consuming, etc choice, so we can code around expected behaviour: example knowing it is a consuming choice can mean we remove it from the UI on submission (and re-add it if command eventually fails), vs non-consuming we would never remove it.
But would settle for just have the constants to start!

@stefanobaghino-da
Copy link
Contributor

I'm not sure I'm following what you want to achieve here. The point of the generated classes is not that of returning something you can re-use separately, but rather to fit with a Daml model that exists. What you're proposing seems to be something in which you want to create code to then manually assemble exercises, but I fail to see the point of this if you can just have a method that returns the exercise command you want to send.

@stefanobaghino-da stefanobaghino-da added component/java-ecosystem Java development experience discussion Things to be discussed and decided team/ledger-clients Related to the Ledger Clients team's components. labels Jul 4, 2022
@StephenOTT
Copy link
Contributor Author

@stefanobaghino-da if I follow the examples

https://github.com/digital-asset/ex-java-bindings/blob/633d2d935ae2c4fa691e124f9eaec4a78d43532a/src/main/java/examples/pingpong/grpc/PingPongProcessor.java#L149

the examples have the choice string manually written.

Is there choice methods generated for every choice?

even if generated, having the choice name as a accessible variable/const would be helpful for reuse, testing etc.

Generated classes can provide a second valuable function: to parse the daml file so code can be built from it. For example, maybe I want to monitor the transactions for a specific exercising of a choice, it would be nice to reference the choice name from the const instead of looking it up in the daml and re-writing it. If the value ever changed then I would be able to easily note/watch for the change of the const value in the generated code.

@stefanobaghino-da
Copy link
Contributor

the examples have the choice string manually written.

I understand the point about the examples, but that to me is more of a pointer of the fact that we should do some work with regards to our examples (which were first authored before the first version of the codegen), rather than encourage working without generated code.

Is there choice methods generated for every choice?

Yes.

even if generated, having the choice name as a accessible variable/const would be helpful for reuse, testing etc.

Can you expand on what would be the advantage of generating constants for choice names, since you can access any of those through a method call?

Generated classes can provide a second valuable function: to parse the daml file so code can be built from it.

Parsing Daml files is discouraged. Our codegen decouples from the surface language by using the Daml-LF intermediate format, which is designed for this.

For example, maybe I want to monitor the transactions for a specific exercising of a choice, it would be nice to reference the choice name from the const instead of looking it up in the daml and re-writing it. If the value ever changed then I would be able to easily note/watch for the change of the const value in the generated code.

This makes sense during the development workflow and could be a good argument towards considering this, but keep in mind that changing your choice names is something that should not be done lightly, since it represents a breaking change in Daml code and ultimately in the signature you expose through the Ledger API.

@S11001001 @ray-roestenburg-da Thoughts?

@StephenOTT
Copy link
Contributor Author

@stefanobaghino-da even something like: "You index/store the transactions and you want to query for specific moments where a choice was exercised." It comes back to having a "golden source" for the choice name. Maybe you want to validate that the choice is even possible before checking the index, so you need some source of choice names.

Parsing Daml files is discouraged. Our codegen decouples from the surface language by using the Daml-LF intermediate format, which is designed for this.

I was suggesting that your current codegen is already doing the parsing of the daml files / generates the code. From the generated code (from the daml codegen), there can be other code generation that occurs at later stages (both compile time and runtime): storage, indexing, UI generation, api request validations, etc.

As you suggest, there may be a helper method for each choice, but someone may wish to write a single method that can execute any of the available choices, so could use the lower level builder and it would be better to use a reference to a name instead of manually re-typing it. (same idea for writing tests)

@StephenOTT
Copy link
Contributor Author

StephenOTT commented Jul 4, 2022

Is there choice methods generated for every choice?

Yes.

@stefanobaghino-da can you explain this further? Where are methods generated for every choice?

As far as i can tell, only templates with keys have their choices generated as methods in the template's class. If it is Template without a key, then no methods are generated. (2.2.0)

Okay found the confusion here. The exerciseByKey commands are at the Template level, but you need to navigate into SomeTemplate.ContractId(someId).exercise..., Would seem to be better to have a SomeTemplate.Key(someKey).exercise.

Even with the methods generated it would be nice to have these values available so they can be passed into other tooling as described above.

@StephenOTT
Copy link
Contributor Author

Building on this further: https://discuss.daml.com/t/getting-all-choices-for-a-given-party-or-contract/4830/4. This discussion on how to get the list of choices is a good example of why we should have the choice names in the generated code. There is a lot of hoops to jump through to get a simple list of choices.

by giving the devs the ability to meta program you enable the community to build more capabilities instead of waiting for DA to build everything.

@S11001001 S11001001 changed the title Provide contract choice names as constants in contract's class. (Java bindings) Provide contract choice names as constants in contract's class Jul 5, 2022
@S11001001
Copy link
Contributor

I suggest we codegen for each choice

// one for each choice
public static final ChoiceMetadata<Tpl, ArgType, ResType> CHOICE_Iou_Transfer = ...

ChoiceMetadata can just contain whatever we have at hand in the codegen, but err on the side of fewer fields rather than everything we have. The three tparams can be phantom unless/until we think of something good to use them for. ContractCompanion can be extended with a Map<String, ChoiceMetadata<Data, ?, ?>>, so retrievable through the static COMPANION on each template class.

@stefanobaghino-da
Copy link
Contributor

@S11001001 What would be the overlap with #12897 (comment)?

@S11001001
Copy link
Contributor

@stefanobaghino-da The suggested implementations pretty much completely overlap.

I should note, however, that for the typical choice exerciser, #14312 is likely to be a lot nicer to use for the restricted case of decoding the result (because if you line the utilities up, you can largely forget that encoding/decoding is happening at all). Which might be a better solution to #12897, depending on what the exercise code looks like.

@S11001001
Copy link
Contributor

@stefanobaghino-da Let's say that you are inspecting a transaction stream. There are a few tools you can build nicely on top of ChoiceMetadata, given enough "stuff" in the metadata:

  1. Identify an exercise event of a choice that matches a given expected choice from codegen. You can use the name and template ID for this.
  2. Having found such an event, decode the choice argument. This would hang off the ArgType tparam.
  3. Likewise, decode the exercise result. This would hang off the ResType tparam.

@stefanobaghino-da
Copy link
Contributor

@leonidr-da @asarpeshkar-da @juliuswilliam-da I would like to have your feedback with regards to this and whether it would help you with the issue outlined in #12897 and https://discuss.daml.com/t/extracting-choice-return-type-defined-in-daml-templates-as-a-java-type/4666.

@S11001001 S11001001 added the ledger clients facade enriching the ledger API by bindings/codegen, JSON API, custom view label Aug 22, 2022
@S11001001 S11001001 changed the title Provide contract choice names as constants in contract's class Provide contract choice metadata as constants in contract's class Aug 22, 2022
@S11001001
Copy link
Contributor

TypeScript has a sort of counterpart to this ChoiceMetadata proposal in the Choice type.

* @typeparam T The template type.
* @typeparam K The contract key type.
* @typeparam C The choice type.
* @typeparam R The choice return type.
*
*/
export interface Choice<T extends object, C, R, K = unknown> {

Of note, the C and R tparams can be used to drive argument encoding and result decoding in the way I've described for ArgType and ResType above:

async exercise<T extends object, C, R, K>(
choice: Choice<T, C, R, K>,
contractId: ContractId<T>,
argument: C,
): Promise<[R, Event<object>[]]> {

@S11001001
Copy link
Contributor

With #15116 merged, the example in description can be written as

-ExerciseCommand(Organization.TEMPLATE_ID, "someContractId", "CreateManager", args)
+ExerciseCommand(Organization.TEMPLATE_ID, "someContractId", Organization.CHOICE_CreateManager.name, args)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component/java-ecosystem Java development experience ledger clients facade enriching the ledger API by bindings/codegen, JSON API, custom view team/ledger-clients Related to the Ledger Clients team's components.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants