JSOL

Meet JSON's functional half-brother.


JSOL, a single source of truth for business logic: exactly the same results, across different codebases.

I needed to keep the same business rules running on different targets, and the solutions I found were too complex to integrate into the lightweight pipeline I was already using. So I ended up building my own.

Today, JSOL compiles (even itself) to JavaScript, TypeScript, PHP and Python. It uses a deliberately simple syntax, a set of standard functions designed to remove ambiguities between languages, and contracts to ensure the compiled code produces the same results on every target.

Once I solved my cases, I decided to make it more robust so I could actually trust it. The best robustness standard I could come up with was to keep pushing it until I felt comfortable publishing it, and hopefully help the next person in line. :)


/**
@contract
{ "cases": [
	{ "$nYear": 2000 },
	{ "$nYear": 1900 },
	{ "$nYear": 2023 }
] }
*/

const $bIsLeapYear = function($nYear) {
	if (Math.modX($nYear, 400) === 0) return true;
	if (Math.modX($nYear, 100) === 0) return false;
	return Math.modX($nYear, 4) === 0;
};

JSOL's functions are compiled to every target and tested against the same contract. If any target produces a different result, the contract fails.



Knowing the risks is good.
Reducing them is better.

When the same business rule has to be maintained across several targets, it's not enough to know that programming languages differ in their implementation and semantics.

  • A change in business logic shouldn't automatically become a new ticket and a separate project for every target. Especially when regulations, tax rules, or other requirements can change with little notice and need to be addressed yesterday.
  • A reliable workflow shouldn't depend on having that particular programmer on call who happens to remember every language-specific edge case.
  • Even with AI in the toolset, some of these differences can slip through: it happened to me, and that's why I started JSOL.

The more often those rules change, the more opportunities there are for a semantic difference to become a real bug.

If you have already been affected by this kind of scenario, you may even consider contributing or supporting the project. The next step for JSOL is to sort out the 140+ semantic differences already documented, making this kind of verification systematic rather than something you'll have to remember and check manually.

Case JS PHP Python
7.5 % 2 1.5 1 1.5
Math.round(2.5) 3 3 2
Math.round(-2.5) -2 -3 -2
"😀".length 2 4 1
String(true) true 1 True
"12abc" as int 12 12 ValueError
"10" < "9" true false true
[10, 1, 2].sort() 1, 10, 2 1, 2, 10 1, 2, 10
"abc".split("") a,b,c a,b,c ValueError
"a" || "b" a true a
min(NaN, 5) NaN 5 nan
[].pop() undefined null IndexError
"" as number 0 0 ValueError

These are documented language behaviors. The challenge isn't knowing that they exist; it's ensuring that they don't become bugs when the business rule changes.

Is it worth your time?

The first question we developers ask about a new tool is: "Should I bother learning this?". Short answer is: probably not.

Oh. You're still reading. Well, for the long answer:

  • JSOL has strict syntax, zero syntactic sugar, and a learning curve.
  • Writing it –even with an AI's help– will take you longer than writing native code you've already mastered.
  • But JSOL's upfront cost can pay off in iterative maintenance.

The honest way to answer that question is with a model. So the first example below is exactly that: an adoption-economics model written in JSOL, running live in the REPL. And compiled to every target for inspection (less the polyfills).

Play with the inputs: how many targets you maintain, how often your rules change, and get how many iterations until (if) the upfront cost pays for itself. And while you're at it, you're watching JSOL do what it was built to do.

JSOL Mascot
JSOL's mascot: the Sun of May wearing Jason's mask.
📊 JSOL Spreadsheet REPL — v0.2.97

Function: $mAdoptionEconomicsSimple

// @JSOL v0.2.96

