One big difference, however, between interpreted and compiled languages is that interpreted languages typically implement an _`eval` function_ while compiled languages do not. What does this mean?
:::
## Dynamic vs. Static Languages
::: tip Terminology
In general, the difference between a dynamic and static language is how much of the source code is resolved during Compilation (or Parsing) vs. Evaluation/Runtime:
- _"Static"_ languages perform more code analysis (e.g., type-checking, [data ownership](https://doc.rust-lang.org/stable/book/ch04-00-understanding-ownership.html)) during Compilation/Parsing.
- _"Dynamic"_ languages perform more code analysis, including `eval` of additional code, during Evaluation/Runtime.
For the purposes of this discussion, the primary difference between a static and dynamic language is whether or not it has an `eval` function.
:::
### Eval Function
Most dynamic, interpreted languages have an `eval` function. For example, [Python `eval`](https://docs.python.org/3/library/functions.html#eval) (also, [Python `exec`](https://docs.python.org/3/library/functions.html#exec)) or [Bash `eval`](https://linux.die.net/man/1/bash).
The argument to an `eval` is _"source code inside of source code"_, typically conditionally or dynamically computed. This means that, when an interpreted language encounters an `eval` in source code during Parse/Eval, it typically interrupts the normal Evaluation process to start a new Parse/Eval on the source code argument to the `eval`.
Here's a simple Python `eval` example to demonstrate this (potentially confusing!) concept:
```python:line-numbers
# hello_eval.py
print("Hello, World!")
eval("print('Hello, Eval!')")
```
When you run the file (`python hello_eval.py`), you'll see two messages: _"Hello, World!"_ and _"Hello, Eval!"_. Here is what happens:
1. The entire program is Parsed
2. (Line 3) `print("Hello, World!")` is Evaluated
3. (Line 4) In order to evaluate `eval("print('Hello, Eval!')")`:
1. `print('Hello, Eval!')` is Parsed
2. `print('Hello, Eval!')` is Evaluated
::: tip More fun
Consider `eval("eval(\"print('Hello, Eval!')\")")` and so on!
:::
Notice how the use of `eval` here adds a new "meta" step into the execution process. Instead of a single Parse/Eval, the `eval` creates additional, "recursive" Parse/Eval steps instead. This means that the bytecode produced by the Python interpreter can be further modified during the evaluation.
Nushell does not allow this.
As mentioned above, without an `eval` function to modify the bytecode during the interpretation process, there's very little difference (at a high level) between the Parse/Eval process of an interpreted language and that of the Compile/Run in compiled languages like C++ and Rust.
::: tip Takeaway
This is why we recommend that you _"think of Nushell as a compiled language"_. Despite being an interpreted language, its lack of `eval` gives it some of the characteristic benefits as well as limitations common in traditional static, compiled languages.
:::
We'll dig deeper into what it means in the next section.
## Implications
Consider this Python example:
```python:line-numbers
exec("def hello(): print('Hello eval!')")
hello()
```
::: note
We're using `exec` in this example instead of `eval` because it can execute any valid Python code rather than being limited to `eval` expressions. The principle is similar in both cases, though.
:::
During interpretation:
1. The entire program is Parsed
2. In order to Evaluate Line 1:
1. `def hello(): print('Hello eval!')` is Parsed
2. `def hello(): print('Hello eval!')` is Evaluated
3. (Line 2) `hello()` is evaluated.
Note, that until step 2.2, the interpreter has no idea that a function `hello` even exists! This makes [static analysis](https://en.wikipedia.org/wiki/Static_program_analysis) of dynamic languages challenging. In this example, the existence of the `hello` function cannot be checked just by parsing (compiling) the source code. The interpreter must evaluate (run) the code to discover it.