Package parameters.
A package parameter is a named static value that the build request may set. It is declared with param in a package's root module, takes its value from [config] in silk.toml or from its default, and may be checked with a where predicate.
Syntax#
ParameterDeclaration = 'pub'? 'param' Identifier ':' Type ('=' Expression)? ('where' Expression)?Manifest tables (TOML) that supply values:
[config]
ModulePath.ParameterName = Value (project tier)
[build]
profile = ProfileName
[profiles.ProfileName]
target = Triple (optional; the host by default)
config.ModulePath.ParameterName = Value (override tier)Declarations#
param name: T = defaultdeclares a private parameter. A private parameter must have a default.pub param name: Tmay omit the default. Every build must then bind it.Package parameters are read only from the root module of the package being built (
[package].mainbelow[package].source, by defaultsrc/main.silk).A
paramin any other module, or in a dependency package, is not registered. Reading it is SEM0214, reported at theparamdeclaration.A
paramcannot appear inside a module-levelstatic ifarm. Parameters are fixed beforestatic ifselects declarations. Such aparamis SEM0214 at its declaration.A parameter is read-only. Assigning to it is SEM0036.
A violation of these schema rules stops
silk checkandsilk buildwith SEM0214 and a reason. A rule broken in the source is reported at the declaration:
src/main.silk:1:1: error[SEM0214] Invalid compilation configuration: a private package parameter needs a default valueA
pub paramthat nothing binds and that has no default is reported at its declaration, bysilk checkandsilk build:
src/main.silk:1:1: error[SEM0214] Invalid compilation configuration: package parameter `x` has no default value and no binding; give it a default or set it under `[config]` in silk.tomlA refused schema does not hide syntax errors.
silk checkandsilk buildreport the module's syntax errors first, then the SEM0214. Withpub param o: f64 = 1.0on line 1 and a malformedfn broken( { }on line 5:
src/main.silk:5:12: error[PAR0001] Expected `)`
src/main.silk:1:1: error[SEM0214] Invalid compilation configuration: a package parameter's type must be bool, an integer, a string, or a fixed array of themTypes#
The type must be concrete and admissible:
bool, a fixed-width or pointer-sized integer type,string, or a fixed array[T; N]of an admissible type.Other types, such as
f64, are SEM0214 at the declaration: "a package parameter's type must be bool, an integer, a string, or a fixed array of them".Enum, struct, union and optional types, such as
Option<i32>, are not supported yet. Each is SEM0214 at the declaration: "package parameterehas an enum, struct, union or optional type, which package parameters do not support yet". This holds with or without a default or binding.?Tis not a Silk type, in aparamor anywhere else. It is one parse error at the?, PAR0007 "?Tis not a Silk type; write an optional type asOption<T>", and the rest of the declaration is still checked.pub param o: ?i32 = 1,param o: ?i32 = 1andlet x: ?i32 = 3each report PAR0007 alone.pub param o: ?i32with no default reports PAR0007 and then SEM0214 "package parameterohas no default value and no binding". Written asOption<i32>, the parameter gets the SEM0214 above.
Defaults#
The default is a static expression of the declared type. A mismatch, as in
param a: i32 = true, is SEM0214 at the default: "the default value of package parameteradoes not have its typei32".It may call static functions and read
constvalues and other parameters. Calling an ordinary function is SEM0176.A default that reads another parameter sees that parameter's final value, after bindings. This gives dependent parameters:
param queueDepth: i32 = workers * 8.Parameters whose defaults read each other form a cycle (SEM0223).
Every default is evaluated, even when a binding replaces it. A default that fails, for example through
compileError, fails the build.See Static evaluation for what a static expression may contain.
Validation with where#
where predicatefollows the default, or the type when there is no default.The predicate must be
bool. Otherwise it is SEM0214 at the predicate: "thewherepredicate of package parameterxis not abool". It may read this parameter and others.Predicates run against the final values of all parameters, whether they come from a default or a binding.
A predicate that is
falseis SEM0214 at the predicate: "the bound value of package parameterxdoes not satisfy itswherepredicate".Comparison and logical operators work in predicates. Indexing (
weights[0]) is reported as unsupported ("unsupported: this construct is not supported by the native compiler yet").
Using parameters#
A parameter name is a static value of its type. It can appear wherever such a value can: runtime expressions,
constinitializers,static ifconditions, andstaticarguments.A module-level
static ifmay test a parameter to choose declarations. See Static control flow and reflection.A
staticparameter that receives a package parameter gives one instance per final value. See Static evaluation.
pub param#
Only a
pub paramaccepts a value from[config]. A value for a private parameter is refused: "package parameterxis notpub, so it cannot be bound".pubis what makes a parameter part of the package's configurable surface. Without it, the default is the only value.
Setting values with [config]#
A value is one line under [config]. The key is the root module's path without .silk, then the parameter's name: main.port = 8080 sets port of src/main.silk, and lib.level = 2 sets level of src/lib.silk in a library. A module below the source root spells its directories with dots: net.http.retries = 3 is src/net/http.silk.
[config]
main.port = 8080
main.weights = [3, 4]
[config.main] # the same, written as a table
label = "edge"The value is plain TOML. Silk checks it against the parameter's declared type:
| Declared type | TOML value |
|---|---|
| An integer type | An integer, such as 8080, -3, 1_000 or 0xff. It must fit the type. -0 reads as 0. |
bool | true or false |
string | A string |
[T; N] | An array of exactly N values of T, such as [3, 4] for [i32; 2] |
Every value in a manifest is a literal. Values that come from somewhere else, such as a secret or the environment, cannot be written there.
A key with no module before the parameter is refused at its line:
InvalidInput: config.port: name the module before the parameter, as config.main.port.A float, date or time is refused at its line:
InvalidInput: config.main.ratio: a package parameter value is an integer, a boolean, a string or an array of them.A value for an unknown parameter, of the wrong type, or out of range is refused with SEM0214 at the line of its key, naming the parameter, as in
silk.toml:6: error[SEM0214] invalid package parameter binding: the value bound to `port` does not have its parameter's type. An unknown name reads "modulemain.silkdeclares no package parameterprot". An array of the wrong length or element type is refused the same way.Every value is type-checked, including one that loses on precedence.
[config]only reaches the package the manifest describes. A dependency's parameters keep their defaults.Before 0.1.0 values were written as
[[build.bindings]]tables with tagged values.build.bindingsand a profile'sbindingsare now refused at their line:build.bindings is an earlier spelling; write config, as config.main.limit = 42.
--profile-input JSON still carries tagged bindings, the transport tools use. Each binding has package ("name@version"), module ("main"), parameter, value and origin. A value is { "kind": "integer", "value": "8080" }, { "kind": "boolean", "value": true }, { "kind": "string", "value": "x" } or { "kind": "array", "values": [ ... ] }. origin is { "source": "...", "provenance": "literal" }, or "translated-public" with a translator; "secret", "physical-supply" and "runtime" are refused.
Profiles and precedence#
[profiles.<name>]is a named build profile.targetdefaults to the host. Other fields includeoptimization,safety,threading,debug,libcandartifact;silk/core/compilationandsilk/core/targetread them. The native compiler refusessafety = "unchecked"andthreading = "multi"for now; see Targets and profiles in the Projects section.[build].profilenames the default profile.--profile <name>selects another. An unknown name is refused, and so is an empty one:profile = ""isInvalidInput: build.profile.A build of a named profile, selected by
--profileor by[build].profile, writes its output tobuild/llvm/<triple>/<name>/. Other builds usedebug/orrelease/.--profile-input <json>supplies a complete profile, with the same fields and taggedbindings, as JSON.--profileand--profile-inputcannot be combined with--target,--releaseor--optimization.[config]values are project-tier. Every build receives them, including--releasebuilds without a profile.A profile's
configvalues (config.main.verbose = truein[profiles.<name>]) and the bindings of--profile-inputare override-tier. An override value beats a project value for the same parameter.Two values for one parameter at the same tier conflict, even when they are equal. The build is refused.
Without any value, a parameter takes its default.
Examples#
pub param verbose: bool = false
pub param workers: i32 = 4 where workers > 0 && workers <= 64
param queueDepth: i32 = workers * 8
pub param label: string = "service"
fn spread(static count: i32, items: i32) -> i32 {
return items / count
}
pub fn main() -> i32 {
static if verbose {
return 1
}
if queueDepth != 32 {
return 2
}
if label != "service" {
return 3
}
return spread(workers, 8) - 2
}A required parameter and a profile override. silk.toml:
[package]
name = "demo"
version = "0.1.0"
silk-version = "0.1.0"
[config]
main.port = 8080
[build]
profile = "dev"
[profiles.dev]
config.main.verbose = truesrc/main.silk:
pub param port: u16
pub param verbose: bool = false
param retries: i32 = 3 where retries >= 0
pub fn main() -> i32 {
if port != 8080 { return 1 }
static if !verbose { return 2 }
return retries - 3
}Diagnostics#
| Code | Meaning |
|---|---|
| SEM0036 | Assignment to a parameter, which is not a writable place |
| SEM0176 | A default needs runtime work, such as an ordinary function call |
| SEM0177 | A default reached a compileError |
| SEM0214 | Rejected parameter schema, binding, default or predicate: invalid declaration or type, unbound pub param, refused binding, wrong default type, non-bool or false where, param in a module-level static if, or a parameter outside the root module |
| SEM0223 | Parameters whose defaults depend on each other |
See also#
Static evaluation · Static control flow and reflection · Program entry and termination · silk/core/compilation, silk/core/target