/**
 @description

 # Simplified JSOL Adoption Economics
 
 Simplified version of `adoption-economics.jsol.js`: same break-even model
 from **ADOPTION_ECONOMICS.md**, collapsed from 11 inputs to 5 by folding
 dev cost and QA cost into a single number per side (native and JSOL),
 and treating host-adaptation cost (H/h, "wiring, not logic" per the
 source doc) as negligible rather than asking for it separately.
 
 ## Cost Formulas
 
 `setupCostNative     = qTargets * nNativeCostSetup`
 `setupCostJsol       = nJsolCostSetup`
 `iterationCostNative = qTargets * nNativeCostIteration`
 `iterationCostJsol   = nJsolCostIteration`
 
 ## Derivation Reference
 
 See `adoption-economics.jsol.js` for the full derivation of **verdict** and
 **breakEvenIterations** from setupGap and perIterationSavings, including
 why a single "immediate win" boolean is the wrong shape for this
 result: setup cost and per-iteration cost can favor different sides,
 and collapsing that into one flag hides real scenarios (JSOL can be
 cheaper today and still lose over time if its iteration cost is high
 enough — **jsol_wins_until_expiration** below).
 
 ## Parameters
 
 - **@param {integer} $qTargets** - N, number of target languages (e.g. 2 for JS+PHP).
 - **@param {number} $nNativeCostSetup** - Combined dev+QA cost per target, writing it the first time.
 - **@param {number} $nJsolCostSetup** - Cost of writing and verifying the .jsol file, first time.
 - **@param {number} $nNativeCostIteration** - Combined dev+QA cost per target, per later change.
 - **@param {number} $nJsolCostIteration** - Cost of changing and re-verifying the .jsol file, per later change.
 
 ## Returns
 
 - **@returns {Map}** - **verdict**: *jsol_wins_always* | *jsol_wins_after_breakeven* | *jsol_wins_until_expiration* | *native_always_wins*
 - **breakEvenIterations**: -1 when no finite crossover exists
 - **setupCostNative**: Total native setup cost
 - **setupCostJsol**: Total JSOL setup cost
 - **iterationCostNative**: Total native iteration cost
 - **iterationCostJsol**: Total JSOL iteration cost
 */


/**
 @contract
 {
   "cases": [
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 4, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 0.7 },
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 6, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 1 },
     { "$qTargets": 4, "$nNativeCostSetup": 2, "$nJsolCostSetup": 7, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 2 }
   ]
 }
*/

const $mAdoptionEconomicsSimple = function($qTargets, $nNativeCostSetup, $nJsolCostSetup, $nNativeCostIteration, $nJsolCostIteration) {
    const $nSetupCostNative = $qTargets * $nNativeCostSetup;
    const $nSetupCostJsol = $nJsolCostSetup;

    const $nIterationCostNative = $qTargets * $nNativeCostIteration;
    const $nIterationCostJsol = $nJsolCostIteration;

    const $nSetupGap = $nSetupCostJsol - $nSetupCostNative;
    const $nPerIterationSavings = $nIterationCostNative - $nIterationCostJsol;

    let $sVerdict = "native_always_wins";
    let $nBreakEvenIterations = -1;

    if ($nPerIterationSavings > 0) {
        if ($nSetupGap <= 0) {
            $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
        } else {
            $sVerdict = "jsol_wins_after_breakeven";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
        }
    } else if ($nPerIterationSavings < 0) {
        if ($nSetupGap < 0) {
            $sVerdict = "jsol_wins_until_expiration";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
        }
    } else {
        if ($nSetupGap <= 0) {
            $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
        }
    }

    return Map.create(
        "verdict", $sVerdict,
        "breakEvenIterations", $nBreakEvenIterations,
        "setupCostNative", $nSetupCostNative,
        "setupCostJsol", $nSetupCostJsol,
        "iterationCostNative", $nIterationCostNative,
        "iterationCostJsol", $nIterationCostJsol
    );
};
// @JSOL v0.2.96

