question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Decoder types for Java codegen

See original GitHub issue

What is the problem you want to solve?

The core decoders in Java codegen look like this:

public static <a> MyDT<a> fromValue(Value value, Function<Value, a> fromValuea) {}

Where there is one type parameter and fromValue* argument per type parameter in the Daml datatype definition.

It’s true that a Function<Value, MyDT<a>> can be derived from this, but not in a way that is pleasant to use, and not in a way that can solve a problem like #14299: fromValuea cannot be used to reach the constructor for a.ContractId. Additionally, decoders for primitive types are always generated as inline lambdas; users who want to invoke fromValue on parameterized types must reinvent these.

What is the solution you would propose?

Basically, reorder the arguments.

Introduce an analogue to ValueDecoder from Scala codegen:

@FunctionalInterface
public interface FromValue<A> {
  A fromValue(Value value);

  default ContractId<A> fromContractId(String contractId) {
    // throw IAE or return "generic" cid, not sure which is best
  }
}

and codegen these instead:

<a> FromValue<MyDT<a>> fromValue(FromValue<a> fromValuea)

Supply a library of constants of these, one for each primitive type. In FromValueGenerator, refer to these constants instead of generating lambdas. The one for ContractId<a> will not be a constant, but instead be parameterized by FromValue<a> and use its fromContractId method to produce the final value.

Likewise, for Daml data types, generate direct calls to these instead of lambdas. To avoid infinite recursion, do not invoke fromValue for fields eagerly unless you have proved that the fromValue call is acyclic; otherwise, invoke the recursive fromValue calls from within the generated fromValue lambda. (This is implicitly how generated ValueDecoders work in Scala codegen.)

For templates T, generate an @Override for fromContractId that effectively encapsulates new T.ContractId. This will reduce the strange mismatch between T.ContractId and ContractId<T> explained in #14299.

ContractCompanion<Ct, Id, Data> should either have a method to return a FromValue<Data> or implement FromValue<Data> itself. It already has all the tools needed to include this extension, which has been the intended upshot of changes to Java codegen since #13724.

Deprecate the prior fromValue methods, and change how they are generated to be implemented in terms of constructing and applying an appropriate FromValue.

Describe alternatives you’ve considered

It is possible to solve only the contract ID casting problem in #14299 by defining a nominal subclass of Function<Value, a> and using that for the fromValuea argument. Decoding a contract ID would look like

(fromValuea instanceof TemplateFromValue)
  ? ((TemplateFromValue<a>) fromValuea).fromContractId(fields$.get(0))
  : /* fallback case for non-template fromValue */

However, a simplified combinator language as suggested in this issue helps to solve other problems, by making the language for assembling decoders, such as suggested for #14312, more intuitive. For example, to decode a ParametrizedContractId<Iou>, you will write something like

// infers type ValueDecoder<ParametrizedContractId<Iou>>
var decoder = ParametrizedContractId.fromValue(Iou.fromValue());
decoder.fromValue(somethingFromBindings);

As such, it should enable more readily integrated use of codegen-generated types with the arbitrary Value types from the bindings.

Additional context

This arose out of thinking about the commonalities between #14299 and #14312, as well as discussion of the observation that many Java bindings users are hand-parsing and assembling Values rather than taking full advantage of translation to generated Java models for their Daml.

The placement of fromContractId is inspired by showList from Haskell Show, and readList from Read for that matter; the problem it solves is very similar, if you think about it in terms of “factoring code causes different things to happen”.

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
chunlokling-dacommented, Sep 15, 2022

@digital-asset/ledger-clients any objections if I rename the interface form FromValue to ValueDecoder?

1reaction
S11001001commented, Sep 13, 2022

@chunlokling-da Please feel free to bikeshed the name for the interface FromValue, either yourself or with the team. I just named it after the function without further thought.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Generate Java code from DAML
To achieve this, you can use DAML to Java code generator (“Java codegen”) to generate Java types based on a DAML model.
Read more >
VE Source Editor / Code Generation (CodeGen) component
Decoders are responsible for decoding the Java AST expression contained in a CodeExpressionRef and for making the appropriate updates to the VE ...
Read more >
ASN1C ASN.1 to Java Code Generation - Objective Systems
Generated Java encoders/decoders and run-time are a 100% pure Java solution for encoding an decoding ASN. 1-based messages. The generated Java code consists...
Read more >
[Swift] handle decoding of unknown enum types if optional
Description If I have a model class, say vehicle which has an enum 'type' which can have two values, 'car' and 'motorbike'.
Read more >
getquill/quill - Gitter
Decoder [AuthorizedSession] = deriveDecoder[AuthorizedSession] val ctx = app.init.Init.postgres. ... mkString("/")}") package codegen import java.sql.Types.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found