Decoder types for Java codegen
See original GitHub issueWhat 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 ValueDecoder
s 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 Value
s 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:
- Created a year ago
- Comments:6 (6 by maintainers)
Top GitHub Comments
@digital-asset/ledger-clients any objections if I rename the interface form
FromValue
toValueDecoder
?@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.