From 8aabac0be7b8dfc263008f8ca17604d7654b1f25 Mon Sep 17 00:00:00 2001 From: Adam Chalmers Date: Wed, 5 Feb 2025 13:03:28 -0600 Subject: [PATCH] Update types.md with keyword args data (#5270) A few issues: - There was no description of how `|>` works - Need to explain our keyword arguments implementation - It was using old syntax for `angledLine` which now takes an object as its first parameter, not an array --- docs/kcl/types.md | 195 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 147 insertions(+), 48 deletions(-) diff --git a/docs/kcl/types.md b/docs/kcl/types.md index 5e786e0af..d95c0f028 100644 --- a/docs/kcl/types.md +++ b/docs/kcl/types.md @@ -47,21 +47,6 @@ myObj = { a = 0, b = "thing" } We support two different ways of getting properties from objects, you can call `myObj.a` or `myObj["a"]` both work. - -## Functions - -We also have support for defining your own functions. Functions can take in any -type of argument. Below is an example of the syntax: - -``` -fn myFn(x) { - return x -} -``` - -As you can see above `myFn` just returns whatever it is given. - - ## Binary expressions You can also do math! Let's show an example below: @@ -76,6 +61,120 @@ You can nest expressions in parenthesis as well: myMathExpression = 3 + (1 * 2 / (3 - 7)) ``` +## Functions + +We also have support for defining your own functions. Functions can take in any +type of argument. Below is an example of the syntax: + +``` +fn myFn(x) { + return x +} +``` + +As you can see above `myFn` just returns whatever it is given. + +KCL's early drafts used positional arguments, but we now use keyword arguments. If you declare a +function like this: + +``` +fn add(left, right) { + return left + right +} +``` + +You can call it like this: + +``` +total = add(left = 1, right = 2) +``` + +Functions can also declare one *unlabeled* arg. If you do want to declare an unlabeled arg, it must +be the first arg declared. + +``` +// The @ indicates an argument can be used without a label. +// Note that only the first argument can use @. +fn increment(@x) { + return x + 1 +} + +fn add(@x, delta) { + return x + delta +} + +two = increment(1) +three = add(1, delta = 2) +``` + +## Pipelines + +It can be hard to read repeated function calls, because of all the nested brackets. + +``` +i = 1 +x = h(g(f(i))) +``` + +You can make this easier to read by breaking it into many declarations, but that is a bit annoying. + +``` +i = 1 +x0 = f(i) +x1 = g(x0) +x = h(x1) +``` + +Instead, you can use the pipeline operator (`|>`) to simplify this. + +Basically, `x |> f(%)` is a shorthand for `f(x)`. The left-hand side of the `|>` gets put into +the `%` in the right-hand side. + +So, this means `x |> f(%) |> g(%)` is shorthand for `g(f(x))`. The code example above, with its +somewhat-clunky `x0` and `x1` constants could be rewritten as + +``` +i = 1 +x = i +|> f(%) +|> g(%) +|> h(%) +``` + +This helps keep your code neat and avoid unnecessary declarations. + +## Pipelines and keyword arguments + +Say you have a long pipeline of sketch functions, like this: + +``` +startSketch() +|> line(%, end = [3, 4]) +|> line(%, end = [10, 10]) +|> line(%, end = [-13, -14]) +|> close(%) +``` + +In this example, each function call outputs a sketch, and it gets put into the next function call via +the `%`, into the first (unlabeled) argument. + +If a function call uses an unlabeled first parameter, it will default to `%` if it's not given. This +means that `|> line(%, end = [3, 4])` and `|> line(end = [3, 4])` are equivalent! So the above +could be rewritten as + +``` +startSketch() +|> line(end = [3, 4]) +|> line(end = [10, 10]) +|> line(end = [-13, -14]) +|> close() +``` + +Note that we are still in the process of migrating KCL's standard library to use keyword arguments. So some +functions are still unfortunately using positional arguments. We're moving them over, so keep checking back. +Some functions like `angledLine`, `startProfileAt` etc are still using the old positional argument syntax. +Check the docs page for each function and look at its examples to see. + ## Tags Tags are used to give a name (tag) to a specific path. @@ -88,17 +187,17 @@ way: ``` startSketchOn('XZ') |> startProfileAt(origin, %) - |> angledLine([0, 191.26], %, $rectangleSegmentA001) - |> angledLine([ - segAng(rectangleSegmentA001) - 90, - 196.99 - ], %, $rectangleSegmentB001) - |> angledLine([ - segAng(rectangleSegmentA001), - -segLen(rectangleSegmentA001) - ], %, $rectangleSegmentC001) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) + |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001) + |> angledLine({ + angle = segAng(rectangleSegmentA001) - 90, + length = 196.99, + }, %, $rectangleSegmentB001) + |> angledLine({ + angle = segAng(rectangleSegmentA001), + length = -segLen(rectangleSegmentA001), + }, %, $rectangleSegmentC001) + |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) + |> close() ``` ### Tag Identifier @@ -121,17 +220,17 @@ However if the code was written like this: fn rect(origin) { return startSketchOn('XZ') |> startProfileAt(origin, %) - |> angledLine([0, 191.26], %, $rectangleSegmentA001) - |> angledLine([ - segAng(rectangleSegmentA001) - 90, - 196.99 - ], %, $rectangleSegmentB001) - |> angledLine([ - segAng(rectangleSegmentA001), - -segLen(rectangleSegmentA001) - ], %, $rectangleSegmentC001) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) + |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001) + |> angledLine({ + angle = segAng(rectangleSegmentA001) - 90, + length = 196.99 + }, %, $rectangleSegmentB001) + |> angledLine({ + angle = segAng(rectangleSegmentA001), + length = -segLen(rectangleSegmentA001) + }, %, $rectangleSegmentC001) + |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) + |> close() } rect([0, 0]) @@ -149,17 +248,17 @@ For example the following code works. fn rect(origin) { return startSketchOn('XZ') |> startProfileAt(origin, %) - |> angledLine([0, 191.26], %, $rectangleSegmentA001) - |> angledLine([ - segAng(rectangleSegmentA001) - 90, - 196.99 - ], %, $rectangleSegmentB001) - |> angledLine([ - segAng(rectangleSegmentA001), - -segLen(rectangleSegmentA001) - ], %, $rectangleSegmentC001) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) + |> angledLine({angle = 0, length = 191.26}, %, $rectangleSegmentA001) + |> angledLine({ + angle = segAng(rectangleSegmentA001) - 90, + length = 196.99 + }, %, $rectangleSegmentB001) + |> angledLine({ + angle = segAng(rectangleSegmentA001), + length = -segLen(rectangleSegmentA001) + }, %, $rectangleSegmentC001) + |> line(endAbsolute = [profileStartX(%), profileStartY(%)]) + |> close() } rect([0, 0])