/**
 @description

 # Simplified JSOL Adoption Economics
 
 Simplified version of `adoption-economics.jsol.js`: same break-even model
 from **ADOPTION_ECONOMICS.md**, collapsed from 11 inputs to 5 by folding
 dev cost and QA cost into a single number per side (native and JSOL),
 and treating host-adaptation cost (H/h, "wiring, not logic" per the
 source doc) as negligible rather than asking for it separately.
 
 ## Cost Formulas
 
 `setupCostNative     = qTargets * nNativeCostSetup`
 `setupCostJsol       = nJsolCostSetup`
 `iterationCostNative = qTargets * nNativeCostIteration`
 `iterationCostJsol   = nJsolCostIteration`
 
 ## Derivation Reference
 
 See `adoption-economics.jsol.js` for the full derivation of **verdict** and
 **breakEvenIterations** from setupGap and perIterationSavings, including
 why a single "immediate win" boolean is the wrong shape for this
 result: setup cost and per-iteration cost can favor different sides,
 and collapsing that into one flag hides real scenarios (JSOL can be
 cheaper today and still lose over time if its iteration cost is high
 enough — **jsol_wins_until_expiration** below).
 
 ## Parameters
 
 - **@param {integer} $qTargets** - N, number of target languages (e.g. 2 for JS+PHP).
 - **@param {number} $nNativeCostSetup** - Combined dev+QA cost per target, writing it the first time.
 - **@param {number} $nJsolCostSetup** - Cost of writing and verifying the .jsol file, first time.
 - **@param {number} $nNativeCostIteration** - Combined dev+QA cost per target, per later change.
 - **@param {number} $nJsolCostIteration** - Cost of changing and re-verifying the .jsol file, per later change.
 
 ## Returns
 
 - **@returns {Map}** - **verdict**: *jsol_wins_always* | *jsol_wins_after_breakeven* | *jsol_wins_until_expiration* | *native_always_wins*
 - **breakEvenIterations**: -1 when no finite crossover exists
 - **setupCostNative**: Total native setup cost
 - **setupCostJsol**: Total JSOL setup cost
 - **iterationCostNative**: Total native iteration cost
 - **iterationCostJsol**: Total JSOL iteration cost
 */


/**
 @contract
 {
   "cases": [
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 4, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 0.7 },
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 6, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 1 },
     { "$qTargets": 4, "$nNativeCostSetup": 2, "$nJsolCostSetup": 7, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 2 }
   ]
 }
*/

