---
# System prepended metadata

title: Alternative approach for dynamic views
tags: [views]

---

---
title: Alternative approach for dynamic views
tags: views
description: specification, test cases
---
[toc]

# MAIN: Alternative approach for dynamic views

This is an alternative approach for dynamic views where the new instruction will take an additional `'arg` argument to parametrize its behavior. This will make it easier for the caller of the dynamic view to reuse the view lambda.

The type of `VIEW_EXEC` is:

```
:: lambda (pair 'arg 'storage_ty) 'return : 'arg : address : 'S ->  option 'return : 'S
```
- `lambda (pair 'arg 'storage_ty) 'return`: The lambda that we apply to the target contract's storage `'storage_ty` to retrieve a value `'return`. The argument `'arg` is used to parametrizes the behavior of the lambda.
- `address`: The target contract address.
- `option 'return`: The value retrieved from the target contract. Returns `None` if failed.

The semantics of `VIEW_EXEC` is:

```
> VIEW_EXEC / code : arg : addr : S => Some v : S
        iff
          addr is the address of the target smart contract
           with storage s of type 'storage_ty
         and code / Pair arg s : [] => v : []

> VIEW_EXEC/ _ : _ : _ : S => None : S
   otherwise
```

### Example
Suppose we have a contract that looks like below:

```
# contract_a

parameter unit;
storage (pair int int) # result (int 2, int 3)
code { 
    CDR;
    UNPAIR;
    CAR;
    ADD; # assume it returns 2
    PUSH int 3;
    PAIR;
    NIL operation;
    PAIR;    
}
```

Suppose we want to write a `contract_b` that fetches either first or second element of `contract_a`'s storage based on the argument passed in run time.

Using the new `VIEW_EXEC` instruction, we can write:

```
# contract_b
parameter address;
storage int;
code {
  CAR; # get address
  
  # this is an 'arg, push left to fetch the first element.
  PUSH (or unit unit) (LEFT unit);
  
  # lambda takes (or unit unit) as para
  LAMBDA (pair (or unit unit) (pair int int)) int 
     { 
      UNPAIR; 
      # lambda chooses CAR left branch base on the input 'arg above
      IF_LEFT { CAR; } { CDR; } 
     }; 
  
  VIEW_EXEC; # result: Some int 2
  
  IF_NONE {PUSH string "view call failed"; FAILWITH} {};
  NIL operation;
  PAIR;
}
```

## Comparison with the main proposal

### Pros of alternative:
Make it easier to reuse the view lambda, for example by storing in big map or global constant. This is because the caller can change the behavior of the lambda by passing different arguments.

### Cons of alternative:
More involved for simple use case that do not require parametrized lambda.

Take this example from the main doc:

```
# contract_a
parameter unit ;
storage int ; # result: int 2
code { 
       CDR;
       PUSH int 1; 
       ADD; # assume the result is 2
       NIL operation;
       PAIR
     }
```

If we want to write `contract_b` that fetches the int in the storage of `contract_a` and increment it, we would write something like below.

```
# contract_b
parameter address ;
storage int ;
code { 
      CAR; # get address
      PUSH unit UNIT; # feels redundant
      LAMBDA (pair unit int) int { PUSH int 1; ADD } ;
      VIEW_EXEC ; # result: Some (int 3)
      IF_NONE { PUSH string "view call failed" ; FAILWITH } { } ;
      NIL operation ;
      PAIR ;
     }
```

Note that the `PUSH UNIT` feels redundant here.