Eval in FuncScript

What is FuncScript?

FuncScript1 is a superset of JSON that lets you promote property values into expressions. Instead of static literals, { x: 1 + 2; } is perfectly legal. You can execute FuncScript using fs-cli2 (the command line interface) or experiment in FuncScript Studio3 (a web-based environment).

This article assumes you have basic knowledge of FuncScript. If you’re new to it, I recommend starting with the official documentation or reading my previous articles: fs-cli basics and functions in FuncScript.

What is eval?

Even though FuncScript code is typically written inside {}, it doesn’t mean we can’t do anything outside braces. Just like Python, Node, or Lua have their own REPL4 environments, FuncScript has fs-cli - which lets us execute simple code without worrying about wrapping everything in a file structure. It’s similar to using run5 to do 4 + 5 in C or C++ without the main function.

So the following is also legal in FuncScript:

fs-cli '4 + 3'
Type: Integer
Value:
7

Keep in mind that you need to quote your argument with "" or '' for fs-cli, otherwise unexpected things will happen. For more about fs-cli syntax, please read my first view on fs-cli.


Two ways to run FuncScript

There are two main ways to run FuncScript: FuncScript Studio (a web-based editor) and fs-cli (command line interface).

The main difference is the method of input. In fs-cli, everything we call code must be passed as fs-cli 'arg' where arg is the code. Using quotes is a must (or at least recommended) because things like fs-cli 4 + 4 will only read the first 4 and miss everything after the first argument.

# This is WRONG - fs-cli only sees "4"
fs-cli 4 + 4
Type: Integer
4

# This is CORRECT
fs-cli '4 + 4'
Type: Integer
8

This means fs-cli eval 4 + 4 is an invalid expression. The solution is quoting it as fs-cli 'eval 4 + 4'.

In FuncScript Studio, eval 4 + 4 works directly since it’s an editor environment. You can access the playground at funcscript.org/fsstudio.


Eval with different types

As long as we follow the same format, we can use eval with any type:

fs-cli 'eval "Hello, Esubalew"'
Type: String
"Hello, Esubalew"

fs-cli 'eval [3, 3]'
Type: List
[3, 3]

fs-cli 'eval {}'
Type: KeyValueCollection
{}

fs-cli 'eval {age: 10, name: "cool"}'
Type: KeyValueCollection
{
"age": 10,
"name": "cool"
}

The same applies in FuncScript Studio, except we don’t use the outer quotes:

eval {age: 10, name: "cool"}
// Output: { "age": 10, "name": "cool" }

Eval with expressions inside braces

We can use eval inside {} to combine values:

fs-cli '{name: "Esubalew"; full: "Hello, " + name;}'
Type: KeyValueCollection
{
  "name": "Esubalew",
  "full": "Hello, Esubalew"
}

fs-cli '{a: 10; b: 20; sum: a + b;}'
Type: KeyValueCollection
{
"a": 10,
"b": 20,
"sum": 30
}

But what if we want to avoid the intermediate sum key and just evaluate to the sum directly?


The problem with missing keys

Can we do something like this?

fs-cli '{a: 10; b: 20; a + b}'

Will this result in 30? No, it will not. The {} object violates the key: value syntax because a + b is without a key.

fs-cli '{a: 10; b: 20; a + b}'
Failed to parse expression

This is where eval becomes powerful. By taking eval inside {}, we can return the result directly:

fs-cli '{a: 10; b: 20; eval a + b;}'
Type: Integer
30

Focusing on results with eval

Consider this example where we want to transform a list:

{
  doubled: [1, 2] map (number) => number * 2;
}
// Output: { "doubled": [2, 4] }

But what if we just want the result without the doubled key?

{
  eval [1, 2] map (number) => number * 2;
}
// Output: [2, 4]

We can also access specific elements:

fs-cli '{number: [1, 2] map (n) => n * 2; eval number[0]}'
Type: Integer
2

A practical example

Let’s revisit an example from my previous article:

{
  rate: 1/100;
  numbers: Range(1, 2);
  multiply: (number) => {
    old: number;
    newer: number * rate;
  };
  multiplied: numbers map (number) => multiply(number);
}

This returns everything including intermediate steps:

{
  rate: 0.01,
  numbers: [1, 2],
  multiply: "[Function]",
  multiplied: [{ old: 1, newer: 0.01 }, { old: 2, newer: 0.02 }],
};

