github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/commands/let.md (about)

     1  # `let`
     2  
     3  > Evaluate a mathematical function and assign to variable (deprecated)
     4  
     5  ## Description
     6  
     7  `let` evaluates a mathematical function and then assigns it to a locally
     8  scoped variable (like `set`)
     9  
    10  **This is a deprecated feature. Please refer to [`expr`](expr.md) instead.**
    11  
    12  ## Usage
    13  
    14  ```
    15  let var_name=evaluation
    16  
    17  let var_name++
    18  
    19  let var_name--
    20  ```
    21  
    22  ## Examples
    23  
    24  ```
    25  » let age=18
    26  » $age
    27  18
    28  
    29  » let age++
    30  » $age
    31  19
    32  
    33  » let under18=age<18
    34  » $under18
    35  false
    36  
    37  » let under21 = age < 21
    38  » $under21
    39  true
    40  ```
    41  
    42  ## Detail
    43  
    44  ### Other Operators
    45  
    46  `let` also supports the following operators (substitute **VAR** with your
    47  variable name, and **NUM** with a number):
    48  
    49  * `VAR--`, subtract 1 from VAR
    50  * `VAR++`, add 1 to VAR
    51  * `VAR -= NUM`, subtract NUM from VAR
    52  * `VAR += NUM`, add NUM to VAR
    53  * `VAR /= NUM`, divide VAR by NUM
    54  * `VAR *= NUM`, multiply VAR by NUM
    55  
    56  eg
    57  
    58  ```
    59  » let i=0
    60  » let i++
    61  » $i
    62  1
    63  
    64  » let i+=8
    65  » $i
    66  9
    67  
    68  » let i/=3
    69  3
    70  ```
    71  
    72  Please note these operators are not supported by `=`.
    73  
    74  ### Variables
    75  
    76  There are two ways you can use variables with the math functions. Either by
    77  string interpolation like you would normally with any other function, or
    78  directly by name.
    79  
    80  String interpolation:
    81  
    82  ```
    83  » set abc=123
    84  » = $abc==123
    85  true
    86  ```
    87  
    88  Directly by name:
    89  
    90  ```
    91  » set abc=123
    92  » = abc==123
    93  false
    94  ```
    95  
    96  To understand the difference between the two, you must first understand how
    97  string interpolation works; which is where the parser tokenised the parameters
    98  like so
    99  
   100  ```
   101  command line: = $abc==123
   102  token 1: command (name: "=")
   103  token 2: parameter 1, string (content: "")
   104  token 3: parameter 1, variable (name: "abc")
   105  token 4: parameter 1, string (content: "==123")
   106  ```
   107  
   108  Then when the command line gets executed, the parameters are compiled on demand
   109  similarly to this crude pseudo-code
   110  
   111  ```
   112  command: "="
   113  parameters 1: concatenate("", GetValue(abc), "==123")
   114  output: "=" "123==123"
   115  ```
   116  
   117  Thus the actual command getting run is literally `123==123` due to the variable
   118  being replace **before** the command executes.
   119  
   120  Whereas when you call the variable by name it's up to `=` or `let` to do the
   121  variable substitution.
   122  
   123  ```
   124  command line: = abc==123
   125  token 1: command (name: "=")
   126  token 2: parameter 1, string (content: "abc==123")
   127  ```
   128  
   129  ```
   130  command: "="
   131  parameters 1: concatenate("abc==123")
   132  output: "=" "abc==123"
   133  ```
   134  
   135  The main advantage (or disadvantage, depending on your perspective) of using
   136  variables this way is that their data-type is preserved.
   137  
   138  ```
   139  » set str abc=123
   140  » = abc==123
   141  false
   142  
   143  » set int abc=123
   144  » = abc==123
   145  true
   146  ```
   147  
   148  Unfortunately is one of the biggest areas in Murex where you'd need to be
   149  careful. The simple addition or omission of the dollar prefix, `$`, can change
   150  the behavior of `=` and `let`.
   151  
   152  ### Strings
   153  
   154  Because the usual Murex tools for encapsulating a string (`"`, `'` and `()`)
   155  are interpreted by the shell language parser, it means we need a new token for
   156  handling strings inside `=` and `let`. This is where backtick comes to our
   157  rescue.
   158  
   159  ```
   160  » set str abc=123
   161  » = abc==`123`
   162  true
   163  ```
   164  
   165  Please be mindful that if you use string interpolation then you will need to
   166  instruct `=` and `let` that your field is a string
   167  
   168  ```
   169  » set str abc=123
   170  » = `$abc`==`123`
   171  true
   172  ```
   173  
   174  ### Best practice recommendation
   175  
   176  As you can see from the sections above, string interpolation offers us some
   177  conveniences when comparing variables of differing data-types, such as a `str`
   178  type with a number (eg `num` or `int`). However it makes for less readable code
   179  when just comparing strings. Thus the recommendation is to avoid using string
   180  interpolation except only where it really makes sense (ie use it sparingly).
   181  
   182  ### Non-boolean logic
   183  
   184  Thus far the examples given have been focused on comparisons however `=` and
   185  `let` supports all the usual arithmetic operators:
   186  
   187  ```
   188  » = 10+10
   189  20
   190  
   191  » = 10/10
   192  1
   193  
   194  » = (4 * (3 + 2))
   195  20
   196  
   197  » = `foo`+`bar`
   198  foobar
   199  ```
   200  
   201  ### Read more
   202  
   203  Murex uses the [govaluate package](https://github.com/Knetic/govaluate). More information can be found in it's manual.
   204  
   205  ### Type Annotations
   206  
   207  When `set` or `global` are used as a function, the parameters are passed as a
   208  string which means the variables are defined as a `str`. If you wish to define
   209  them as an alternate data type then you should add type annotations:
   210  
   211  ```
   212  » set int age = 30
   213  ```
   214  
   215  (`$age` is an integer, `int`)
   216  
   217  ```
   218  » global bool dark_theme = true
   219  ```
   220  
   221  (`$dark_theme` is a boolean, `bool`)
   222  
   223  When using `set` or `global` as a method, by default they will define the
   224  variable as the data type of the pipe:
   225  
   226  ```
   227  » open example.json -> set: file
   228  ```
   229  
   230  (`$file` is defined a `json` type because `open` wrote to `set`'s pipe with a
   231  `json` type)
   232  
   233  You can also annotate `set` and `global` when used as a method too:
   234  
   235  ```
   236  out 30 -> set: int age
   237  ```
   238  
   239  (`$age` is an integer, `int`, despite `out` writing a string, `str, to the pipe)
   240  
   241  > `export` does not support type annotations because environmental variables
   242  > must always be strings. This is a limitation of the current operating systems.
   243  
   244  ### Scoping
   245  
   246  Variable scoping is simplified to three layers:
   247  
   248  1. Local variables (`set`, `!set`, `let`)
   249  2. Global variables (`global`, `!global`)
   250  3. Environmental variables (`export`, `!export`, `unset`)
   251  
   252  Variables are looked up in that order of too. For example a the following
   253  code where `set` overrides both the global and environmental variable:
   254  
   255  ```
   256  » set    foobar=1
   257  » global foobar=2
   258  » export foobar=3
   259  » out $foobar
   260  1
   261  ```
   262  
   263  #### Local variables
   264  
   265  These are defined via `set` and `let`. They're variables that are persistent
   266  across any blocks within a function. Functions will typically be blocks
   267  encapsulated like so:
   268  
   269  ```
   270  function example {
   271      # variables scoped inside here
   272  }
   273  ```
   274  
   275  ...or...
   276  
   277  ```
   278  private example {
   279      # variables scoped inside here
   280  }
   281  
   282  ```
   283  
   284  ...however dynamic autocompletes, events, unit tests and any blocks defined in
   285  `config` will also be triggered as functions.
   286  
   287  Code running inside any control flow or error handing structures will be
   288  treated as part of the same part of the same scope as the parent function:
   289  
   290  ```
   291  » function example {
   292  »     try {
   293  »         # set 'foobar' inside a `try` block
   294  »         set foobar=example
   295  »     }
   296  »     # 'foobar' exists outside of `try` because it is scoped to `function`
   297  »     out $foobar
   298  » }
   299  example
   300  ```
   301  
   302  Where this behavior might catch you out is with iteration blocks which create
   303  variables, eg `for`, `foreach` and `formap`. Any variables created inside them
   304  are still shared with any code outside of those structures but still inside the
   305  function block.
   306  
   307  Any local variables are only available to that function. If a variable is
   308  defined in a parent function that goes on to call child functions, then those
   309  local variables are not inherited but the child functions:
   310  
   311  ```
   312  » function parent {
   313  »     # set a local variable
   314  »     set foobar=example
   315  »     child
   316  » }
   317  »
   318  » function child {
   319  »     # returns the `global` value, "not set", because the local `set` isn't inherited
   320  »     out $foobar
   321  » }
   322  »
   323  » global $foobar="not set"
   324  » parent
   325  not set
   326  ```
   327  
   328  It's also worth remembering that any variable defined using `set` in the shells
   329  FID (ie in the interactive shell) is localised to structures running in the
   330  interactive, REPL, shell and are not inherited by any called functions.
   331  
   332  #### Global variables
   333  
   334  Where `global` differs from `set` is that the variables defined with `global`
   335  will be scoped at the global shell level (please note this is not the same as
   336  environmental variables!) so will cascade down through all scoped code-blocks
   337  including those running in other threads.
   338  
   339  #### Environmental variables
   340  
   341  Exported variables (defined via `export`) are system environmental variables.
   342  Inside Murex environmental variables behave much like `global` variables
   343  however their real purpose is passing data to external processes. For example
   344  `env` is an external process on Linux (eg `/usr/bin/env` on ArchLinux):
   345  
   346  ```
   347  » export foo=bar
   348  » env -> grep foo
   349  foo=bar
   350  ```
   351  
   352  ### Function Names
   353  
   354  As a security feature function names cannot include variables. This is done to
   355  reduce the risk of code executing by mistake due to executables being hidden
   356  behind variable names.
   357  
   358  Instead Murex will assume you want the output of the variable printed:
   359  
   360  ```
   361  » out "Hello, world!" -> set hw
   362  » $hw
   363  Hello, world!
   364  ```
   365  
   366  On the rare occasions you want to force variables to be expanded inside a
   367  function name, then call that function via `exec`:
   368  
   369  ```
   370  » set cmd=grep
   371  » ls -> exec $cmd main.go
   372  main.go
   373  ```
   374  
   375  This only works for external executables. There is currently no way to call
   376  aliases, functions nor builtins from a variable and even the above `exec` trick
   377  is considered bad form because it reduces the readability of your shell scripts.
   378  
   379  ### Usage Inside Quotation Marks
   380  
   381  Like with Bash, Perl and PHP: Murex will expand the variable when it is used
   382  inside a double quotes but will escape the variable name when used inside single
   383  quotes:
   384  
   385  ```
   386  » out "$foo"
   387  bar
   388  
   389  » out '$foo'
   390  $foo
   391  
   392  » out %($foo)
   393  bar
   394  ```
   395  
   396  ## See Also
   397  
   398  * [Reserved Variables](../user-guide/reserved-vars.md):
   399    Special variables reserved by Murex
   400  * [Variable and Config Scoping](../user-guide/scoping.md):
   401    How scoping works within Murex
   402  * [`%(Brace Quote)`](../parser/brace-quote.md):
   403    Initiates or terminates a string (variables expanded)
   404  * [`=` (arithmetic evaluation)](../parser/equ.md):
   405    Evaluate a mathematical function (deprecated)
   406  * [`[ Index ]`](../parser/item-index.md):
   407    Outputs an element from an array, map or table
   408  * [`[[ Element ]]`](../parser/element.md):
   409    Outputs an element from a nested structure
   410  * [`export`](../commands/export.md):
   411    Define an environmental variable and set it's value
   412  * [`expr`](../commands/expr.md):
   413    Expressions: mathematical, string comparisons, logical operators
   414  * [`global`](../commands/global.md):
   415    Define a global variable and set it's value
   416  * [`if`](../commands/if.md):
   417    Conditional statement to execute different blocks of code depending on the result of the condition
   418  * [`set`](../commands/set.md):
   419    Define a local variable and set it's value
   420  
   421  <hr/>
   422  
   423  This document was generated from [builtins/core/typemgmt/math_doc.yaml](https://github.com/lmorg/murex/blob/master/builtins/core/typemgmt/math_doc.yaml).