-
Notifications
You must be signed in to change notification settings - Fork 6
Open
Labels
ApiNfun syntax is not changed, but C# syntax isNfun syntax is not changed, but C# syntax isDefinitely nice to have
Description
Idea
NFun expressions already look like data literals. Structs, arrays, numbers, strings — all are valid NFun expressions. Essentially, NFun is already a superset of JSON in expressiveness.
The proposal is to formalize and promote NFun as a data language — an alternative to JSON/TOML/YAML for configs, data, and templates.
Three usage modes
| Mode | Capabilities | Analogue |
|---|---|---|
| Constant | Only literals, structs, arrays. No computations | JSON, TOML |
| Computable | + expressions, variables, functions, if/else |
Jsonnet, Dhall |
| With external variables | + host provides context (user, order, ...) |
Current main NFun use case |
All three modes are the same NFun — the host decides what's available.
Example: NFun document
# ===== Server configuration =====
appName = 'MyService'
version = '2.1.0'
debug = true
# ----- Network -----
host = 'localhost'
port = if (debug) 8080 else 443
baseUrl = 'http://{host}:{port}/api/v1'
# ----- Database -----
db = {
host = 'db.internal'
port = 5432
name = 'myservice'
pool = if (debug) 5 else 50
connStr = 'Host={db.host};Port={db.port};Database={db.name};Pooling=true;MaxPool={db.pool}'
}
# ----- Limits -----
maxUploadMb = 50
maxUploadSize = maxUploadMb * 1024 * 1024
requestTimeout = 30
retryDelays = [1, 2, 5, 10, 30]
# ----- Logging -----
logging = {
level = if (debug) 'trace' else 'warning'
console = debug
file = '/var/log/{appName}.log'
maxSize = 100 * 1024 * 1024
rotate = 5
}
# ----- External services -----
services = [
{ name = 'auth', url = 'http://auth.internal:3001', timeout = 5 }
{ name = 'storage', url = 'http://storage.internal:3002', timeout = 30 }
{ name = 'notify', url = 'http://notify.internal:3003', timeout = 10 }
]
# ----- CORS -----
cors = {
origins = if (debug)
['http://localhost:3000', 'http://localhost:5173']
else
['https://myservice.com', 'https://app.myservice.com']
methods = ['GET', 'POST', 'PUT', 'DELETE']
maxAge = 24 * 60 * 60
}Key advantage: embeddability
Unlike Jsonnet/Dhall/CUE — NFun is not an external tool, but a library:
// Constant / computable — result is a value
var config = Funny.Calc<ServerConfig>(configText);
// With external variables — host provides context
var rule = Funny.ForCalc<Context, Result>(ruleText);The host application controls the sandbox. No filesystem, no network — only what was explicitly provided.
What needs to be done
- Schema validation API —
Funny.Validate<T>(text)returns errors without execution - JSON interop —
Funny.FromJson()/.ToJson()conversion - Multiline strings (Triple-quoted multiline strings with trim margin: '''...''' #98) — critical for templates
- Raw strings with escape levels (Escape level prefix for string interpolation: $'...' $$'...' #99) — for embedded JSON/regex
- Import/include — for config composition (NFun-Lang)
Comparison with JSON
The same config in JSON:
{
"appName": "MyService",
"version": "2.1.0",
"debug": true,
"host": "localhost",
"port": 8080,
"baseUrl": "http://localhost:8080/api/v1",
"db": {
"host": "db.internal",
"port": 5432,
"name": "myservice",
"pool": 5,
"connStr": "Host=db.internal;Port=5432;Database=myservice;Pooling=true;MaxPool=5"
},
"maxUploadMb": 50,
"maxUploadSize": 52428800,
"requestTimeout": 30,
"retryDelays": [1, 2, 5, 10, 30],
"logging": {
"level": "trace",
"console": true,
"file": "/var/log/MyService.log",
"maxSize": 104857600,
"rotate": 5
},
"services": [
{ "name": "auth", "url": "http://auth.internal:3001", "timeout": 5 },
{ "name": "storage", "url": "http://storage.internal:3002", "timeout": 30 },
{ "name": "notify", "url": "http://notify.internal:3003", "timeout": 10 }
],
"cors": {
"origins": ["http://localhost:3000", "http://localhost:5173"],
"methods": ["GET", "POST", "PUT", "DELETE"],
"maxAge": 86400
}
}Key differences:
- No comments — impossible to explain why
portis 8080 or whatmaxSizemeans - No computations —
52428800instead of50 * 1024 * 1024,86400instead of24 * 60 * 60 - No variables —
"MyService"repeated infile,baseUrlmust be hardcoded with duplicated host/port - No conditionals — need separate
config.dev.json/config.prod.jsonfiles - Mandatory double quotes on keys — visual noise
connStrmust be manually assembled with all values hardcoded and duplicated
Related issues
- Triple-quoted multiline strings with trim margin: '''...''' #98 — Multiline strings
- Escape level prefix for string interpolation: $'...' $$'...' #99 — Escape levels for string interpolation
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
ApiNfun syntax is not changed, but C# syntax isNfun syntax is not changed, but C# syntax isDefinitely nice to have