Move Tuple and Either types to DA.Types (#1099)

* Add a helper function to qualify things with respect to a module

* Supress some warnings I saw when building

* Move Tuple* and Either to daml-prim:DA.Types, so they have a nice name for Java users (instead of GHC.Tuple or DA.Internal.Prelude)

* Add copyright header

* Update daml-foundations/daml-ghc/daml-prim-src/DA/Types.daml

Co-Authored-By: Martin Huschenbett <martin.huschenbett@posteo.me>

* Update daml-foundations/daml-ghc/daml-prim-src/DA/Types.daml

Co-Authored-By: Martin Huschenbett <martin.huschenbett@posteo.me>

* Update the daml-lf translation of tuple types

* Fix up the scala bindings for how to use types

* Clarify what action people need to take following the release notes

* Fix an expected test

* Clarify the changelogs even more

* Run ScalaFmt

* Clean up the release notes a bit

* Use the changelog from Beth

* Update the release notes again

* Update docs/source/support/release-notes.rst

Co-Authored-By: Gerolf Seitz <gerolf.seitz@digitalasset.com>

* Fix up the scenario error messages
This commit is contained in:
Neil Mitchell 2019-05-13 16:36:21 +01:00 committed by GitHub
parent 496cf5069f
commit ed431b4717
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 115 additions and 82 deletions

View File

@ -19,7 +19,7 @@ module Control.Exception.Base
import GHC.Base
import GHC.CString (fromString)
import GHC.Err
import GHC.Tuple
import GHC.Tuple()
import GHC.Types
-- List of errors inserted by GHC, copied from

View File

@ -0,0 +1,65 @@
-- Copyright (c) 2019 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
-- SPDX-License-Identifier: Apache-2.0
{-# LANGUAGE NoImplicitPrelude #-}
daml 1.2
-- | A module containing all the standard types from the base libraries,
-- so they have nice names when used from Java or similar.
module DA.Types
( Either (..)
) where
import GHC.Types()
-- | The `Either` type represents values with two possibilities: a value of
-- type `Either a b` is either `Left a` or `Right b`.
--
-- The `Either` type is sometimes used to represent a value which is
-- either correct or an error; by convention, the `Left` constructor is
-- used to hold an error value and the `Right` constructor is used to
-- hold a correct value (mnemonic: "right" also means "correct").
data Either a b = Left a | Right b
-- NOTE(MH): These types are not supposed to be used in DAML. The converter to
-- DAML-LF rewrites the types above to them, so they are visible to non-DAML users.
data Tuple2 a b =
Tuple2{_1 : a; _2 : b}
data Tuple3 a b c =
Tuple3{_1 : a; _2 : b; _3 : c}
data Tuple4 a b c d =
Tuple4{_1 : a; _2 : b; _3 : c; _4 : d}
data Tuple5 a b c d e =
Tuple5{_1 : a; _2 : b; _3 : c; _4 : d, _5 : e}
data Tuple6 a b c d e f =
Tuple6{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f}
data Tuple7 a b c d e f g =
Tuple7{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g}
data Tuple8 a b c d e f g h =
Tuple8{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h}
data Tuple9 a b c d e f g h i =
Tuple9{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i}
data Tuple10 a b c d e f g h i j =
Tuple10{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j}
data Tuple11 a b c d e f g h i j k =
Tuple11{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k}
data Tuple12 a b c d e f g h i j k l =
Tuple12{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l}
data Tuple13 a b c d e f g h i j k l m =
Tuple13{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m}
data Tuple14 a b c d e f g h i j k l m n =
Tuple14{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n}
data Tuple15 a b c d e f g h i j k l m n o =
Tuple15{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o}
data Tuple16 a b c d e f g h i j k l m n o p =
Tuple16{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o; _16 : p}
data Tuple17 a b c d e f g h i j k l m n o p q =
Tuple17{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o; _16 : p; _17 : q}
data Tuple18 a b c d e f g h i j k l m n o p q r =
Tuple18{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o; _16 : p; _17 : q; _18 : r}
data Tuple19 a b c d e f g h i j k l m n o p q r s =
Tuple19{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o; _16 : p; _17 : q; _18 : r; _19 : s}
data Tuple20 a b c d e f g h i j k l m n o p q r s t =
Tuple20{_1 : a; _2 : b; _3 : c; _4 : d; _5 : e; _6 : f; _7 : g; _8 : h; _9 : i; _10 : j; _11 : k; _12 : l; _13 : m; _14 : n; _15 : o; _16 : p; _17 : q; _18 : r; _19 : s; _20 : t}

View File

@ -58,6 +58,7 @@ import GHC.Prim
import GHC.Tuple
import GHC.CString (unpackCString#)
import GHC.Types
import DA.Types
infix 4 ==, /=, <, <=, >=, >
infixr 3 &&
@ -178,6 +179,8 @@ deriving instance (Eq a, Eq b, Eq c, Eq d, Eq e, Eq f, Eq g,
Eq h, Eq i, Eq j, Eq k, Eq l, Eq m, Eq n, Eq o)
=> Eq (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
deriving instance (Eq a, Eq b) => Eq (Either a b)
-- slightly strange encoding to avoid value level recursion
-- and to optimise so we avoid going through the dictionary lots of times
eqList :: (a -> a -> Bool) -> [a] -> [a] -> Bool
@ -289,6 +292,8 @@ deriving instance (Ord a, Ord b, Ord c, Ord d, Ord e, Ord f, Ord g,
Ord h, Ord i, Ord j, Ord k, Ord l, Ord m, Ord n, Ord o)
=> Ord (a, b, c, d, e, f, g, h, i, j, k, l, m, n, o)
deriving instance (Ord a, Ord b) => Ord (Either a b)
instance (Ord a) => Ord [a] where
compare [] [] = EQ
compare [] (_:_) = LT

View File

@ -17,8 +17,8 @@ module GHC.Num
import GHC.Base
import GHC.Classes
import GHC.CString
import GHC.Err
import GHC.CString()
import GHC.Err()
import GHC.Integer.Type
import GHC.Real
import GHC.Types

View File

@ -20,6 +20,8 @@ import GHC.Base
import GHC.CString (fromString)
import GHC.Tuple () -- We're using tuples but they are builtin syntax.
import GHC.Types
import GHC.Classes ()
import DA.Types
-- | The `shows` functions return a function that prepends the
-- output 'String' to an existing 'String'. This allows constant-time
@ -148,6 +150,7 @@ showCommaSpace = showString ", "
deriving instance Show ()
deriving instance Show Bool
deriving instance (Show a, Show b) => Show (Either a b)
instance Show Int where
show = primitive @"BEToText"

View File

@ -30,6 +30,7 @@ module GHC.Tuple() where
import GHC.CString () -- Make sure we do it first, so that the
-- implicit Typeable stuff can see GHC.Types.TyCon
-- and unpackCString# etc
import DA.Types() -- so that if we desugar a tuple the result is still found
default () -- Double and Integer aren't available yet
@ -61,45 +62,3 @@ data (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q) = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q)
data (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r) = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r)
data (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s) = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s)
data (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t) = (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t)
-- NOTE(MH): These types are not supposed to be by users. The converter to
-- DAML-LF rewrites the types above to them.
data Tuple2 a b =
Tuple2{_1 :: a; _2 :: b}
data Tuple3 a b c =
Tuple3{_1 :: a; _2 :: b; _3 :: c}
data Tuple4 a b c d =
Tuple4{_1 :: a; _2 :: b; _3 :: c; _4 :: d}
data Tuple5 a b c d e =
Tuple5{_1 :: a; _2 :: b; _3 :: c; _4 :: d, _5 :: e}
data Tuple6 a b c d e f =
Tuple6{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f}
data Tuple7 a b c d e f g =
Tuple7{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g}
data Tuple8 a b c d e f g h =
Tuple8{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h}
data Tuple9 a b c d e f g h i =
Tuple9{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i}
data Tuple10 a b c d e f g h i j =
Tuple10{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j}
data Tuple11 a b c d e f g h i j k =
Tuple11{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k}
data Tuple12 a b c d e f g h i j k l =
Tuple12{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l}
data Tuple13 a b c d e f g h i j k l m =
Tuple13{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m}
data Tuple14 a b c d e f g h i j k l m n =
Tuple14{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n}
data Tuple15 a b c d e f g h i j k l m n o =
Tuple15{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o}
data Tuple16 a b c d e f g h i j k l m n o p =
Tuple16{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o; _16 :: p}
data Tuple17 a b c d e f g h i j k l m n o p q =
Tuple17{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o; _16 :: p; _17 :: q}
data Tuple18 a b c d e f g h i j k l m n o p q r =
Tuple18{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o; _16 :: p; _17 :: q; _18 :: r}
data Tuple19 a b c d e f g h i j k l m n o p q r s =
Tuple19{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o; _16 :: p; _17 :: q; _18 :: r; _19 :: s}
data Tuple20 a b c d e f g h i j k l m n o p q r s t =
Tuple20{_1 :: a; _2 :: b; _3 :: c; _4 :: d; _5 :: e; _6 :: f; _7 :: g; _8 :: h; _9 :: i; _10 :: j; _11 :: k; _12 :: l; _13 :: m; _14 :: n; _15 :: o; _16 :: p; _17 :: q; _18 :: r; _19 :: s; _20 :: t}

View File

@ -21,6 +21,7 @@ import GHC.Integer.Type as GHC (fromInteger)
import GHC.Num as GHC
import GHC.Real as GHC (fromRational)
import GHC.Show as GHC
import DA.Types as GHC (Either(..))
import GHC.Tuple()
import GHC.Types as GHC (Bool (..), Int, Ordering (..), Text, Decimal, ifThenElse, primitive)
@ -280,16 +281,6 @@ optional n _ None = n
optional _ f (Some x) = f x
-- | The `Either` type represents values with two possibilities: a value of
-- type `Either a b` is either `Left a` or `Right b`.
--
-- The `Either` type is sometimes used to represent a value which is
-- either correct or an error; by convention, the `Left` constructor is
-- used to hold an error value and the `Right` constructor is used to
-- hold a correct value (mnemonic: "right" also means "correct").
data Either a b = Left a | Right b
deriving (Eq, Ord, Show)
instance Functor (Either e) where
fmap f (Left e) = Left e
fmap f (Right a) = Right (f a)

View File

@ -613,7 +613,7 @@ convertExpr env0 e = do
t1 <- convertType env t1
t2 <- convertType env t2
let fields = [(mkField f1, t1), (mkField f2, t2)]
tupleTyCon <- qGHC_Tuple env (mkTypeCon ["Tuple" ++ show (length fields)])
tupleTyCon <- qDA_Types env $ mkTypeCon ["Tuple" ++ show (length fields)]
let tupleType = TypeConApp tupleTyCon (map snd fields)
pure $ ETmLam (varV1, TTuple fields) $ ERecCon tupleType $ zipWithFrom mkFieldProj (1 :: Int) fields
where
@ -778,12 +778,10 @@ convertExpr env0 e = do
| Just m <- nameModule_maybe $ varName x
, Just con <- isDataConId_maybe x
= do
unitId <- convertUnitId (envModuleUnitId env) (envPkgMap env) $ GHC.moduleUnitId m
let qualify = Qualified unitId (convertModuleName $ GHC.moduleName m)
let qual f ('(':',':xs) | dropWhile (== ',') xs == ")" = qDA_Types env $ f $ "Tuple" ++ show (length xs + 1)
qual f ('$':'W':t) = qualify env m $ f t
qual f t = qualify env m $ f t
ctor@(Ctor _ fldNames _) <- toCtor env con
let renameCons ('(':',':xs) | dropWhile (== ',') xs == ")" = "Tuple" ++ show (length xs + 1)
renameCons ('$':'W':t) = t
renameCons t = t
-- NOTE(MH): The first case are fully applied record constructors,
-- the second case is everything else.
if | let tycon = dataConTyCon con
@ -796,17 +794,13 @@ convertExpr env0 e = do
-> fmap (, []) $ do
tyArgs <- mapM (convertType env) tyArgs
tmArgs <- mapM (convertExpr env) tmArgs
let tcon = TypeConApp (qualify (mkTypeCon [renameCons (is (dataConTyCon con))])) tyArgs
qTCon <- qual (mkTypeCon . pure) $ is (dataConTyCon con)
let tcon = TypeConApp qTCon tyArgs
pure $ ERecCon tcon (zip fldNames tmArgs)
| otherwise
-> fmap (, args) $ pure $ EVal $ qualify $ mkVal ("$ctor:" ++ renameCons (is x))
| Just m <- nameModule_maybe $ varName x = fmap (, args) $ do
unitId <- convertUnitId (envModuleUnitId env) (envPkgMap env) $ GHC.moduleUnitId m
pure $ EVal $
Qualified
unitId
(convertModuleName $ GHC.moduleName m) $
convVal x
-> fmap (, args) $ fmap EVal $ qual (\x -> mkVal $ "$ctor:" ++ x) $ is x
| Just m <- nameModule_maybe $ varName x = fmap (, args) $
fmap EVal $ qualify env m $ convVal x
| isGlobalId x = fmap (, args) $ do
pkgRef <- nameToPkgRef env $ varName x
pure $ EVal $ Qualified pkgRef (envLFModuleName env) $ convVal x
@ -1061,10 +1055,15 @@ convertModuleName :: GHC.ModuleName -> LF.ModuleName
convertModuleName (GHC.moduleNameString -> x)
= mkModName $ splitOn "." x
qGHC_Tuple :: Env -> a -> ConvertM (Qualified a)
qGHC_Tuple env a = do
qualify :: Env -> GHC.Module -> a -> ConvertM (Qualified a)
qualify env m x = do
unitId <- convertUnitId (envModuleUnitId env) (envPkgMap env) $ GHC.moduleUnitId m
pure $ Qualified unitId (convertModuleName $ GHC.moduleName m) x
qDA_Types :: Env -> a -> ConvertM (Qualified a)
qDA_Types env a = do
pkgRef <- packageNameToPkgRef env "daml-prim"
pure $ Qualified pkgRef (mkModName ["GHC", "Tuple"]) a
pure $ Qualified pkgRef (mkModName ["DA", "Types"]) a
convertQualified :: NamedThing a => Env -> a -> ConvertM (Qualified TypeConName)
convertQualified env x = do
@ -1089,7 +1088,7 @@ packageNameToPkgRef env =
convertTyCon :: Env -> TyCon -> ConvertM LF.Type
convertTyCon env t
| t == unitTyCon = pure TUnit
| isTupleTyCon t, arity >= 2 = TCon <$> qGHC_Tuple env (mkTypeCon ["Tuple" ++ show arity])
| isTupleTyCon t, arity >= 2 = TCon <$> qDA_Types env (mkTypeCon ["Tuple" ++ show arity])
| t == listTyCon = pure (TBuiltin BTList)
| t == boolTyCon = pure TBool
| t == intTyCon || t == intPrimTyCon = pure TInt64

View File

@ -23,7 +23,7 @@ isInternal :: GHC.ModuleName -> Bool
isInternal (GHC.moduleNameString -> x)
= "DA.Internal." `isPrefixOf` x ||
"GHC." `isPrefixOf` x ||
x `elem` ["Control.Exception.Base", "Data.String", "LibraryModules"]
x `elem` ["Control.Exception.Base", "Data.String", "LibraryModules", "DA.Types"]
mayImportInternal :: [GHC.ModuleName]
mayImportInternal = map GHC.mkModuleName ["Prelude", "DA.Time", "DA.Date", "DA.Record", "DA.TextMap"]

View File

@ -13,7 +13,7 @@
}
},
"source": "Scenario",
"message": "Scenario execution failed on commit at Main:28:5:\n #0: create of Main:Agree at DA.Internal.Prelude:372:1\n failed due to a missing authorization from 'Alice'\n\nLast source location: DA.Internal.Prelude:372:1\n\nLedger time: 1970-01-01T00:00:00Z\n\nPartial transaction:\n Sub-transactions:\n #0\n └─> create Main:Agree\n with\n p1 = 'Foo'; p2 = 'Alice'"
"message": "Scenario execution failed on commit at Main:28:5:\n #0: create of Main:Agree at DA.Internal.Prelude:363:1\n failed due to a missing authorization from 'Alice'\n\nLast source location: DA.Internal.Prelude:363:1\n\nLedger time: 1970-01-01T00:00:00Z\n\nPartial transaction:\n Sub-transactions:\n #0\n └─> create Main:Agree\n with\n p1 = 'Foo'; p2 = 'Alice'"
}
],
"file:/tests/diagnostics/scenario-error/Prelude.daml": [],

