Share your Programming Language Jam submissions here!

← Back to all posts
Mech - A language for reactive systems
CoreyMech (4)

Mech

You can try Mech online at docs.mech-lang.org, or at the REPL below.

Mech is open source and hosted here: github.com/mech-lang/mech

Or on repl.it: https://repl.it/@MechLang/MechLang

Mech is a language for developing data-driven, reactive systems like animations, games, and robots. It makes composing, transforming, and distributing data easy, allowing you to focus on the essential complexity of your work.

Mech is influenced by the programming languages Matlab, Excel, and Eve. It is meant for applications where there will be a lot of streaming data that can be modeled as tables. This fits a surprisingly wide variety of tasks, but particularly ones where the program interacts with the real world through timers, sensors, and other sources of data. Mech is a distributed programming language, so transporting data across different nodes in a compute cluster is easy.

Language Fundamentals

Mech programs are built from block of code that read and write data to global tables of values.

For example, here is a block of code in mech that adds two columns of numbers:

  x = 1:10
  y = 21:30
  #z = x + y

Mech code is orderless, so we can embed it here in this Markdown document and compile it with the Mech compiler. To run a .mec file, use the run subcommand of the mech executable. It will print the contents of the #mech/output table to stdout.

The above block generates two columns of data: one numbered 1 through 10, the other 21 through 30. The last line of the block adds these two columns together elementwise. Looping over the entire table is implicit in the plus operator. The resulting column of data is written to a table with global scope named #z. The tables x and y are local to the block scope, so they are not accessible outside of the block.

The block model provides reactivity to Mech programs. Blocks will always recompute their output when the input table change, much like an excel spreadsheet will recompute all dependent values of a changed cell. A block recomputing its output can cause a cascade of downstream blocks to update as well. A Mech program will continue to compute as long as new blocks update their output. When no blocks are able to update, a steady state is reached and a Mech program will wait for any new updates from the outside world.

Tables

Every variable in Mech is a table. Tables are 2-dimensional collections of values, which can take the following form:

  • Empty - The value represents nothing
  • Quantity - A generic numerical representation
  • String - A generic character array representation
  • Boolean - True or False
  • Reference - A reference to another table

Quantities are how numbers are represented in Mech. Quantities are base 10, and can have an optional unit associated with them. For example, the following block

  #weight-result = 1kg + 10g

Will produce the correct result of 1010g.

Table columns can have labels. For example, we can create a table of students in a class:

  #students = [|id   major       gpa|
                1234 "Biology"   3.85
                5678 "Chemistry" 2.33]

Functions

We can read the #z column from another block.

  #a = math/sin(angle: #z)

This is a single line block that reads the #z column and applies the function math/sin to every element, then writes the result to the global table #a. If you run this function in the repl, it will trigger a download of the math library from the Mech language module repository. Modules are downloaded as needed when member function are invoked.

Functions also have named arguments. This allows functions to be used in various ways. For example, we can use the stats/average() function to calculate the average of a table over its rows, columns, and the entire table:

  x = [1 2 3; 4 5 6]                // Create a 2 x 3 table
  #avg-1 = stats/average(row: x)    // average over the table rows
  #avg-1 = stats/average(column: x) // average over the table columns
  #avg-1 = stats/average(table: x)  // average over the entire table
  #avg-gpa = stats/average(column: #students.gpa) // average GPA of the students

Standard Library

Math

+ - add
- - subtract
* - multiply
/ - divide
^ - power
** - matrix multiply

Logic

& - and
| - or

Comparison

== - equality
!= - inequality
>= - greater than or equal to
>  - greater than
<= - less than or equal to
<  - less than

Concatenate

[x y]   // Horizontal concatenate
[x ; y] // Vertical concatenate

Bouncing Ball Example

Things get interesting when a program depends on an external source of data. Let's add a timer to our program:

  #time/timer += [period: 1000, ticks: 0]

This block will start a timer by adding a row to the #time/timer table, which tells the #time library to create a timer that will fire ever 1000 ms. On each firing of the timer, the ticks column will be updated.

We can also create a table of bounding balls:

  x = 1:100  // Create 100 balls
  y = x
  #balls = [|x y vx vy| // Balls start out with 20 x-velocity and 0 y-velocity
             x y 20 0]
  #gravity = 1

Now we can update the position of the balls every time the timer ticks

  ~ #time/timer.ticks
  #balls.x := #balls.x + #ball.vx
  #balls.y := #balls.y + #ball.y
  #balls.vy := #balls.vy + #gravity // column plus a scalar does the right thing (elementwise addition of scalar to column)

When balls hit the ground, we can reverse their velocities. We will do this using logical indexing

  ~ #time/timer.ticks
  ix = #balls.y > 500 // ix will be a column of Boolean values, 
                     // where it will be true for every ball with
                     // y value greater than 500
  #balls.vy{ix} := -#balls.vy // Only reverse the vy of balls where ix is true

Other Language Features

Mech is built with a database included, so there are some database-like features available to the language runtime. All interactions with the language runtime are recorded as a transaction. For example, with the ticking timer above, whenever the timer fires it creates a transaction that updates the Mech program when it is applied. We can save these transactions as the program runs, which gives us some new options. First, we can reconstruct the state of any program by replaying the transactions in order. This is helpful for sharing bug reports or working in a team. Second, we can replay transactions in reverse in order to "time travel" back to a previous point of our program's execution history. This helps with debugging.

The Mech executable has several tools to make using Mech more pleasant.

  • Mech test - A testing harness for running tests of Mech code
  • Mech build - Compile a .mec file or a collection of .mec files into a .blx file.
  • Mech run - run a .mec or .blx file
  • Mech serve - serve a .blx file to a client Mech core.

Distribution

Mech programs can run on many cores, or even completely different machines. Consider a networked pong game. This game may consist of three parts: player 1's computer, player 2's computer, and a server that coordinates the game. The server creates the game timer that drives the ball, and it computes the position of the ball and whether or not it has collided with a paddle.

  #ball = [x: 50 y: 50]
  #time/timer += [period: 16, ticks: 0]

Player 1 and Player 2 don't require any logic to move the ball, nor do they require any timers locally. The players will subscribe to the ball updates, and they will be able to move the paddles. When players move the paddles, this change is communicated with the server, which will then test to see if the updated paddle position collides with the ball. The following blocks would be loaded onto Player 1's core.

  #player-1 = 0

Move the player up when the up arrow is pressed

  ~ #html/keyboard.key == "Up"
  #player-1 := #player-1 + 1

Move the player down when the down arrow is pressed

  ~ #html/keyboard.key == "Down"
  #player-1 := #player-1 - 1

Conclusion

Mech is an exciting new language for a number of reasons. We are most excited to use it as part of our middle school outreach program called Forward Robotics, which aims to teach middle school students about technology through interacting with machines like robots and drones. The Mech team is:

  • Corey Montella
  • Allison Codi
  • Sarah Pontier
  • Zach Coriarty
  • Thanos Kougionis
  • Alan Wang
  • Brian Zhu
  • Michelle Modzelewska

We are students and researchers at Lehigh University in Bethlehem Pennsylvania. We hope you enjoy our entry, and invite you to learn more about Mech at docs.mech-lang.org

https://repl.it/@MechLang/Mech#README.md

Commentshotnewtop
TheDrone7 (1440)

Hello there! The jam required you to work as a team, like you did, so please mention your team members in the post.