Instead of showing all the intermediate variables like rate and the function, we can focus on the result:

{
  rate: 1/100;
  numbers: Range(1, 2);
  multiply: (number) => {
    old: number;
    newer: number * rate;
  };
  multiplied: numbers map (number) => multiply(number);
  eval multiplied;
}
// Output: [{ old: 1, newer: 0.01 }, { old: 2, newer: 0.02 }]

We can go even further and focus on a very specific result:

{
  rate: 1/100;
  numbers: Range(1, 2);
  multiply: (number) => {
    old: number;
    newer: number * rate;
  };
  multiplied: numbers map (number) => multiply(number);
  eval multiplied[0].newer;
}
// Output: 0.01

When eval has no effect

Please note that using eval on a value that’s already a direct return is useless:

fs-cli 'range(1, 10)'
Type: List
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

fs-cli 'range(1, 10)[0]'
Type: Integer
1

fs-cli 'eval range(1, 10)[0]'
Type: Integer
1

Here adding eval is of no effect. Think of it like doing eval 1 which just returns 1.


Eval with functions

If we have a function (what I call a “key function” - learn more at my functions article) that returns a multiplied value:

{
  multi: (x) => x * 2;
}
// Output: { "multi": "[Function]" }

We can use it by expanding:

{
  multi: (x) => x * 2;
  play: multi(2);
}
// Output: { "multi": "[Function]", "play": 4 }

But what if we just want a function that returns a number? This time eval is very important:

fs-cli '{multi: (x) => x * 2; eval multi(2)}'
Type: Integer
4

Eval with Reduce

Let’s use eval with Reduce, a powerful built-in function. Reduce takes these parameters:

  • list - the list to reduce
  • lambda - a function that takes (currentState, currentValue) and returns the new state
  • initialValue - the starting value

Let’s sum numbers from 1 to 10:

{
  numbers: range(1, 10);
  sum: Reduce(numbers, (stateNow, number) => stateNow + number, 0);
}
// Output: { "numbers": [1, 2, ...10], "sum": 55 }

We can simplify by passing the range directly:

{
  sum: Reduce(range(1, 10), (stateNow, number) => stateNow + number, 0);
}
// Output: { "sum": 55 }

Using eval, we can return just the number without a key:

{
  sum: Reduce(range(1, 10), (stateNow, number) => stateNow + number, 0);
  eval sum;
}
// Output: 55

We can also remove the sum: key entirely:

{
  eval Reduce(range(1, 10), (stateNow, number) => stateNow + number, 0);
}
// Output: 55

And since we don’t have key-value pairs anymore, we can even get rid of {}:

fs-cli 'eval Reduce(range(1,10), (s, n) => s + n, 0)'
Type: Integer
55

Eval in conditional expressions

Before finishing the exploration of eval, let’s also see another example: eval in conditional expressions.

The rule in FuncScript when it comes to conditions follows this pattern: key: if condition then assignValue else assignOther - where assignOther is used when the condition is unsatisfied.

{
  value: 10;
  message: if value > 0 then "oh at least positive" else "damn negative";
}

Output:

{
  value: 10,
  message: "oh at least positive",
};

So here we can use eval to directly evaluate the if result without needing an intermediate key:

{
  value: 10;
  eval if value > 0 then "oh at least positive" else "damn negative";
}

Output:

"oh at least positive";

Conclusion

The eval keyword in FuncScript is a powerful tool for:

  1. Focusing on results - Skip intermediate variables and return exactly what you need
  2. Cleaner output - Avoid KeyValueCollection wrappers when you just want a value
  3. Flexible expressions - Use both inside and outside {} depending on your context
  4. Working with functions - Extract return values from lambda expressions

Remember: eval is most useful when you’re inside {} and want to avoid intermediate keys. Outside braces, it’s often redundant since expressions already evaluate directly.


1 FuncScript is a superset of JSON that overlaps with much of JavaScript syntax yet introduces its own twists. FuncScript

2 fs-cli is the command line interface for executing FuncScript expressions. fs-cli

3 FuncScript Studio is a web-based environment for experimenting with FuncScript. FuncScript Studio

4 A read–eval–print loop (REPL), also termed an interactive toplevel or language shell, is a simple interactive computer programming environment that takes single user inputs, executes them, and returns the result to the user. Read–eval–print loop

5 run is a universal multi-language runner and smart REPL written in Rust that lets you execute code in 25+ languages from the command line. run