const $mAdoptionEconomicsSimple = function($qTargets, $nNativeCostSetup, $nJsolCostSetup, $nNativeCostIteration, $nJsolCostIteration) {
  const $nSetupCostNative = $qTargets * $nNativeCostSetup;
    const $nSetupCostJsol = $nJsolCostSetup;

    const $nIterationCostNative = $qTargets * $nNativeCostIteration;
    const $nIterationCostJsol = $nJsolCostIteration;

    const $nSetupGap = $nSetupCostJsol - $nSetupCostNative;
    const $nPerIterationSavings = $nIterationCostNative - $nIterationCostJsol;

    let $sVerdict = "native_always_wins";
    let $nBreakEvenIterations = -1;

    if ($nPerIterationSavings > 0) {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
    else {
      $sVerdict = "jsol_wins_after_breakeven";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else if ($nPerIterationSavings < 0) {
    if ($nSetupGap < 0) {
      $sVerdict = "jsol_wins_until_expiration";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
  }
  return JSOL.dict(
        "verdict",  $sVerdict, 
        "breakEvenIterations",  $nBreakEvenIterations, 
        "setupCostNative",  $nSetupCostNative, 
        "setupCostJsol",  $nSetupCostJsol, 
        "iterationCostNative",  $nIterationCostNative, 
        "iterationCostJsol",  $nIterationCostJsol
    );
};
window['$mAdoptionEconomicsSimple'] = $mAdoptionEconomicsSimple;
<?php
// @JSOL v0.2.96

/**
 @description

 # Simplified JSOL Adoption Economics
 
 Simplified version of `adoption-economics.jsol.js`: same break-even model
 from **ADOPTION_ECONOMICS.md**, collapsed from 11 inputs to 5 by folding
 dev cost and QA cost into a single number per side (native and JSOL),
 and treating host-adaptation cost (H/h, "wiring, not logic" per the
 source doc) as negligible rather than asking for it separately.
 
 ## Cost Formulas
 
 `setupCostNative     = qTargets * nNativeCostSetup`
 `setupCostJsol       = nJsolCostSetup`
 `iterationCostNative = qTargets * nNativeCostIteration`
 `iterationCostJsol   = nJsolCostIteration`
 
 ## Derivation Reference
 
 See `adoption-economics.jsol.js` for the full derivation of **verdict** and
 **breakEvenIterations** from setupGap and perIterationSavings, including
 why a single "immediate win" boolean is the wrong shape for this
 result: setup cost and per-iteration cost can favor different sides,
 and collapsing that into one flag hides real scenarios (JSOL can be
 cheaper today and still lose over time if its iteration cost is high
 enough — **jsol_wins_until_expiration** below).
 
 ## Parameters
 
 - **@param {integer} $qTargets** - N, number of target languages (e.g. 2 for JS+PHP).
 - **@param {number} $nNativeCostSetup** - Combined dev+QA cost per target, writing it the first time.
 - **@param {number} $nJsolCostSetup** - Cost of writing and verifying the .jsol file, first time.
 - **@param {number} $nNativeCostIteration** - Combined dev+QA cost per target, per later change.
 - **@param {number} $nJsolCostIteration** - Cost of changing and re-verifying the .jsol file, per later change.
 
 ## Returns
 
 - **@returns {Map}** - **verdict**: *jsol_wins_always* | *jsol_wins_after_breakeven* | *jsol_wins_until_expiration* | *native_always_wins*
 - **breakEvenIterations**: -1 when no finite crossover exists
 - **setupCostNative**: Total native setup cost
 - **setupCostJsol**: Total JSOL setup cost
 - **iterationCostNative**: Total native iteration cost
 - **iterationCostJsol**: Total JSOL iteration cost
 */


/**
 @contract
 {
   "cases": [
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 4, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 0.7 },
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 6, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 1 },
     { "$qTargets": 4, "$nNativeCostSetup": 2, "$nJsolCostSetup": 7, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 2 }
   ]
 }
*/

$mAdoptionEconomicsSimple = function($qTargets, $nNativeCostSetup, $nJsolCostSetup, $nNativeCostIteration, $nJsolCostIteration) {
  $nSetupCostNative = $qTargets * $nNativeCostSetup;
    $nSetupCostJsol = $nJsolCostSetup;

    $nIterationCostNative = $qTargets * $nNativeCostIteration;
    $nIterationCostJsol = $nJsolCostIteration;

    $nSetupGap = $nSetupCostJsol - $nSetupCostNative;
    $nPerIterationSavings = $nIterationCostNative - $nIterationCostJsol;

    $sVerdict = "native_always_wins";
    $nBreakEvenIterations = -1;

    if ($nPerIterationSavings > 0) {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
    else {
      $sVerdict = "jsol_wins_after_breakeven";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else if ($nPerIterationSavings < 0) {
    if ($nSetupGap < 0) {
      $sVerdict = "jsol_wins_until_expiration";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
  }
  return JSOL::dict(
        "verdict",  $sVerdict, 
        "breakEvenIterations",  $nBreakEvenIterations, 
        "setupCostNative",  $nSetupCostNative, 
        "setupCostJsol",  $nSetupCostJsol, 
        "iterationCostNative",  $nIterationCostNative, 
        "iterationCostJsol",  $nIterationCostJsol
    );
};
declare var JSOL: any;
declare var Rgx: any;
declare var Str: any;
declare var Arr: any;
declare var Bool: any;
declare var Cast: any;

// @JSOL v0.2.96

/**
 @description

 # Simplified JSOL Adoption Economics
 
 Simplified version of `adoption-economics.jsol.js`: same break-even model
 from **ADOPTION_ECONOMICS.md**, collapsed from 11 inputs to 5 by folding
 dev cost and QA cost into a single number per side (native and JSOL),
 and treating host-adaptation cost (H/h, "wiring, not logic" per the
 source doc) as negligible rather than asking for it separately.
 
 ## Cost Formulas
 
 `setupCostNative     = qTargets * nNativeCostSetup`
 `setupCostJsol       = nJsolCostSetup`
 `iterationCostNative = qTargets * nNativeCostIteration`
 `iterationCostJsol   = nJsolCostIteration`
 
 ## Derivation Reference
 
 See `adoption-economics.jsol.js` for the full derivation of **verdict** and
 **breakEvenIterations** from setupGap and perIterationSavings, including
 why a single "immediate win" boolean is the wrong shape for this
 result: setup cost and per-iteration cost can favor different sides,
 and collapsing that into one flag hides real scenarios (JSOL can be
 cheaper today and still lose over time if its iteration cost is high
 enough — **jsol_wins_until_expiration** below).
 
 ## Parameters
 
 - **@param {integer} $qTargets** - N, number of target languages (e.g. 2 for JS+PHP).
 - **@param {number} $nNativeCostSetup** - Combined dev+QA cost per target, writing it the first time.
 - **@param {number} $nJsolCostSetup** - Cost of writing and verifying the .jsol file, first time.
 - **@param {number} $nNativeCostIteration** - Combined dev+QA cost per target, per later change.
 - **@param {number} $nJsolCostIteration** - Cost of changing and re-verifying the .jsol file, per later change.
 
 ## Returns
 
 - **@returns {Map}** - **verdict**: *jsol_wins_always* | *jsol_wins_after_breakeven* | *jsol_wins_until_expiration* | *native_always_wins*
 - **breakEvenIterations**: -1 when no finite crossover exists
 - **setupCostNative**: Total native setup cost
 - **setupCostJsol**: Total JSOL setup cost
 - **iterationCostNative**: Total native iteration cost
 - **iterationCostJsol**: Total JSOL iteration cost
 */


/**
 @contract
 {
   "cases": [
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 4, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 0.7 },
     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 6, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 1 },
     { "$qTargets": 4, "$nNativeCostSetup": 2, "$nJsolCostSetup": 7, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 2 }
   ]
 }
*/

const $mAdoptionEconomicsSimple = function($qTargets: any, $nNativeCostSetup: any, $nJsolCostSetup: any, $nNativeCostIteration: any, $nJsolCostIteration: any): Record<string, any> {
  const $nSetupCostNative: number = $qTargets * $nNativeCostSetup;
    const $nSetupCostJsol: number = $nJsolCostSetup;

    const $nIterationCostNative: number = $qTargets * $nNativeCostIteration;
    const $nIterationCostJsol: number = $nJsolCostIteration;

    const $nSetupGap: number = $nSetupCostJsol - $nSetupCostNative;
    const $nPerIterationSavings: number = $nIterationCostNative - $nIterationCostJsol;

    let $sVerdict: string = "native_always_wins";
    let $nBreakEvenIterations: number = -1;

    if ($nPerIterationSavings > 0) {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
    else {
      $sVerdict = "jsol_wins_after_breakeven";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else if ($nPerIterationSavings < 0) {
    if ($nSetupGap < 0) {
      $sVerdict = "jsol_wins_until_expiration";
            $nBreakEvenIterations = $nSetupGap / $nPerIterationSavings;
    }
  }
  else {
    if ($nSetupGap <= 0) {
      $sVerdict = "jsol_wins_always";
            $nBreakEvenIterations = 0;
    }
  }
  return JSOL.dict(
        "verdict",  $sVerdict, 
        "breakEvenIterations",  $nBreakEvenIterations, 
        "setupCostNative",  $nSetupCostNative, 
        "setupCostJsol",  $nSetupCostJsol, 
        "iterationCostNative",  $nIterationCostNative, 
        "iterationCostJsol",  $nIterationCostJsol
    );
};
import math
import functools
from jsol_core import JSOL

# @JSOL v0.2.96

#*
# @description
#
# # Simplified JSOL Adoption Economics
# 
# Simplified version of `adoption-economics.jsol.js`: same break-even model
# from **ADOPTION_ECONOMICS.md**, collapsed from 11 inputs to 5 by folding
# dev cost and QA cost into a single number per side (native and JSOL),
# and treating host-adaptation cost (H/h, "wiring, not logic" per the
# source doc) as negligible rather than asking for it separately.
# 
# ## Cost Formulas
# 
# `setupCostNative     = qTargets * nNativeCostSetup`
# `setupCostJsol       = nJsolCostSetup`
# `iterationCostNative = qTargets * nNativeCostIteration`
# `iterationCostJsol   = nJsolCostIteration`
# 
# ## Derivation Reference
# 
# See `adoption-economics.jsol.js` for the full derivation of **verdict** and
# **breakEvenIterations** from setupGap and perIterationSavings, including
# why a single "immediate win" boolean is the wrong shape for this
# result: setup cost and per-iteration cost can favor different sides,
# and collapsing that into one flag hides real scenarios (JSOL can be
# cheaper today and still lose over time if its iteration cost is high
# enough — **jsol_wins_until_expiration** below).
# 
# ## Parameters
# 
# - **@param {integer} $qTargets** - N, number of target languages (e.g. 2 for JS+PHP).
# - **@param {number} $nNativeCostSetup** - Combined dev+QA cost per target, writing it the first time.
# - **@param {number} $nJsolCostSetup** - Cost of writing and verifying the .jsol file, first time.
# - **@param {number} $nNativeCostIteration** - Combined dev+QA cost per target, per later change.
# - **@param {number} $nJsolCostIteration** - Cost of changing and re-verifying the .jsol file, per later change.
# 
# ## Returns
# 
# - **@returns {Map}** - **verdict**: *jsol_wins_always* | *jsol_wins_after_breakeven* | *jsol_wins_until_expiration* | *native_always_wins*
# - **breakEvenIterations**: -1 when no finite crossover exists
# - **setupCostNative**: Total native setup cost
# - **setupCostJsol**: Total JSOL setup cost
# - **iterationCostNative**: Total native iteration cost
# - **iterationCostJsol**: Total JSOL iteration cost
# 


#*
# @contract
# {
#   "cases": [
#     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 4, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 0.7 },
#     { "$qTargets": 2, "$nNativeCostSetup": 2, "$nJsolCostSetup": 6, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 1 },
#     { "$qTargets": 4, "$nNativeCostSetup": 2, "$nJsolCostSetup": 7, "$nNativeCostIteration": 0.8, "$nJsolCostIteration": 2 }
#   ]
# }
#

def mAdoptionEconomicsSimple(qTargets, nNativeCostSetup, nJsolCostSetup, nNativeCostIteration, nJsolCostIteration): 

  nSetupCostNative = qTargets * nNativeCostSetup;
  nSetupCostJsol = nJsolCostSetup;

  nIterationCostNative = qTargets * nNativeCostIteration;
  nIterationCostJsol = nJsolCostIteration;

  nSetupGap = nSetupCostJsol - nSetupCostNative;
  nPerIterationSavings = nIterationCostNative - nIterationCostJsol;

  sVerdict = "native_always_wins";
  nBreakEvenIterations = -1;

  if nPerIterationSavings > 0: 

    if nSetupGap <= 0: 

      sVerdict = "jsol_wins_always";
      nBreakEvenIterations = 0;


    else: 

      sVerdict = "jsol_wins_after_breakeven";
      nBreakEvenIterations = nSetupGap / nPerIterationSavings;




  elif nPerIterationSavings < 0: 

    if nSetupGap < 0: 

      sVerdict = "jsol_wins_until_expiration";
      nBreakEvenIterations = nSetupGap / nPerIterationSavings;




  else: 

    if nSetupGap <= 0: 

      sVerdict = "jsol_wins_always";
      nBreakEvenIterations = 0;




  return JSOL.dict(
  "verdict",  sVerdict, 
  "breakEvenIterations",  nBreakEvenIterations, 
  "setupCostNative",  nSetupCostNative, 
  "setupCostJsol",  nSetupCostJsol, 
  "iterationCostNative",  nIterationCostNative, 
  "iterationCostJsol",  nIterationCostJsol
  );


Every example is also a test.

To be released, every JSOL build has to pass every example correctly, with exactly the same results across every supported target. A "minor" change that resulted in a test giving out "8" in JavaScript and "8.0" in PHP? Rejected.

The language and compiler are continuosly improved because of what these 70+ examples demand. The CLRS examples are here for the same reason: if JSOL aims to be a language someone can read rather than just compile, it has to survive contact with computer science, not just invoicing.

💳

Strict Validation

Luhn, IBAN, CUIT, ISBN-13. Checksum algorithms that have to produce the exact same result in the browser and on the server: the exact scenario where a divergent implementation means a rejected payment or a failed compliance check.
📈

Finance & Rules

Loan amortization, progressive tax tiers, stacked discounts, shipping rate matrices. Rules that change when the business changes, and that silently produce wrong invoices when the frontend and backend disagree.
🧮

Computer Science

Dynamic Programming vs. Greedy (Coin Change), searching algorithms, sorting algorithms, Caesar/Rot13 ciphers, Sieve of Eratosthenes. Executable pseudocode that compiles and runs, not just sits in a textbook.

What JSOL is NOT

JSOL is not a full-stack framework, and it's not a general-purpose language. It is an isolated, pure, synchronous calculator. It doesn't touch the DOM, it doesn't make network requests (no fetch or Async), and it doesn't talk to databases.

Every alternative to JSOL (like Haxe or WebAssembly) buys generality or performance at the cost of requiring a toolchain. JSOL buys zero-toolchain portability by aggressively restricting what you can write.


The Honest Tradeoffs (Where JSOL is worse)

JSOL is intentionally worse and slower than writing native code on any single target. It is currently validating its core hypotheses on portability first. These are the engine-level restrictions you accept when using it:

Feature Native JS / PHP / Python JSOL Why it was stripped
Developer Speed & Syntax Fast (Syntactic sugar, modern abstractions) Slower (Dumb, ugly, spartan & strictly constrained) To eliminate the need for an AST compiler, JSOL severely restricts grammar to flat, lowest-common-denominator patterns.
Control Flow Async, Promises, Threads Strictly Synchronous (Single-thread blocking) Async control flow has no shared syntax between JS, PHP, and Python.
State & Collections Performance Classes, this, Reference Passing Flat Dicts & Value Semantics (Higher GC pressure) Forbidding classes guarantees simple $O(1)$ property access, but forces copying for immutability across targets, making JSOL slower on large arrays.
Text Parsing Native Regex (PCRE / V8 / RE2) Restricted Regex subset & procedural loops Regex engines differ across runtimes. Complex patterns, lookarounds, and backreferences can cause catastrophic backtracking (ReDoS) in one engine but not another.
Floating Point Precision Native floating-point masking / coercion quirks Strict IEEE-754 across all targets For $n, JSOL enforces strict IEEE-754 behavior across all runtimes for predictable standardization. For exact accounting where IEEE-754 is unsuitable, future specs may incorporate other mature, mathematically proven standards.

Design Pillars

Four principles shape every rule in the specification.

1. Clarity

A JSOL algorithm has to be readable by the person who owns the business logic, not just by a compiler.

This is also why JSOL doesn't standardize how you structure code (nested functions vs. flat scope, for instance) — that's implementation shape, not business logic.

2. Portability

The same source runs correctly on every proven target.

This is where Deterministic Parity comes from: given identical inputs, every target's output has to match, bit for bit.

3. Performance

The compiled output should be no heavier and no slower than it has to be.

This is where Zero Dead Code comes from: nothing gets shipped that a given file doesn't actually use.

4. Developer Experience

Writing, compiling, and debugging JSOL should be as frictionless as the constraints allow.

This is where the AST-free compiler pipeline and Zero Runtime Dependencies come from.

A sample of JSOL's design tradeoffs


The modulo operation is a good example of JSOL's design.

C-like languages differ in how they calculate this basic operation. When I had to pick one, I realized that the de facto business logic standard isn't a programming language at all, but Excel.

That's where the “X” in modX comes from:

  • Calling it mod would leave the behavior ambiguous: which mod?
  • Math.modX() explicitly means: calculate modulo the way Excel does.

By giving it a distinct name, JSOL makes the decision explicit, and avoids the risk of developers incorrectly expecting the behavior of the language they're used to.

mod(7, 3) = 1 in all languages
mod(-7, 3) = -1 in JS, Java, C#, C, C++, Rust, Go
= 2 in Python, Ruby, Haskell, Lua, R, Dart, Excel
mod(7, -3) = 1 in JS, Java, C#
= -2 in Python, Ruby, Haskell
= ERROR in Zig
mod(7.5, 2) = 1.5 in JS, Python, Excel
= 1 in PHP

Same operation, different results. Only one is what accountants expect.

This is an open problem, not a finished product

The project maintains a set of EXTENDING documents that map out different ways to push JSOL further: adding new target languages, resolving semantic differences that threaten Deterministic Parity, and extending the type and function system for specific domains such as dates or color science.

These aren't just feature requests. Each one is a different technical problem: from compiler backends and runtime semantics to type design, language interoperability, memory models and closure conversion.

If you're a developer, a researcher, a CS educator or a student and you see a problem here that interests you, there's probably a place for you to contribute. You don't have to solve the whole thing. A target, a semantic divergence, a domain extension, a test case, or a better solution to an existing problem can all move the project forward.

The goal is simple: solve our problems, and leave fewer problems for the person who comes next.

Fork it. Break it. Build something. Challenge an assumption.