# Mixed Type Types?

**URL:** <https://forum.flow.com/t/mixed-type-types/686>\
**Category:** 🏄🏻‍♀️ Cadence\
**Created:** [December 21, 2020, 10:06pm UTC](https://forum.flow.com/t/mixed-type-types/686 "2020-12-21T22:06:20Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![qvvg](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/qvvg/32/78_2.png) [@qvvg](https://forum.flow.com/u/qvvg)\
**Post date:** [December 21, 2020, 10:06pm UTC](https://forum.flow.com/t/mixed-type-types/686/1 "2020-12-21T22:06:20Z")

</div>

In a Cadence contract I have a function that has the ability to return the desired optional struct given an `address` and a `UInt64`.

```auto
import C from 0x___

pub fun main(address: Address, id: UInt64): C.ReadOnly? {
  return C.fetc(address: address, id: id)
}

```

From javascript (where `CODE` is the above) I can call the above like so:

```javascript
await fcl.send([
  fcl.script(CODE),
  fcl.args([
    fcl.arg("0x ____", t.Address),
    fcl.arg(72, t.UInt64)
  ])
]).then(fcl.decode)

```

I am trying to turn the above into a batch fetching, where given a list of `address`, `id` pairs I can return a list of the above results. Which is where I run into my issue that I need help with.  
An important additional constraint to keep in mind is there is no guarantee that the `address` and `id` are unique. **Can the smart people here think of a nice way of doing this?**

The following cadence is invalid (mixed-type array) but should be a way to convey what I am trying to do

```javascript
const WANT = [
  { key: "a", value: [addr1, id1] },
  { key: "b", value: [addr2, id2] },
  { key: "c", value: [addr2, id2] },
  { key: "d", value: [addr3, id3] },
]

const CODE = fcl.cdc`
  import C from 0x ____

  pub fun main(want: {String: [Address, UInt64]}): {String: C.ReadOnly?} {
    let result: {String: C.ReadOnly?} = {}
    for let w in want.keys {
      result[w] = C.fetch(address: w[0], id: w[1])
    }
    return result
  }
`

await fcl.send([
  fcl.script(CODE),
  fcl.args([
    fcl.arg(WANT, t.Dictionary({ key: t.String, value: t.Array([t.Address, t.Unit64]) }))
  ])
]).then(fcl.decode) // Would return something like { a: thing, b: thing, c: null, d: thing }

```

---

<div class="post-metadata">

**Author:** ![bastian](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/bastian/32/183_2.png) [@bastian](https://forum.flow.com/u/bastian)\
**Post date:** [December 21, 2020, 10:15pm UTC](https://forum.flow.com/t/mixed-type-types/686/2 "2020-12-21T22:15:24Z")

</div>

If you want to have values of various types in an array, you have to use a type that all values conform to. In your case, both `Address` and `UInt64` are value types (as opposed to resources), so they conform to `AnyStruct`.

A gotcha in Cadence is the type inference right now: An array is inferred to have the type of the first element, so you have to cast the first element to `AnyStruct`:

```auto
let address: Address = 0x1
let number: UInt64 = 1
let values: [AnyStruct] = [address as AnyStruct, number]

```

---

<div class="post-metadata">

**Author:** ![robmyers](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/robmyers/32/182_2.png) [@robmyers](https://forum.flow.com/u/robmyers)\
**Post date:** [December 21, 2020, 10:19pm UTC](https://forum.flow.com/t/mixed-type-types/686/3 "2020-12-21T22:19:06Z")

</div>

Ohh. Yes the type inference was tripping me up. Nice.

---

<div class="post-metadata">

**Author:** ![bastian](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/bastian/32/183_2.png) [@bastian](https://forum.flow.com/u/bastian)\
**Post date:** [December 21, 2020, 10:21pm UTC](https://forum.flow.com/t/mixed-type-types/686/4 "2020-12-21T22:21:58Z")

</div>

There’s an issue to improve the type inference for array literals, dictionary literals, and the ternary operator here: [https://github.com/onflow/cadence/issues/61](https://github.com/onflow/cadence/issues/61)

---

<div class="post-metadata">

**Author:** ![MaxStarka](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/maxstarka/32/56_2.png) [@MaxStarka](https://forum.flow.com/u/MaxStarka)\
**Post date:** [December 21, 2020, 10:33pm UTC](https://forum.flow.com/t/mixed-type-types/686/5 "2020-12-21T22:33:55Z")

</div>

Me, personally, would start with something like this:

```auto
const CODE = fcl.cdc`
  import C from 0x ____

  pub fun main(keys: [String], addresses: [Address], ids: [UInt64]} {
    let result: {String: C.ReadOnly?} = {}

    // This should be really in the JS code, but just for the sake of user we will check it here
    assert(keys.length == addresses.length && addresses.length == ids.length, "Arrays have different number of elements")

    var i = 0
    while i < keys.length {
        let key = keys[i]
        let address = addresses[i]
        let id = ids[i]
        result[key] = C.fetch(address: address, id: id) // we can make names optional if we are allowed to edit contract
        
        i = i + 1
    }

    return result
  }
`

const WANT = [
  { key: "a", value: [addr1, id1] },
  { key: "b", value: [addr2, id2] },
  { key: "c", value: [addr2, id2] },
  { key: "d", value: [addr3, id3] },
]

const { keys, addresses, ids } = WANT.reduce((acc, item) => {
    acc.keys.push(item.key);
    acc.addresses.push(item.value[0])
    acc.ids.push(item.value[1])
   
    return acc
   }, { keys: [], addresses: [], ids: [] })

await fcl.send([
  fcl.script(CODE),
  fcl.args([
    fcl.arg(keys, t.Array(String)),
    fcl.arg(keys, t.Array(Address)),
    fcl.arg(ids, t.Array(UInt64))
  ])
]).then(fcl.decode) // Would return something like { a: thing, b: thing, c: null, d: thing }

```

While it’s possible to create typecasting solution for mixed type array/dictionary, I think it’s overkill for a case with this constraints 🙂

---

<div class="post-metadata">

**Author:** ![qvvg](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/qvvg/32/78_2.png) [@qvvg](https://forum.flow.com/u/qvvg)\
**Post date:** [December 21, 2020, 10:34pm UTC](https://forum.flow.com/t/mixed-type-types/686/6 "2020-12-21T22:34:55Z")

</div>

For my own reference and as an update I was able to get this to work with this:

```javascript
const result = await fcl.send([
  fcl.script`
    pub struct Foo {
      pub let addr: String
      pub let id: UInt64

      init(addr: String, id: UInt64) {
        self.addr = addr
        self.id = id
      }
    }
    
    pub fun main(args: {String: [AnyStruct]}): {String: Foo} {
      let r: {String: Foo} = {}
      
      for key in args.keys {
        let addr: String = args[key]![0] as! String
        let id: UInt64 = args[key]![1] as! UInt64
        
        r[key] = Foo(addr: addr, id: id)
      }
      return r
    }
  `,
  fcl.args([
    fcl.arg([
      {key: "foo", value: ["rawr", 3]},
      {key: "bar", value: ["moo", 9]},
    ], t.Dictionary({ key: t.String, value: t.Array([t.String, t.UInt64]) }))
  ])
]).then(fcl.decode)

 assert(result, {
  "foo": {
    "addr": "rawr",
    "id": 3
  },
  "bar": {
    "addr": "moo",
    "id": 9
  }
})

```

Any hints or any thoughts on ways of making it cleaner? This code will be in the exemplar app?  
cc: @bastian @robmyers @MaxStarka

---

<div class="post-metadata">

**Author:** ![bastian](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/bastian/32/183_2.png) [@bastian](https://forum.flow.com/u/bastian)\
**Post date:** [December 21, 2020, 10:38pm UTC](https://forum.flow.com/t/mixed-type-types/686/7 "2020-12-21T22:38:40Z")

</div>

In my answer I mostly tried to focus on having values of different types in an array.

As to your concrete problem/code: I don’t think it’s a good idea to put this type-unsafe code in the exemplar app, what @MaxStarka showed is type-safer. Maybe replace `while i < 5` with the length of the `addresses`, and check the length of the `ids` matches the length of the addresses.

---

<div class="post-metadata">

**Author:** ![MaxStarka](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/maxstarka/32/56_2.png) [@MaxStarka](https://forum.flow.com/u/MaxStarka)\
**Post date:** [December 21, 2020, 10:43pm UTC](https://forum.flow.com/t/mixed-type-types/686/8 "2020-12-21T22:43:46Z")

</div>

That was a silly mistake, thanks for catching that one up, @bastian 😅  
I’ve replaced `5` with actual length of array and added `assert` to check that lengths of arrays match.

---

<div class="post-metadata">

**Author:** ![qvvg](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/qvvg/32/78_2.png) [@qvvg](https://forum.flow.com/u/qvvg)\
**Post date:** [December 21, 2020, 11:47pm UTC](https://forum.flow.com/t/mixed-type-types/686/9 "2020-12-21T23:47:35Z")

</div>

Yeah, I came up with a similar solution to @MaxStarka in my head already and was already probably going to go in that direction, was hoping there would be a nicer way of doing it though. It’s not really a solution I was (or still am) particularly excited/happy with. While splitting things up into three arrays and then using the script as a zip function works there is a heap of additional incidental complexity involved in both the expansion of the data in javascript and zipping of the data in cadence. Both solutions feel a little hacky, dirty and off, more of a “it will get the job done” kind of vibe and wouldn’t feel very proud if I were to recommend either of them as a solution to others, which the exemplar app is supposed to be… 😕

From a web app perspective we need batch fetching, from most of the contracts I have seen it’s most likely going to be an address of the resource owner, plus other things that act as some sort of cursor for lookup.

I’m in no way saying we need to hastily find a solution, or add some sort of new type to Cadence, more asking if we can have a think about this on our own, or keep it in the back of our minds so that when it comes up again (no way I will be the last one haha) we might have some answers ready or even a solution we can be proud of and recommend without hesitation.

Can any of us think of any other possible solutions to this batch problem? I worry that the initial code example might have added a bias to, or skewed the solutions a little. From a cadence perspective, @bastian are you able to say or give an example of a nice way of writing cadence to achieve a similar thing where the data remains grouped together? How should I go about thinking about how best to do this in cadence?
