100 Languages Speedrun: Episode 88: Brat
Tags: brat, lua, smalltalk
Published: 2022-02-13 16:49:50

[Brat](http://brat-lang.org/) is another experimental language, with very minimalistic syntax that looks sort of Ruby and Io inspired to me. It describes itself as "a little toy language that just doesn’t care".

Brat runs on Lua VM. There are no packages, so you need to compile it from sources. There's also no VSCode syntax highlighting, and very limited documentation.

### Hello, World!

```
#!/usr/bin/env brat

p "Hello, World!"
```

```
$ ./hello.brat
Hello, World!
```

Brat compiles to Lua, so if you can check generated `hello.lua` for what exactly will be executed. It's not the most human-readable.

### FizzBuzz

```
#!/usr/bin/env brat

1.to 100 { n|
  true? (n % 15 == 0)
    { p "FizzBuzz" }
    {
      true? (n % 5 == 0)
        { p "Buzz" }
        {
          true? (n % 3 == 0)
            { p "Fizz" }
            { p n }
        }
    }
}
```

Block syntax drops the first `|`, so it's just `{ n| ... }` instead of `{ |n| ... }`.

There's no keywords here. `true? condition, {if_true}, {if_false}` is how you can do if-else.

The exact rules aren't clear, but commas are optional in some cases.

### Unicode

Unicode support is 💩, just like in Lua.

```
#!/usr/bin/env brat

p "Hello".length
p "Żółw".length
p "💩".length
```

```
$ ./unicode.brat
5
7
4
```

### Functional Programming

The basic functional programming works:

```
#!/usr/bin/env brat

a = [1 2 3 4 5]
p a.map { x| x * 2 }
p a.select { x| x % 2 == 1}
p a.reduce { x, y| x + y}
```

```
$ ./functional.brat
[2, 4, 6, 8, 10]
[1, 3, 5]
15
```

### Fibonacci

Brat has very little syntax, but one thing it includes is Ruby-style string interpolation.

```
#!/usr/bin/env brat

fib = {n|
  true? (n <= 2)
    { 1 }
    { fib(n - 1) + fib(n - 2) }
}

1.to 20 {n| p "fib(#{n}) = #{fib(n)}" }
```

```
$  ./fib.brat
fib(1) = 1
fib(2) = 1
fib(3) = 2
fib(4) = 3
fib(5) = 5
fib(6) = 8
fib(7) = 13
fib(8) = 21
fib(9) = 34
fib(10) = 55
fib(11) = 89
fib(12) = 144
fib(13) = 233
fib(14) = 377
fib(15) = 610
fib(16) = 987
fib(17) = 1597
fib(18) = 2584
fib(19) = 4181
fib(20) = 6765
```

### Data Structures

Brat has Arrays and Hashes, and they have working `==` and `print`, at would be totally unremarkable, except in Lua both of these operations are completely broken.

```
#!/usr/bin/env brat

a = [1 2 3 4 5]
h = ["name" : "Alice", "surname" : "Smith"]

p a
p h
p [1 2] == [1 2]
p ["name": "Alice"] == ["name": "Alice"]
```

```
$ ./data.brat
[1, 2, 3, 4, 5]
[name: Alice, surname: Smith]
true
true
```

### Person

Brat uses prototype-based OO model:

```
#!/usr/bin/env brat

person = object.new
person.to_s = { "#{name} #{surname}" }

alice = person.new
alice.name = "Alice"
alice.surname = "Smith"

p alice
```

```
$ ./person.brat
Alice Smith
```

### Vector

We can declare constructors, operators, and so on:

```
#!/usr/bin/env brat

vector = object.new
vector.x = 0
vector.y = 0
vector.to_s = { "<#{x},#{y}>" }
vector.init = { xx, yy |
  my.x = xx
  my.y = yy
}
vector.+ = { other |
  vector.new(x + other.x, y + other.y)
}

a = vector.new(20, 60)
b = vector.new(400, 9)
c = a + b

p a
p b
p c
```

```
$ ./vector.brat
<20,60>
<400,9>
<420,69>
```

### Wordle

Here's Wordle in Brat.

* it would be nice to have some `elsif` as chained `true?` gets quite messy
* we also need to `include :file` to get access to `file` functions
* defining `array.prototype.random` we need to explicitly say `object.random` so it doesn't call itself

```
#!/usr/bin/env brat

include :file

array.prototype.random = { my[object.random(length)] }

words = file.read("wordle-answers-alphabetical.txt").split("\n")
word = words.random
guess = ""

while { guess != word } {
  print "Guess word: "
  guess = g
  true? { guess.length == 5 }
    {
      0.to 4 { n|
        true? { guess[n] == word[n] }
          { print "🟩" }
          {
            true? { word.include?(guess[n]) }
              { print "🟨" }
              { print "🟥" }
          }
      }
      print "\n"
    }
    {
      p "Guess must be 5 characters"
    }
}
```

```
$ ./wordle.brat
Guess word: agile
🟥🟥🟥🟩🟥
Guess word: world
🟥🟩🟥🟩🟨
Guess word: could
🟥🟩🟥🟩🟨
Guess word: dolly
🟩🟩🟩🟩🟩
```

### Should you use Brat?

Brat is actually a decent Smalltalk-style language. It has extremely minimalist syntax, prototype-based OOP, and in many ways it should be a lot more enjoyable than actual Smalltalk.

It's a bit of a pain to install, but if you want "Smalltalk experience" for one weekend, Brat is a solid choice.

There are definitely some annoyances like error messages being unclear, Brat insisting on extra spaces where you'd think they're unnecessary, and lack of Unicode support, but it's good enough for some fun playing with it.

Brat is obviously nowhere near production-ready.

### Code

[All code examples for the series will be in this repository](https://github.com/taw/100-languages-speedrun).

[Code for the Brat episode is available here](https://github.com/taw/100-languages-speedrun/tree/master/episode-88-brat).