Coding with Shards¶
In this chapter, we will be learning how to code with Shards so that you can write your very own program!
The shard¶
A shard in its most basic code form consists of its name surrounded by parentheses.
The above example consists of 3 different predefined shards.
Shards are named to make their purpose rather intuitive. (Msg)
is the Message shard that prints a message to the console, while Math.Add
is a Mathematics shard that adds numbers together.
Note
It is a good practice to name your code based on its purpose. This allows others to easily understand what your code achieves without getting too technical.
For example, the code (Msg "Hello World!")
can be easily understood to be sending the message "Hello World" to the console. You do not need to delve into how (Msg)
was coded to understand what it can do.
A shard can take in an input, process that input, and produce an output. Shards also have parameters that behave as user-defined settings.
For example, Math.Add
has the parameter Operand
which is defined by the user. It determines the value that will be added to the input. The final result is then produced as the output.
In code form, parameters are defined by the user within the parentheses of the shard itself, after the shard's name. The above examples will appear as 5 (Math.Add 1)
and 5 (Math.Add 3)
in code.
Some shards have multiple parameters. When specifying values for multiple parameters, you will have to prepend your values with the parameter they are for if some parameters are skipped.
Let us take a look at the Repeat
shard which has four parameters: Action
, Times
, Forever
, Until
.
We can utilize the Repeat
shard with its different parameters as shown:
1 2 |
|
- When no parameters are specified, parameters are treated as implicit and are resolved in order. In this case,
Action
is the implicit parameter forRepeat
and we set(Msg "Hello World")
to it. - Since the other parameters are not defined, they will assume their default values. In this case, the
Repeat
shard will not run at all asTimes
has a default value of 0.
1 2 3 |
|
- The parameters are explicitly declared for clarity.
- Repeats the
Action
twice.
1 2 3 |
|
- Both parameters can be implicit since they are resolved in order. In this case,
Action
is the first implicit parameter, andTimes
is the second implicit parameter.
1 2 3 |
|
- You can still implicitly declare the first parameter, while fully declaring the other parameters. Note that it does not work vice versa. You cannot implicitly declare parameters if a parameter before it has been explicitly declared.
1 2 3 |
|
- This will not work as you cannot implicitly declare the second parameter if the first has been fully declared.
1 2 3 4 5 |
|
- The
Times
parameter is skipped andForever
is declared instead. Since we are skipping a parameter, we must fully declare the parameters that come after it. Until
takes a shard that returnstrue
orfalse
.Repeat
will loop forever until the shard specified inUntil
evaluates totrue
.
->
When using shards for a parameter (e.g., Action
), you must always place ->
before the first shard.
->
is a shard container used to group multiple shards together. We will see how to eliminate the use of ->
later in the segment for defshards
.
To find out more about the input/output/parameter of a shard, you can search for the shard in the search bar above and check out its documentation page.
Give it a try!
Type "Msg" in the search bar above and select the first result that appears. It should lead you to the page for Msg
here.
From there, you can learn more about:
-
The purpose of the shard
-
Its parameters
-
The input type it can receive
-
The output it will produce
-
How to utilize the shard by looking at the examples given
Data Types¶
A shard can take in data, process it, and output the results.
There are many different types of data in the Shards language, and each shard will have specific data types that it can work with.
For example, the Math.Add
shard can only work with numeric data types, while the Log
shard that prints information to the console can work with Any
data type.
Here are some of the data types found in Shards:
Data Type | Description | Example |
---|---|---|
Any |
Any data type. | |
None |
No data type. | |
Bool |
Evaluates to either true or false . |
true , false |
Float |
A numerical value with a decimal point. | 2.53 , -9.124 |
Int |
A numerical value with no decimals. Read as "integer". | 2 , -9 |
Sequence |
A collection of values. | [2.5, -9.1, 9.7] |
String |
Characters enclosed by double quotes. | "A string!" |
Wire |
A sequence of shards. |
Note
A shard can have multiple data types as its input and output. For example, the shard Math.Add
can have its input and output as an Int
, or it can have its input and output as a Float
.
For the full list of data types and more in-depth reading, check out the Types
documentation page here.
Variables¶
To better work with data across your code, we can assign them to data containers known as variables.
Imagine a scenario where you have a float 3.141592653589793
that you need to reuse in code multiple times. Instead of typing out the entire float each time, you could assign it to a variable called .pi-value
and simply use that variable whenever it is needed.
1 |
|
1 2 |
|
- 3.141592653589793 is assigned to the variable
.pi-value
. We'll learn more about assigning variables in a bit!
Variable names always start with a .
period.
Some example of variable names:
-
.x
-
.number-of-apples
-
.is-verified
How you assign data to variables depends on the variable type. The main differences between variables are as follows:
-
Constant vs Mutable
-
Constant: The variable's value cannot be changed once defined.
-
Mutable: The variable's value can be changed.
-
-
Local vs Global
-
Local: The variable is only known within the Wire it originated from.
-
Global: The variable is known throughout the entire Mesh.
-
Local vs Global
We will learn more about this later in the section about Scope in Shards.
Here are the variable types and the symbols used to create and assign to them:
Variable Type | Shard | Alias | Description |
---|---|---|---|
Local, Constant | Ref |
= |
Creates a local constant variable. |
Local, Mutable | Set |
>= |
Creates a local mutable variable. |
Global, Mutable | Set |
>== |
Creates a global mutable variable. |
Mutable | Update |
> |
Updates a mutable variable. |
In summary:
-
Use
=
to create constant variables. -
Otherwise, use
>=
to create local variables, or>==
to make them global. -
Use
>
to update variable values.
When defining variables in your program, you can use Setup
to ensure that variables defined within it will only ever be defined once within a program.
1 2 3 |
|
- Code within a
Setup
will only be run once. As such, you can prevent variables defined in a loop from being reset each time.
Setup
is an alias of the shard Once
, with its Every
parameter set to 1 to ensure that code defined in its Action
parameter will only be run once.
Grouping shards¶
defshards
allows you to group multiple shards to form a new shard, thereby eliminating the use of ->
. It is useful for organizing your code and improving readability.
defshards
has a syntax as such:
1 2 3 |
|
The square brackets []
are where you can define parameters. For example:
1 2 3 |
|
When used in code:
1 |
|
1 2 |
|
Let us now take a look at how we can utilize defshards
in a code snippet that counts from 1 to 5 multiple times.
1 2 3 4 5 6 7 8 |
|
We can replace the use of ->
above with defshards
to make the count from 1 to 5 code reusable and factor it out under a new shard called msg-one-to-five
.
1 2 3 4 5 6 7 8 9 10 |
|
Note
The parameter will still require a ->
if it contains multiple shards.
1 2 3 4 5 |
|
The Wire¶
A Wire is made up of a sequence of shards, queued for execution from left to right, top to bottom.
To create a Wire, we use defwire
.
1 2 3 |
|
Note
The syntax for defwire
is different from defshards
as you cannot define parameters. Square brackets []
are not used. Instead, defwire
inherits variables from the parent wire unless the variables are pure.
Note
Unlike defshards
which group shards up for organization, defwire
groups shards up to fulfill a purpose. As Wires are created with a purpose in mind, they should be appropriately named to reflect it.
A Wire's lifetime ends once the final shard within it has been executed. To keep a Wire alive even after it has reached its end, we can set it to be loopable. This is called a Looped Wire.
A Looped Wire will continue running until its exit conditions have been met.
Note
You will learn more about the entering and exiting of Looped Wires in the next chapter!
To create a Looped Wire, we use defloop
.
1 2 3 |
|
The Mesh¶
Wires are queued for execution within a Mesh, from left to right, top to bottom.
To queue a Wire on a Mesh, we use schedule
.
1 |
|
Note
We will learn more about controlling the flow of Shards with Wires and Meshes in the following chapter.
Running Shards¶
To get Shards running, a specific hierarchy and sequence must be followed. Your shards are first queued into Wires, which are then queued onto a Mesh.
When the Mesh is run, the Wires are executed in sequence and your program is started. This is done using the aptly named command run
.
1 |
|
run
can take in two optional values:
-
The interval between each iteration of the Mesh.
-
The maximum number of iterations, which is typically used for debugging purposes.
Note
If your program has animations, we recommend that you set the first value to (/ 1.0 60.0)
which emulates 60 frames per second (60 FPS).
1 |
|
Let us now take a look at what a basic Shards program will look like!
Writing a sample program¶
Do you recall the hungry-cat
loop from the previous chapter? Let us try to implement a simpler modified version of it using the concepts learned in this chapter.
In this example, the "cat" starts off with 0 hunger. At the end of each loop, we increase the hunger by 1. Once the value of hunger is greater than 0, the cat starts to make cat noises.
defshards and defwire¶
Let us first define the make-cat-noises
Wire.
1 2 3 4 5 |
|
We can employ the Repeat
shard we saw earlier to make our code more efficient.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Going a step further, we can better organize our code by creating new shards with defshards
. Look at how much neater it is now!
1 2 3 4 5 6 7 8 9 10 11 12 |
|
The Loop¶
With the make-cat-noises
Wire done, let us now look at creating the full hungry-cat
program loop.
1 |
|
We want to first create a variable to track the cat's hunger level. Create the .hunger
variable and assign the value of 0 to it. Remember to create the variable within Setup
to prevent it from being reassigned at each iteration of the loop.
1 2 3 |
|
- Code within a
Setup
will only be run once in a program.
Next, use the Math.Inc
shard to increase the value of .hunger
every time the Wire loops.
1 2 3 4 |
|
Conditionals¶
A conditional can be used to check if .hunger
is greater than 0. When the cat's hunger level has risen above 0, we want the cat to start making cat noises. Some conditional shards that you can use are:
When
allows you to specify what happens if a condition is met. The syntax reads as such: When
a condition is met, Then
a specified action happens.
If
is similar to When
, but it has an additional parameter Else
that allows it to have a syntax that reads as such: If
a condition is met, Then
a specified action occurs, Else
another action is executed instead.
For this example, using When
would suffice as we only need make-cat-noises
to run When
hunger IsMore
than 0.
1 2 3 4 5 6 7 |
|
Debugging¶
What if you wanted to check the value of .hunger
in each loop iteration?
We can employ a shard that is useful when you wish to debug your code - the Log
shard.
Debugging
Debugging is the process of attempting to find the cause of an error or undesirable behavior in your program. When attempting to debug your code, functions or tools that allow you to check the value of variables at various points in your code can be useful in helping you narrow down where the errors could be originating from.
Log
is useful as it can be placed at any point of your code to check the value passing through it. In this example, we will use Log
to verify the value of .hunger
before the conditional check with When
occurs. Upon running the code, you will see that when the value of .hunger
becomes 1, the cat starts to make noises.
Readying the Mesh¶
Before our program can run, do not forget to:
-
Define the Mesh.
-
schedule
the Wire on the Mesh. -
run
the Mesh.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
- We set the Mesh to only run 3 iterations. This means that the
hungry-cat
loop will only occur 3 times.
[hungry-cat] Hunger Level: 0
[hungry-cat] Hunger Level: 1
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Mew
[hungry-cat] Hunger Level: 2
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Meow
[make-cat-noises] Mew
[make-cat-noises] Mew
[make-cat-noises] Mew
Congratulations! You have now learned the fundamentals of writing a Shards program.
We will next look at how you can manipulate the flow of Shards to give you better control of how your program utilizes different Wires.