Now with Dart & C++ implementations

Code is Data

Ball is a programming language where every program is a Protocol Buffer message. Write your logic once — serialize it, store it, send it over the wire, and compile it to any target language.

hello_world.ball.yamlyaml
name: hello_world
modules:
  -
    name: main
    functions:
      -
        name: main
        body:
          call:
            module: std
            function: print
            input:
              messageCreation:
                typeName: PrintInput
                fields:
                  -
                    name: message
                    value:
                      literal:
                        { stringValue: Hello, World! }
        metadata:
          { kind: function }
    moduleImports:
      -
        { name: std }
entryModule: main
entryFunction: main

POWERED BY

Protocol Buffers · gRPC Patterns · Buf Registry · Cross-Platform

Language design, reimagined

Ball takes a fundamentally different approach to programming languages. Instead of text files parsed into ASTs, your code starts as structured data.

📦

Code is Protobuf

Every Ball program is a Protocol Buffer message. If it deserializes, it’s structurally valid. No syntax errors, ever.

🌐

Compile Anywhere

One Ball program compiles to Dart, C++, Python, Go, JavaScript, Java, C#, and more. Write once, target everything.

📡

Send Code Over the Wire

Programs are data. Serialize them to binary protobuf, store in databases, send over gRPC, or inspect programmatically.

Protobuf Type System

Ball uses protobuf’s own DescriptorProto types, already mapped to every language. No type system fragmentation.

🧩

One In, One Out

Every function takes one input message and returns one output message, like gRPC. This isn’t a limitation — it IS the design.

🔄

Round-Trip Fidelity

Encode Dart or C++ to Ball, then compile back. Metadata preserves visibility, annotations, and cosmetic details for perfect round-trips.

Three programs, one language

For each target language, Ball needs three components to achieve full support.

📝

Encoder

Source → Ball

Parses native source code (Dart, C++, etc.) and encodes it into Ball protobuf messages. The Dart encoder uses the analyzer package; the C++ encoder uses Clang’s JSON AST.

⚙️

Compiler

Ball → Source

Generates native source code from Ball protobuf messages. Handles expression trees, base function dispatch, type emission, and lazy evaluation for control flow.

▶️

Engine

Ball → Execution

Interprets Ball programs directly at runtime without compilation. Evaluates expressions, manages scopes, and dispatches base functions to native implementations.

One program, many targets

The same Ball program compiles to idiomatic code in each target language.

fibonacci.ball.yamlyaml
name: fibonacci
inputType: int
outputType: int
body:
  block:
    statements:
      -
        expression:
          call:
            module: std
            function: if
            input:
              messageCreation:
                typeName: ""
                fields:
                  -
                    name: condition
                    value:
                      call:
                        module: std
                        function: lte
                        input:
                          messageCreation:
                            typeName: ""
                            fields:
                              -
                                name: left
                                value:
                                  reference:
                                    { name: n }                              -
                                name: right
                                value:
                                  literal:
                                    { intValue: "1" }                  -
                    name: then
                    value:
                      call:
                        module: std
                        function: return
                        input:
                          messageCreation:
                            typeName: ""
                            fields:
                              -
                                name: value
                                value:
                                  reference:
                                    { name: n }
    result:
      call:
        module: std
        function: add
        input:
          messageCreation:
            typeName: ""
            fields:
              -
                name: left
                value:
                  call:
                    function: fibonacci
                    input:
                      call:
                        module: std
                        function: subtract
                        input:
                          messageCreation:
                            typeName: ""
                            fields:
                              -
                                name: left
                                value:
                                  reference:
                                    { name: n }                              -
                                name: right
                                value:
                                  literal:
                                    { intValue: "1" }              -
                name: right
                value:
                  call:
                    function: fibonacci
                    input:
                      call:
                        module: std
                        function: subtract
                        input:
                          messageCreation:
                            typeName: ""
                            fields:
                              -
                                name: left
                                value:
                                  reference:
                                    { name: n }                              -
                                name: right
                                value:
                                  literal:
                                    { intValue: "2" }
metadata:
  kind: function
  params:
    -
      name: n
      type: int
fibonacci_compiled.dartdart
int fibonacci(int n) {
  if ((n <= 1)) {
    return n;
  }
  return (fibonacci((n - 1)) + fibonacci((n - 2)));
}

void main() {
  final result = fibonacci(10);
  print(result.toString());
}

Growing ecosystem

Ball targets multiple languages at different maturity levels.

Dart

Mature

Full compiler, encoder, engine. Reference implementation.

C++

Prototype

Full compiler, encoder (Clang AST), engine. Actively developed.

Go

Bindings

Proto bindings generated. Compiler, encoder, and engine planned.

Python

Bindings

Proto bindings generated. Implementation in future roadmap.

TypeScript

Bindings

Proto bindings generated. Web-first target language.

Java

Bindings

Proto bindings generated. Enterprise target language.

C#

Bindings

Proto bindings generated. .NET ecosystem target.

The expression tree

Every Ball computation is one of seven expression types. This uniform representation makes programs inspectable and transformable.

call

Function call

Invoke any function: {module, function, input}

literal

Constant value

int, double, string, bool, bytes, or list literals

reference

Variable reference

Reference a bound name; "input" = function parameter

fieldAccess

Field access

Read a field from an object: {object, field}

messageCreation

Construct message

Build a protobuf message: {typeName, fields[]}

block

Statement block

Sequential let-bindings + result expression

lambda

Anonymous function

Closures and inline function definitions

Ready to rethink programming?

Ball is open source and actively developed. Get started with the Dart implementation today.

# Clone and get started
git clone https://github.com/Ball-Lang/ball.git
cd ball/dart && dart pub get
cd engine && dart test

# Compile an example
cd ../compiler
dart run bin/compile.dart ../../examples/hello_world.ball.json