View File

@ -59,12 +59,14 @@ class DarReaderTest extends WordSpec with Matchers with Inside {
"GHC.Enum",
"GHC.Show",
"GHC.Num",
"DA.Types",
"GHC.Classes",
"Control.Exception.Base",
"GHC.Tuple",
"GHC.Err",
"GHC.Base",
"LibraryModules")
"LibraryModules"
)
}
}

View File

@ -51,14 +51,14 @@ Tuple types
DAML tuple type constructors take types ``T1, T2, …, TN`` to the type ``(T1, T2, …, TN)``. These are exposed in the DAML surface language through the :ref:`Prelude <stdlib-reference-base>` module.
The equivalent DAML-LF type constructors are ``ghc-prim:GHC.Tuple:TupleN``, for each particular N (where 2 <= N <= 20). This qualified name refers to the package name (``ghc-prim``) and the module name (``GHC.Tuple``).
The equivalent DAML-LF type constructors are ``daml-prim:DA.Types:TupleN``, for each particular N (where 2 <= N <= 20). This qualified name refers to the package name (``ghc-prim``) and the module name (``GHC.Tuple``).
For example: the DAML pair type ``(Int, Text)`` is translated to ``ghc-prim:GHC.Tuple:Tuple2 Int64 Text``.
For example: the DAML pair type ``(Int, Text)`` is translated to ``daml-prim:DA.Types:Tuple2 Int64 Text``.
Data types
**********
DAML-LF has two kinds of data declarations:
DAML-LF has two kinds of data declarations:
- **Record** types, which define a collection of data
- **Variant** or **sum** types, which define a number of alternatives

View File

@ -12,6 +12,15 @@ HEAD — ongoing
DAML
~~~~
- **BREAKING CHANGE - DAML Standard Library**: Moved the ``Tuple`` and ``Either`` types to ``daml-prim:DA.Types``
rather than exposing internal locations.
How to migrate:
- You don't need to change DAML code as a result of this change.
- People using the Java/Scala codegen need to replace ``import ghc.tuple.*`` or ``import da.internal.prelude.*`` with ``import da.types.*``.
- People using the Ledger API directly need to replace ``GHC.Tuple`` and ``DA.Internal.Prelude`` with ``DA.Types``.
- **DAML Standard Library**: Add ``String`` as a compatibility alias for ``Text``.
Ledger API

View File

@ -41,8 +41,8 @@ class CodeGenExampleSpec extends WordSpec with Matchers {
}
"create contract with tuple should compile" in {
import com.digitalasset.sample.{MyMain, GHC}
val ct = MyMain.Twoples(alice, GHC.Tuple.Tuple2(1, 2))
import com.digitalasset.sample.{MyMain, DA}
val ct = MyMain.Twoples(alice, DA.Types.Tuple2(1, 2))
val createCommand = ct.create
sendCommand(createCommand)
}