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 reducelambda- a function that takes(currentState, currentValue)and returns the new stateinitialValue- 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:
- Focusing on results - Skip intermediate variables and return exactly what you need
- Cleaner output - Avoid KeyValueCollection wrappers when you just want a value
- Flexible expressions - Use both inside and outside
{}depending on your context - 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