-
Notifications
You must be signed in to change notification settings - Fork 205
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
Variant constructor matching (w/o argument) differs depending on package structure #7207
Comments
This is a problem with the expressivity of variant types at the DAML-LF level, since there's no distinction between "variant constructor with no inputs" and "variant constructor with a single input of unit type" at the DAML-LF level, as is documented in the official docs. Perhaps it would be best to pick the other default in data-dependencies? I.e. to translate all "variant constructor with a single input of unit type" into "variant constructor with no inputs". Either way, one of these two will always be translated back into DAML incorrectly in data-dependencies, unless we change something more fundamental about how types are translated into DAML-LF or represented on the ledger API. This would be a breaking change for existing projects that rely on data-dependencies. cc @bame-da |
If you changed the behaviour in a new DAML-LF version (eg 1.9) so that data-dependencies of LF >= 1.9 packages behaved properly by distinguishing the two cases, think this could be called a bug-fix. Despite being documented, the behaviour @jberthold-da is observing looks sufficiently buggy/broken, and the case where this would affect anyone (recompiling to a new LF version and then using that as a data-dependency) is sufficiently unlikely. |
I agree this behaviour is not ideal, but I do not think we should complexity LF. LF variants are unary, making the argument of a variant optional is almost as complex as making them n-nary. |
Ok, so, after looking into this and talking with @remyhaemmerle-da, it looks like we could change the way we're compiling variants, so that "variant constructors of no input" end up as synthetic variant-record constructors where the record has no fields. We should gate this change by LF version at least, since it's going to affect people who currently use data-dependencies or the ledger api. (That all said, multi-package projects with access to the original source code should not rely on data-dependencies when possible, since it's at best an approximation of the original types.) |
But obviously we need to data-dependencies when data needs to migrate during an upgrade to a newer SDK version, or not?
But that would still require a trailing |
Yes, you're right. There should be an effort to minimize how much goes in data-dependencies (vs. dependencies), but type definitions usually need to be in data-dependencies, so my point wasn't very relevant. Sorry for bringing it up.
No, I don't think so. When a constructor has no arguments, As a workaround for now, you can actually use f : AVariant -> Text
f x = case x of
V1 i -> "V1"
V2 {} -> "V2" |
That works for the match, thanks. The problem reaches further, though, I also want to construct values using |
Maybe worthwhile to note: The change of arity of this constructor only happens when the original package is depended upon as a data dependency. When using a full dependency the constructor match and value without argument compiles fine. |
Yes, this is expected. "dependencies" use GHC's built-in mechanism (interface files) so you have all information from the original package, whereas "data-dependencies" go back from built DALF files, and try to provide a DAML interface to LF code by adding stubs. It is at best an approximation of the original interface, and should, at this point, be thought of as something similar to using the ledger API or language bindings.
I've been implementing this and it looks like a bigger change than I thought, and wouldn't be surprised if it broke a lot of existing code. I would be a lot more comfortable with my first proposed solution -- to change the default way of translating DAML-LF variants with unit constructors back into DAML types, so that you get a constructor with no argument instead of a constructor with a unit argument. We could even deprecate variant constructor with unit arguments from DAML, since they have dubious utility, like we did for record types whose constructor name doesn't match the type name (because it doesn't have a representation at the LF level). cc @hurryabit |
I agree with the suggestion to deprecate variant constructors with a single unnamed argument of type |
This fixes #7207 and adds a regression test. In a separate PR I'll add a warning for variants with single argument of unit type and add a changelog entry. changelog_begin changelog_end
* Preserve empty variant constructor in data-deps. This fixes #7207 and adds a regression test. In a separate PR I'll add a warning for variants with single argument of unit type and add a changelog entry. changelog_begin changelog_end * Add special case for single constructor variants * Add test for special case
When working with multiple DAML packages imported into one another, I found that variant constructors without arguments take a unit argument when imported from another package, but take no argument when used in the same package. The following example shows the problem:
Package 1 contains this module with a variant definition and a function
f1
with a case match on the variantPackage 2 contains a module which imports
Package1File
and contains an identical functionf2
:Note that the match on
V2
uses a_
for an uninteresting argument.This example code compiles when distributed into two packages, but
f2
is incorrect when it resides inside the first package.The text was updated successfully, but these errors were encountered: