From 3777405178ad2c3cfc0f633887ccd9d42628b507 Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Fri, 28 Nov 2025 05:45:48 +0100 Subject: [PATCH 1/3] feat: words, constants and variables page --- docs.json | 1 + languages/fift/variables.mdx | 229 +++++++++++++++++++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 languages/fift/variables.mdx diff --git a/docs.json b/docs.json index 2b2a15983..0aa2e8fac 100644 --- a/docs.json +++ b/docs.json @@ -428,6 +428,7 @@ "group": "Fift", "pages": [ "languages/fift/overview", + "languages/fift/variables", "languages/fift/fift-and-tvm-assembly", "languages/fift/deep-dive", "languages/fift/multisig", diff --git a/languages/fift/variables.mdx b/languages/fift/variables.mdx new file mode 100644 index 000000000..97bfae120 --- /dev/null +++ b/languages/fift/variables.mdx @@ -0,0 +1,229 @@ +--- +title: "Words, Constants, and Variables" +sidebarTitle: "Words, Constants, and Variables" +noindex: "true" +--- + +import { Aside } from '/snippets/aside.jsx'; + +## Words + +A _word_ is an identifier for a `WordDef`, also known as execution token. To define a new word, first define a `WordDef` by enclosing code inside `{ }`; then invoke word `:` followed by the identifier for the new word. For instance, + +```fift +// Take the square of the integer at the top of the stack +{ dup * } : square +``` + +defines a new word `square`, which executes `dup` and `*` when invoked. In this way, typing `5 square` becomes equivalent to typing `5 dup *`, and produces the same result: + +```fift +5 square // Produces 25 at the top of the stack +``` + +It is possible to use the new word as a part of new definitions: + +```fift +// Raise the integer at the top of the stack to the 5th power +{ dup square square * } : **5 +3 **5 // Produces 243 at the top of the stack. +``` + +If the word indicated after `:` is already defined, it is tacitly redefined. However, all existing definitions of other words will continue to use the old definition of the redefined word. For instance, if `square` is redefined after the definition of `**5` above, `**5` will continue to use the original definition of `square`. + +## Constants + +A _constant_ is a word that pushes a predefined value when invoked. Constants can defined by using the word `constant`. For instance, + +```fift +1000000000 constant Gram +``` + +defines a constant `Gram` equal to `10^9`. In other words, `1000000000` will be pushed into the stack whenever `Gram` is invoked: + +```fift +// Pushes Gram and 2 into the stack. +// Then, multiplies them, producing +// 2000000000 at the top of the stack. +Gram 2 * +``` + +Of course, it is possible to use the result of a computation to initialize the value of a constant: + +```fift +// Define constant mGram with the result +// of the computation Gram 1000 / +Gram 1000 / constant mGram +mGram // Pushes 1000000 into the stack +``` + +The value of a constant does not necessarily have to be an `Integer`. For instance, a string constant can be defined in the same way: + +```fift +"Hello, world!" constant hello +hello // Pushes "Hello, world!" into the stack +``` + + + +It is possible to store two values into one "double" constant by using the word `2constant`. For instance: + +```fift +355 113 2constant pifrac +``` + +defines a new word `pifrac`, which will push `355` and `113` (in that order) when invoked. The two components of a double constant can be of different types. + +If a constant with a fixed name within a block or a colon definition is needed, use `=:` and `2=:`, instead of `constant` and `2constant`. +The word `=: ` takes the value at the top of stack, creates constant `` and assigns the value to ``. +Similarly, word `2=: ` takes the two top-most values in the stack, creates constant `` and assigns the values to ``. + +For instance, the following defines a word `setxy`, which sets constants `x` and `y`: + +```fift +{ dup =: x dup * =: y } : setxy +3 setxy x y + // Produces 12 at the top of the stack +7 setxy x y + // Produces 56 at the top of the stack +``` + +The code `3 setxy x y +`, which is equivalent to `3 dup =: x dup * =: y x y +`, changes the stack as follows: + +```text +3 Stack: 3 +dup Stack: 3 3 +=: x Stack: 3 (x is 3) +dup Stack: 3 3 +* Stack: 9 +=: y Stack: (y is 9) +x Stack: 3 +y Stack: 3 9 ++ Stack: 12 +``` + +The code `7 setxy x y +` has a similar explanation. + +To recover the execution-time value of a constant inside a block definition, prefix the constant name with the word `@'`. For instance, using the definition of `setxy` as above, the following code defines a new word `addxy` which accesses the constants `x` and `y` and adds them: + +```fift +{ @' x @' y + } : addxy +3 setxy addxy // Produces 12 at the top of the stack +``` + +The code `3 setxy addxy` has the same effect as the code `3 setxy x y +`. The main difference between `3 setxy addxy` and `3 setxy x y +` is that in `3 setxy addxy`, constants `x` and `y` are accessed inside a code block definition, which require the use of word `@'` to access them; while in `3 setxy x y +`, the constants are accessed outside a code block definition, which does not require the use of word `@'` to access them. + +The drawback of this approach is that `@'` has to look up the current definition of constants `x` and `y` in the dictionary each time `addxy` is executed. [Variables](#variables) provide a more efficient way to achieve similar results. + +## Variables + +_Variables_ are a much more efficient way to represent changeable values. To declare a variable, use the word `variable` followed by the identifier. Internally, the word `variable` creates an empty box, which can then be updated with word `!`, and read with word `@`. + +For instance: + +```fift +// Create two variables x and y, initialized to null +variable x variable y +// Set the value of x to 2 +2 x ! +// Set the value of y to 10 +10 y ! +// Read x and place the value at the top of the stack +x @ +// Read y and place the value at the top of the stack +y @ +// Add the two values ++ // Produces 12 at the top of the stack +``` + +The word `variable` produces variables initialized to `null`. Instead, to create initialized variables to a specific value, use the phrase `box constant`: + +```fift +17 box constant x +x 1+! x @ . +``` + +prints `"18 ok"`. One can even define a special defining word for initialized variables, if they are needed often: + +```fift +{ box constant } : init-variable +17 init-variable x +"test" init-variable y +x 1+! x @ . y @ type +``` + +prints `"18 test ok"`. + +The variables have so far only one disadvantage compared to the constants: one has to access their current values by means of an auxiliary word @. Of course, one can mitigate this by defining a "getter" and a "setter" word for a variable, and use these words to write better-looking code: + +```fift +variable x-box +{ x-box @ } : x +{ x-box ! } : x! +{ x x * 5 x * + 6 + } : f(x) +{ ."( " x . .", " f(x) . .") " } : .xy +3 x! .xy 5 x! .xy +``` + +prints `"( 3 , 30 ) ( 5 , 56 ) ok"`, which are the points `(x, f(x))` on the graph of `f(x) = x 2 + 5x + 6` with `x = 3` and `x = 5`. + +Again, if we want to define "getters" for all our variables, we can first define a defining word as explained in 4.8, and use this word to define both a getter and a setter at the same time: + +```fift +{ hole dup 1 ' @ does create 1 ' ! does create } : variable-set +variable-set x x! +variable-set y y! +{ ."x=" x . ."y=" y . ."x*y=" x y * . cr } : show +{ y 1+ y! } : up +{ x 1+ x! } : right +{ x y x! y! } : reflect +2 x! 5 y! +``` + +show up show right show up show reflect show produces + +```fift +x=2 y=5 x*y=10 +x=2 y=6 x*y=12 +x=3 y=6 x*y=18 +x=3 y=7 x*y=21 +x=7 y=3 x*y=21 +``` + +For instance, the last two code fragments of 2.7 could have been written with the aid of variables instead of constants as follows: + +```fift +variable x variable y +{ dup x ! dup * y ! } : setxy +3 setxy x @ . y @ . x @ y @ + . +7 setxy x @ . y @ . x @ y @ + . +{ ."( " x @ . .", " y @ . .") " } : showxy +3 setxy showxy +``` + +producing the same output as before: + +```fift +3 9 12 ok +7 49 56 ok +( 3 , 9 ) ok +``` + +We can implement a simple counter: + +```fift +variable counter +{ counter 0! } : reset-counter +{ counter @ 1+ dup counter ! } : next-counter +reset-counter next-counter . next-counter . next-counter . +reset-counter next-counter . +``` + +produces + +```fift +1 2 3 ok +1 ok +``` + +After these definitions are in place, we can even forget the definition of `counter` by means of the phrase `forget counter`. Then the only way to access the value of this variable is by means of `reset-counter` and `next-counter`. From 1464e682be87aa0c5c4171ca747d4ab8491df548 Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Tue, 2 Dec 2025 13:18:56 +0100 Subject: [PATCH 2/3] fix: final edit to variables section. --- languages/fift/variables.mdx | 163 +++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 57 deletions(-) diff --git a/languages/fift/variables.mdx b/languages/fift/variables.mdx index 97bfae120..6f855a7ba 100644 --- a/languages/fift/variables.mdx +++ b/languages/fift/variables.mdx @@ -8,32 +8,33 @@ import { Aside } from '/snippets/aside.jsx'; ## Words -A _word_ is an identifier for a `WordDef`, also known as execution token. To define a new word, first define a `WordDef` by enclosing code inside `{ }`; then invoke word `:` followed by the identifier for the new word. For instance, +A _word_ is an identifier for an execution token, also known as a `WordDef`. To define a new word, first define a `WordDef` by enclosing code inside `{ }`; then invoke word `:` followed by the identifier for the word. For instance, ```fift -// Take the square of the integer at the top of the stack +// square takes the square of the integer at the top of the stack { dup * } : square ``` -defines a new word `square`, which executes `dup` and `*` when invoked. In this way, typing `5 square` becomes equivalent to typing `5 dup *`, and produces the same result: +defines a new word `square`, which executes `dup` and `*` when invoked. Typing `5 square` becomes equivalent to typing `5 dup *`, and produces the same result: ```fift 5 square // Produces 25 at the top of the stack +5 dup * // Produces 25 at the top of the stack ``` -It is possible to use the new word as a part of new definitions: +It is possible to use the new word inside new word definitions: ```fift -// Raise the integer at the top of the stack to the 5th power +// **5 raises the integer at the top of the stack to the 5th power { dup square square * } : **5 3 **5 // Produces 243 at the top of the stack. ``` -If the word indicated after `:` is already defined, it is tacitly redefined. However, all existing definitions of other words will continue to use the old definition of the redefined word. For instance, if `square` is redefined after the definition of `**5` above, `**5` will continue to use the original definition of `square`. +If the word indicated after `:` is already defined, it is redefined. However, all existing definitions of other words will continue to use the old definition of the redefined word. For instance, if `square` is redefined after the definition of `**5` above, `**5` will continue to use the original definition of `square`. ## Constants -A _constant_ is a word that pushes a predefined value when invoked. Constants can defined by using the word `constant`. For instance, +A _constant_ is a word that pushes a predefined value when invoked. Constants can defined using the word `constant`. For instance, ```fift 1000000000 constant Gram @@ -139,91 +140,139 @@ y @ The word `variable` produces variables initialized to `null`. Instead, to create initialized variables to a specific value, use the phrase `box constant`: ```fift +// Creates variable x and initializes it with value 17 17 box constant x -x 1+! x @ . +// Read x and place the value at the top of the stack +x @ // 17 at the top of the stack +// Increase 17 by 1 +1 + +// Update x, now storing 18 +x ! ``` -prints `"18 ok"`. One can even define a special defining word for initialized variables, if they are needed often: +It is possible to define a special word for creating variables, if they are needed often: ```fift { box constant } : init-variable +// Create a variable x, initialized to 17 17 init-variable x +// Create a variable y, initialized to "test" "test" init-variable y -x 1+! x @ . y @ type ``` -prints `"18 test ok"`. - -The variables have so far only one disadvantage compared to the constants: one has to access their current values by means of an auxiliary word @. Of course, one can mitigate this by defining a "getter" and a "setter" word for a variable, and use these words to write better-looking code: +Variables have one disadvantage compared to [constants](#constants): accessing the value stored in a variable requires the use of word @. This can be mitigated by defining a "getter" and a "setter" word for a variable, and use these words to write better-looking code: ```fift +// First, create the box storing the variable contents variable x-box + +// Define word x so that it is the procedure that +// reads the box contents. +// So, that now, x can be treated as if +// it was the "variable". +// Instead of writing "x-box @" +// to read the variable contents, simply write "x". { x-box @ } : x -{ x-box ! } : x! -{ x x * 5 x * + 6 + } : f(x) -{ ."( " x . .", " f(x) . .") " } : .xy -3 x! .xy 5 x! .xy -``` -prints `"( 3 , 30 ) ( 5 , 56 ) ok"`, which are the points `(x, f(x))` on the graph of `f(x) = x 2 + 5x + 6` with `x = 3` and `x = 5`. +// Define a similar procedure for updating variables x. +{ x-box ! } : x! -Again, if we want to define "getters" for all our variables, we can first define a defining word as explained in 4.8, and use this word to define both a getter and a setter at the same time: +// Update variable with 5 +5 x! -```fift -{ hole dup 1 ' @ does create 1 ' ! does create } : variable-set -variable-set x x! -variable-set y y! -{ ."x=" x . ."y=" y . ."x*y=" x y * . cr } : show -{ y 1+ y! } : up -{ x 1+ x! } : right -{ x y x! y! } : reflect -2 x! 5 y! +// Read the variable twice and add the results +x x + // Produces 10 at the top of the stack ``` -show up show right show up show reflect show produces +It is possible to define "getters" and "setters" for variables in a more generic way. The following code defines the word `variable-get-set`, which creates a fresh variable and takes the two strings following `variable-get-set` to name the variable's getter and setter, respectively. For example, `variable-get-set x x!` will create a variable with getter `x` and setter `x!`. ```fift -x=2 y=5 x*y=10 -x=2 y=6 x*y=12 -x=3 y=6 x*y=18 -x=3 y=7 x*y=21 -x=7 y=3 x*y=21 +{ hole dup 1 ' @ does create 1 ' ! does create } : variable-get-set ``` -For instance, the last two code fragments of 2.7 could have been written with the aid of variables instead of constants as follows: +Word `variable-get-set` works as follows: ```fift -variable x variable y -{ dup x ! dup * y ! } : setxy -3 setxy x @ . y @ . x @ y @ + . -7 setxy x @ . y @ . x @ y @ + . -{ ."( " x @ . .", " y @ . .") " } : showxy -3 setxy showxy +// Create a fresh box containing null +hole Stack: Box +// Duplicate the box +dup Stack: Box Box +// Push 1 +1 Stack: Box Box 1 +// Push the word definition for @ +' @ Stack: Box Box 1 WordDef-for-@ +// Create an execution token { Box WordDef-for-@ } +// that first pushes Box and then calls @. +// The 1 argument in the stack tells "does" that it should +// consume only one argument below 1 +// in the stack. +does Stack: Box { Box WordDef-for-@ } +// Assign the execution token { Box WordDef-for-@ } +// to the first string comming after the invocation of variable-get-set +create Stack: Box +// Push 1 +1 Stack: Box 1 +// Push the word definition for ! +' ! Stack: Box 1 WordDef-for-! +// Create an execution token { Box WordDef-for-! } +// that first pushes Box and then calls !. +// The 1 argument in the stack tells "does" that it should +// consume only one argument below 1 +// in the stack. +does Stack: { Box WordDef-for-! } +// Assign the execution token { Box WordDef-for-! } +// to the second string comming after the invocation of variable-get-set +create Stack: ``` -producing the same output as before: +For instance, `variable-get-set` can be used as follows: ```fift -3 9 12 ok -7 49 56 ok -( 3 , 9 ) ok +// Create a fresh variable with getter x and setter x! +variable-get-set x x! +// Create a fresh variable with getter y and setter y! +variable-get-set y y! +// Set x and y to 5 and 10, respectively. +5 x! 10 y! +// Swap variables x and y +x y x! y! +// Push x +x // Top of stack has 10 +// Push y +y // Top of stack has 5 ``` -We can implement a simple counter: +For more details on words `create`, `' `, `does`, refer to Sections [4.5](/languages/fift/whitepaper#4-5-defining-words-and-dictionary-manipulation), [4.6](/languages/fift/whitepaper#4-6-dictionary-lookup), and [4.7](/languages/fift/whitepaper#4-7-creating-and-manipulating-word-lists) in the Fift whitepaper. + +As another example of `variable-get-set`, the following implements a simple counter. The example uses auxiliary words `reset-counter` and `incr-counter` to reset the counter variable to `0` and increment the counter by one, respectively. ```fift -variable counter -{ counter 0! } : reset-counter -{ counter @ 1+ dup counter ! } : next-counter -reset-counter next-counter . next-counter . next-counter . -reset-counter next-counter . +// Create the getter "counter" and setter "counter!" +variable-get-set counter counter! + +// Resets the counter to 0 +{ 0 counter! } : reset-counter + +// Increments the counter by one. +{ counter 1 + counter! } : incr-counter + +reset-counter // counter variable has 0 +incr-counter // counter variable has 1 +incr-counter // counter variable has 2 +reset-counter // counter variable has 0 +incr-counter // counter variable has 1 +counter // Pushes 1 to the top of the stack ``` -produces +Word `incr-counter` works as follows: ```fift -1 2 3 ok -1 ok +// Push the current value of counter +counter Stack: c +// Push 1 +1 Stack: c 1 +// Add c and 1 ++ Stack: c+1 +// Store the new value back into the counter variable +counter! Stack: ``` - -After these definitions are in place, we can even forget the definition of `counter` by means of the phrase `forget counter`. Then the only way to access the value of this variable is by means of `reset-counter` and `next-counter`. From b649d0d687757c0c9a1f3fb6ae452dc3b4503c44 Mon Sep 17 00:00:00 2001 From: jeshecdom Date: Tue, 2 Dec 2025 13:21:54 +0100 Subject: [PATCH 3/3] fix: forgot to include comments in some Fift snipets. --- languages/fift/variables.mdx | 48 ++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/languages/fift/variables.mdx b/languages/fift/variables.mdx index 6f855a7ba..f043d7c91 100644 --- a/languages/fift/variables.mdx +++ b/languages/fift/variables.mdx @@ -91,16 +91,16 @@ For instance, the following defines a word `setxy`, which sets constants `x` and The code `3 setxy x y +`, which is equivalent to `3 dup =: x dup * =: y x y +`, changes the stack as follows: -```text -3 Stack: 3 -dup Stack: 3 3 -=: x Stack: 3 (x is 3) -dup Stack: 3 3 -* Stack: 9 -=: y Stack: (y is 9) -x Stack: 3 -y Stack: 3 9 -+ Stack: 12 +```fift +3 // Stack: 3 +dup // Stack: 3 3 +=: x // Stack: 3 (x is 3) +dup // Stack: 3 3 +* // Stack: 9 +=: y // Stack: (y is 9) +x // Stack: 3 +y // Stack: 3 9 ++ // Stack: 12 ``` The code `7 setxy x y +` has a similar explanation. @@ -194,35 +194,35 @@ Word `variable-get-set` works as follows: ```fift // Create a fresh box containing null -hole Stack: Box +hole // Stack: Box // Duplicate the box -dup Stack: Box Box +dup // Stack: Box Box // Push 1 -1 Stack: Box Box 1 +1 // Stack: Box Box 1 // Push the word definition for @ -' @ Stack: Box Box 1 WordDef-for-@ +' @ // Stack: Box Box 1 WordDef-for-@ // Create an execution token { Box WordDef-for-@ } // that first pushes Box and then calls @. // The 1 argument in the stack tells "does" that it should // consume only one argument below 1 // in the stack. -does Stack: Box { Box WordDef-for-@ } +does // Stack: Box { Box WordDef-for-@ } // Assign the execution token { Box WordDef-for-@ } // to the first string comming after the invocation of variable-get-set -create Stack: Box +create // Stack: Box // Push 1 -1 Stack: Box 1 +1 // Stack: Box 1 // Push the word definition for ! -' ! Stack: Box 1 WordDef-for-! +' ! // Stack: Box 1 WordDef-for-! // Create an execution token { Box WordDef-for-! } // that first pushes Box and then calls !. // The 1 argument in the stack tells "does" that it should // consume only one argument below 1 // in the stack. -does Stack: { Box WordDef-for-! } +does // Stack: { Box WordDef-for-! } // Assign the execution token { Box WordDef-for-! } // to the second string comming after the invocation of variable-get-set -create Stack: +create // Stack: ``` For instance, `variable-get-set` can be used as follows: @@ -268,11 +268,11 @@ Word `incr-counter` works as follows: ```fift // Push the current value of counter -counter Stack: c +counter // Stack: c // Push 1 -1 Stack: c 1 +1 // Stack: c 1 // Add c and 1 -+ Stack: c+1 ++ // Stack: c+1 // Store the new value back into the counter variable -counter! Stack: +counter! // Stack: ```