From 1ab5ba3a95290af51199f72d010afba73863943a Mon Sep 17 00:00:00 2001 From: Knut Franke Date: Sun, 21 Sep 2025 14:29:27 +0200 Subject: [PATCH] Add description of compound type signatures list, record and table type signatures were mentioned in several places, but never discussed in detail. The recently added oneof type declaration wasn't documented anywhere (except in the blog post introducing nu 0.105.0, where it was added). Add sections for list, record, table and oneof compound types to the Language Reference Guide. Add a link to the relevant reference page in the "Custom Commands"/"Parameters"/"Parameter Types" section of the book. --- book/custom_commands.md | 6 +- lang-guide/chapters/types/type_signatures.md | 140 ++++++++++++++++++- 2 files changed, 144 insertions(+), 2 deletions(-) diff --git a/book/custom_commands.md b/book/custom_commands.md index 8c38843c3bb..5d1ae85c24d 100644 --- a/book/custom_commands.md +++ b/book/custom_commands.md @@ -3,6 +3,7 @@ prev: text: Programming in Nu link: /book/programming_in_nu.md --- + # Custom Commands As with any programming language, you'll quickly want to save longer pipelines and expressions so that you can call them again easily when needed. @@ -158,7 +159,7 @@ In this case, the final expression is the `match` statement which can return: - `null` if the directory is empty - Otherwise, a `record` representing the randomly chosen file -::: + ::: ## Custom Commands and Pipelines @@ -490,6 +491,9 @@ The following [types](./types_of_data.html) can be used for parameter annotation - `record` - `string` - `table` +- `oneof` + +See [Type signatures](/lang-guide/chapters/types/type_signatures.html) in the Language Reference Guide for more information. ::: diff --git a/lang-guide/chapters/types/type_signatures.md b/lang-guide/chapters/types/type_signatures.md index ca4103ef79b..b18caf6fcb5 100644 --- a/lang-guide/chapters/types/type_signatures.md +++ b/lang-guide/chapters/types/type_signatures.md @@ -45,7 +45,145 @@ There are 3 forms of valid type signatures in Nu: - Basic: E.g. `int`, `bool`, `string`, etc. - Compound: - `list`, - `record` + `record`, + `table` +- Sum types (aka type alternatives): E.g. `oneof` + +### List types + +- `list` - Read as `list of elements of type something` + +For example, `list` would specify a list of integers: + +```nu +def sum_two []: list -> int { $in.0 + $in.1 } + +[1 11 111 1111] | sum_two +# => 12 + +["abc" "def" "ghi"] | sum_two +# error: command doesn't support list input +``` + +- `list` - If no element type is specified, this is equivalent to `list`. + +```nu +def second []: list -> any { $in.1 } + +[1 11 111 1111] | second +# => 11 + +["abc" "def" "ghi"] | second +# => def +``` + +### Record types + +- `record` - Read as `record containing a key key_name with value of type value_type` + +```nu +def greet [person: record] { + $"Hello, ($person.name)!" +} + +greet { name: Ellie } +# => Hello, Ellie! + +greet "Who" +# error: a string is not a record + +greet { given_name: Bob } +# error: the record is missing a "name" key + +greet { name: [] } +# error: the record's "name" value can't be coerced to string + +# The record may contain more keys besides the specified ones though: +greet { name: Bob, age: 32 } +# => Hello, Bob! +``` + +We may also specify multiple keys that a record must possess as a comma separated `name: value_type` list. E.g.: + +```nu +def greet [person: record] { + print $"Hello, ($person.name) the ($person.job)!" + if ($person.birthday | format date "%m-%d") == (date now | format date "%m-%d") { + print "Happy birthday!" + } +} + +greet { name: Bob, job: Builder, birthday: 1998-11-28 } +# => Hello, Bob the Builder! +``` + +Similar to lists, `record` or `record<>` specifies a record with any keys (or even an empty record): + +```nu +def first_key []: record -> string { + columns | first +} + +{ name: Ellie } | first_key +# => name + +{ given_name: Bob } | first_key +# => given_name + +# this will pass type checking (but produce a runtime error) +{} | first_key +``` + +### Table types + +- `table` - Read as `table containing a column column_name with values of type value_type` + +Tables are just lists of records, so table types work very similarly to record types: + +```nu +let data: table, condition: string> = [ + [date temps condition ]; + [2022-02-01T14:30:00+05:00, [38.24, 38.50, 37.99, 37.98, 39.10], 'sunny' ], + [2022-02-02T14:30:00+05:00, [35.24, 35.94, 34.91, 35.24, 36.65], 'sunny' ], + [2022-02-03T14:30:00+05:00, [35.17, 36.67, 34.42, 35.76, 36.52], 'cloudy' ], + [2022-02-04T14:30:00+05:00, [39.24, 40.94, 39.21, 38.99, 38.80], 'rain' ] +] + +def temp_avg [] : table> -> table { + insert avg_temp {|record| $record.temps | math avg} + | reject temps +} + +# Note that both the input and output table contain a column "condition", which +# is not mentioned in the type signature of temp_avg. This is fine. +$data | temp_avg +# => ╭───┬─────────────┬───────────┬──────────╮ +# => │ # │ date │ condition │ avg_temp │ +# => ├───┼─────────────┼───────────┼──────────┤ +# => │ 0 │ 3 years ago │ sunny │ 38.36 │ +# => │ 1 │ 3 years ago │ sunny │ 35.60 │ +# => │ 2 │ 3 years ago │ cloudy │ 35.71 │ +# => │ 3 │ 3 years ago │ rain │ 39.44 │ +# => ╰───┴─────────────┴───────────┴──────────╯ +``` + +### Sum types + +- `oneof` - Read: one of `a`, `b` or `c` + +Example: + +```nu +def foo [ + param: oneof +] { + if ($param | describe) == "binary" { + $param | first 3 + } else { + $param | str substring 0..<3 + } +} +``` ## Custom command parameters and flags