This PR adds support for default parameter values in function definitions, reducing boilerplate and improving API ergonomics:
// Define with defaults
lowpass(freq, q=0.707) = fi.resonlp(freq, q, 1);
// Call - omit defaulted parameters
process = lowpass(1000); // q = 0.707
process = lowpass(1000, 1.5); // q = 1.5Currently, Faust functions require all parameters at every call site, even when sensible defaults exist:
// Without defaults - must specify q every time
lowpass(freq, q) = fi.resonlp(freq, q, 1);
process = lowpass(1000, 0.707), lowpass(2000, 0.707), lowpass(500, 0.707);
// With defaults - cleaner code
lowpass(freq, q=0.707) = fi.resonlp(freq, q, 1);
process = lowpass(1000), lowpass(2000), lowpass(500);This could be especially valuable for library functions where most users want standard values but experts need tunability.
// Single default
gain(x, amount=1.0) = x * amount;
// Multiple defaults (must be rightmost parameters)
mix(a, b, ratio=0.5) = a * (1-ratio) + b * ratio;
env(attack=0.01, decay=0.1, sustain=0.7, release=0.3) = ...;
// Defaults can be expressions
SR = 48000;
nyquist(sr=SR/2) = sr;
// Defaults can reference earlier parameters
scale(x, factor, offset=factor*0.1) = x * factor + offset;Constraints:
- Parameters with defaults must come after parameters without defaults
- Default expressions are evaluated at definition time
- Parser: Extended function parameter syntax to accept
= expression - Boxes: Default values stored by position (nil for required params)
- Eval: Modified function application to fill missing arguments from defaults
Pass tests:
default-params-basic.dsp- single default parameterdefault-params-multiple.dsp- multiple defaults in one functiondefault-params-expression.dsp- defaults using expressions/constants
The large diff in generated files (faustparser.cpp, etc.) is from flex/bison regeneration. Actual source changes:
| File | Lines changed |
|---|---|
faustparser.y |
+97 |
global.hh |
+6 |
sourcereader.cpp |
+16/-9 |
Fully backward compatible - existing function definitions without defaults work unchanged.
Combines naturally with keyword arguments (separate PR):
filter(freq, q=0.707, gain=1.0) = ...;
// All these work:
process = filter(1000);
process = filter(1000, 1.5);
process = filter(1000, gain: 2.0); // skip q, override gain
process = filter(freq: 1000, gain: 2.0); // named + default- Branch:
feature/default-parameters - Base:
master-dev
Another reason not to go for the proposal is the difficulty to keep a clean and simple semantic with the Faust "abstractions follow a full curryfied model", mixed with the new proposed model.
For the Add Python-style selective imports proposal, the same kind of remark: it can be expressed reasonably well with the current syntax, like for instance using:
lp = library("filters.lib").lowpassto import and rename a definition from thefilters.liblibrary.For the Add -il option to inline all libraries, it has to be checked how well it scales, so for instance all DSP in examples should be tested. This can be done by adding new targets in this Makefile. If this works well, then we don't see any reason to define a new option, and would better consider your proposal as a improvement of the current
-eoption.