Hi,
Sorry for the basic question, but I can’t find it in the doc … if I have a data type that i need to be in a Set , is there (like for a template) a way to indicate what attributes compose a Key?
data MyElem = MyElem with
foo: Text
bar: Text
something: Int
somethingelse: Party
deriving (Eq, Show)
How can I have Set MyElem
Sets (DA.Next.Set) are implemented as Maps. Set MyElem is just Map MyElem (). DAML currently only has native maps with text keys (type TextMap. So the Map and Set implementations in DA.Next.Set and DA.Next.Map require one to write serialization and deserialization code to Text.
You can use show as serialization, but then have to write parsing code, which is non-trivial.
This is clearly awkward so we have “Generic Maps” and thus also Generic Sets on our roadmap. You can already test Generic Maps as follows:
Set your project to build DAML-LF 1.dev (which will eventually become 1.9) by adding this to your daml.yaml:
build-options:
- --target=1.dev
Then import DA.Map in your project, add Ord to the list of typeclasses derived by MyElem and treat Map MyElem () as your set. The DA.Set wrapper library doesn’t exist yet, but it would be an easy adaption from daml/Set.daml at a080b47e347277e099167fc59affde9dac313342 · digital-asset/daml · GitHub.
2 Likes
I feel the need to point out that any dar produced using --target=1.dev is very much not supported for any kind of production use. Even just uploading it to a persistent ledger is likely to break things. This is really just meant for dev; please only upload such dars to throwaway ledgers.
While there is a point at which we will create a DAML LF 1.9, it would certainly not be safe to assume 1.9 will be exactly what 1.dev is today, nor a strict superset of it.
1 Like
So, are you saying that the ordering determines the keys used for hashing, in answer to OP? I expect I’ve misunderstood this, but if not, isn’t this a pretty hefty constraint? Is it not enough to have some sort of a Hashable typeclass?
Would this mean that in OP’s example, you’d need to write an instance Ord that then picks which particular field to order on - i.e. using deriving Ord in this particular case wouldn’t work?
Btw. is Ord a total order?
1 Like
I’m not in the loop on the specific work for the new DA.Map, but I think I can offer some elements of an answer nonetheless.
First off, yes, the Ord typeclass is intended to represent a total order. deriving Ord, when it works, does that.
Regarding the requirement for Ord, while one could argue it is not, strictly speaking, a requirement to store something in an associative data structure, and a Hashable typeclass could do the trick if the underlying implementation were indeed a hash table, it’s also possible to implement maps (and sets) using binary trees based on ordering the given elements, as is the case for Data.Set in Haskell. Based on @bernhard’s stated requirement to add Ord, I suspect the current prototype for DA.Map is based on similar techniques.
2 Likes
@Jean_Safar
Something like this is what you’re looking for
import DA.Text
-- We need a separator character that is not in either of our text fields
-- nor a digit
-- nor a Party (https://github.com/digital-asset/daml/blob/ba74146c10d149687d7f42972a9ced6203c3f807/daml-lf/spec/daml-lf-1.rst#literals)
sep : Text
sep = ";"
instance M.MapKey MyElem where
keyToText c = c.foo
<> sep <> c.bar
<> sep <> M.keyToText c.something
<> sep <> M.keyToText c.somethingelse
keyFromText t = case splitOn sep t of
[ foo, bar, somethingT, somethingelseT] ->
MyElem with
foo
bar
something = M.keyFromText somethingT
somethingelse = M.keyFromText somethingelseT
_ -> error $ "Malformed key" <> t
2 Likes
Note that this "; can never be used in a string ever" is likely to bite you in the future. If adding an Ord instance does not work for you, and you really need to support translation to and from a text format, I’d recommend implementing a simple string-based replacement à la htmlencode: on the way in, replace ; with &semicolon and & with &, and do the opposite on the way out. Then you know there is no ; in the encoded strings and you can safely use that as a delimiter.
2 Likes
Let me add some clarification around the upcoming generic map type:
Together with the generic Map type, DAML-LF has gained a builtin generic comparison function. This works for roughly anything that is serializable (not quite accurate but a decent approximation). For incomparable values, e.g., functions, this throws a runtime error.
For DAML, we want to prevent invalid values statically. Currently, this is accomplished by requiring an Ord instance. However, the Ord instance will not actually be used by the map. Instead it will use DAML-LF’s builtin notion of equality. Since nothing stops you from defining an Ord instance for a record containing a function, you can technically still produce something that crashes.
Having two notions of ordering is rather confusing so there is an open question here if it would be better to forbid user-defined Ord instances to make sure that Ord instances always match up with the builtin notion of equality which is also much faster.