How to use if...else for just assigning values

G-d willing

Hello,
I have a very basic question that can help me in not duplicating lines of code.

Let’s say I have a boolean flag that determines a name of a customer.
For example, if the value is true then the name should be “A” else the name should be “B”,

setup : Script ()
setup = script do
  let val = True
  if val then do
    let firstName = "A"
    return ()
  else do
    let firstName = "B"
    return ()

  debug firstName

However, the scope of firstName ends once we go out of the if…else’ scope. And it indicates that the line debug firstName is having a compilation error saying:

error:
    Variable not in scope: firstName

And if I try to introduce the firstName before the if…else block then the value is not getting updated:

setup : Script ()
setup = script do
  let val = True
      firstName = "C"
  if val then do
    let firstName = "A"
    return ()
  else do
    let firstName = "B"
    return ()

  debug firstName

The output of the debug is “C”.
Is this solvable? How can I overcome this?

I am aware that I can create a function that checks this value and return the correct value, however, my scenario is more complicated than this, since I have a data type with many variables and types, and depending on the condition, not all variables need to be changed. I mean the data structure has variables a, b, c & d. if the condition is true, variables a, b & d should get updated, else variables b, c & d should be updated. In addition, following my example, variable d is defined as Either, and depending on the condition it will be set with a different data type.

Thanks,

Hi @cohen.avraham,

“Variables” in Daml are immutable, meaning that you cannot change their value, ever. We usually call them “bindings” instead of “variables” to underline that. All you can do is create new bindings, and they are usually scoped to the do block enclosing them.

So when you write:

setup : Script ()
setup = script do
  let val = True
  if val then do
    let firstName = "A"
    return ()
  else do
    let firstName = "B"
    return ()

  debug firstName

you have two separate firstName bindings, each in their own, separate scope, and there is no firstName binding in the scope of the last line, hence the error.

In

setup : Script ()
setup = script do
  let val = True
      firstName = "C"
  if val then do
    let firstName = "A"
    return ()
  else do
    let firstName = "B"
    return ()

  debug firstName

you have three scopes and three separate firstName bindings. The line

let firstName = "A"

is not changing the value of firstName to be A instead of C. What it is doing is introducing a new binding firstName in the current scope, which shadows (renders inaccessible) the preexisting firstName binding from the parent scope. But only in the current scope, i.e. the current do bloc; once that is finished, the original firstName binding is again accessible, and that’s why it prints A.

So how do we work with immutable bindings? If we can’t have statements that change the value of variables, the only tool we have is to return values. Fortunately, if is an expression that returns a value. So for this simple case you can just write:

setup : Script ()
setup = script do
  let val = True
  let firstName = if val then "A" else "B"
  debug firstName

Given your description of your real use-case (thanks for posting a simplified version, by the way, that makes it a lot easier), you may need to restructure things a bit to fit the constraint that bindings are immutable.

3 Likes

G-d willing

I know that in Daml everything is mutable.
Anyway, thanks, @Gary_Verhaegen for that solution, this is a better solution so far (compared to using a function).
The only “problem” now will be, me typing a lot of that specific “if” condition. But, as said, it is a better way than calling a function, and it is more readable.

The only thing it does not answer is the multiple assignments which, as you said, will need to be restructured or I will need to do a lot of typing

For the multiple assignment issue, there are a few possible solutions. It’s hard to give a recommendation without knowing more about your code; I’d recommend opening a new question thread with a more concrete example of what you’re trying to achieve.

1 Like

will do