onflow / cadence

Cadence, the resource-oriented smart contract programming language šŸƒā€ā™‚ļø
https://developers.flow.com/cadence
Apache License 2.0
531 stars 139 forks source link

Implement additional Array & Variable-size Array functions #2605

Open darkdrag00nv2 opened 1 year ago

darkdrag00nv2 commented 1 year ago

Issue to be solved

A few more functions can be implemented for Array and Variable-size Array types.

Suggested Solution

For [T] or [T; N], these include:

  1. reverse(): Reverses the array by mutating it. Available on both Array and Variable-size Arrays
  2. map<T: AnyStruct, U: AnyStruct>(_ f: (T: U)) : [U; N] and map<T: AnyStruct, U: AnyStruct>(_ f: (T: U)) : [U]. Will create a new Array without mutating
  3. transform<T: AnyStruct, U: T>(_ f: (T: U)) and transform<T: AnyStruct, U: T>(_ f: (T: U)). Will mutate the value. Some discussions happened in Discord on this.
  4. filter(_ pred: (T: Bool)) : [T]. Only available on variable-size Arrays. Will create a new value without mutating

1, 2 and 3 are taken from https://github.com/green-goo-dao/flow-utils/blob/main/cadence/contracts/ArrayUtils.cdc.

We could also add zip, flatten and others but I think they are not needed right now. We can wait for requests for those before implementing them.

Epic: https://github.com/onflow/cadence/issues/1972

turbolent commented 1 year ago

Good idea!

For functions that take a function which is passed the elements, e.g. map, transform and filter: For resource-kinded inputs, the callbacks can't be the resources themselves, but could be references, or the functions are not defined for such inputs (already done for other functions).

For transform in particular cannot exist for resource-kinded inputs: The result would overwrite the existing resource element, implicitly destroying it, which is not allowed.

For filter, the type parameter for U should be defined. Again, for resource-kinded inputs, the function should probably return references, or not be defined.

darkdrag00nv2 commented 1 year ago

Thanks for the insights.

For filter, the type parameter for U should be defined.

It was a typo. I meant to write T instead of U. Basically filter on [T] will also return [T].

darkdrag00nv2 commented 1 year ago

@turbolent I started looking into reverse.

In the issue, I've proposed that we mutate the array itself. To do that we probably need support for reverse in atree itself.

Alternatively, we can have the function return a new array with entries reversed (except for resources). Similar to what the function in https://github.com/green-goo-dao/flow-utils/blob/main/cadence/contracts/ArrayUtils.cdc does.

Thoughts?

turbolent commented 1 year ago

Starting with either variant works (mutating in-place or returning a new value)

It might be a good idea to name the functions accordingly, e.g. Swift has reverse for the in-place operation, and reversed for the one returning a new value (likewise, e.g. sort and sorted).

For the in-pace operation, there shouldn't be any need for support in atree, a simple loop over half the array swapping elements using the Cadence interpreter.ArrayValue functions like Get and Set should work.