Understanding the philosophy behind the language
Juno started as a personal project during my fourth high school year. I had created other programming languages in the past — most were driven by interesting design philosophies: homoiconicity, minimal syntax rules, novel paradigms. But Juno was born out of a practical need: I wanted a C-like language that runs on the JVM.
Java wasn't enough. It's verbose, enterprise-heavy, and deeply object-oriented. Juno aims to be leaner — not necessarily simpler, but focused. Its design philosophy can be summed up in three core attributes: essential, procedural, and safe.
Juno's core is deliberately small. There's no OOP. No first-class functions. No kitchen sink of features. But this minimalism is strategic — Juno's greatest strength is its direct access to the entire Java ecosystem. You get the JVM's mature libraries, battle-tested frameworks, and decades of tooling, all while writing clean, procedural code.
Juno's module system may seem basic compared to languages with elaborate package managers, but it leverages existing JVM infrastructure. This means Juno can grow its ecosystem faster than building everything from scratch — you're not reinventing the wheel, you're choosing better spokes.
Juno also features a single-pass compiler. No intermediate representations, no multi-stage compilation. This makes the compiler faster, simpler to understand, and easier to hack on. The trade-off? Less aggressive optimization. But for most use cases, the JVM's JIT handles that just fine.
Juno's main paradigm is procedural programming — a style familiar to nearly every developer. It's the foundation of C, Go, Pascal, and the imperative core of languages like Python and JavaScript.
OOP was deliberately excluded — not because it's hard to implement on the JVM (it would've been straightforward), but because of its tendency toward bloat. Deep inheritance hierarchies, scattered methods across dozens of classes, implicit coupling... OOP encourages complexity that Juno avoids.
Instead, Juno offers structs for organizing data. They're lightweight, explicit, and come with automatic constructors. No hidden state, no method soup — just clean data definitions:
type foo = struct foo_s {
int x;
string y;
}
void main() {
foo f = new foo(42, "hello");
// Use f.x and f.y as needed
}
Functions operate on data. Data doesn't own behavior. This separation makes Juno code easier to reason about and refactor.
Juno is strongly typed with strict type enforcement. There are no implicit conversions — if you want to mix types, you must be explicit:
float x = 2 / 3.0; // Error: type mismatch
float y = float<2> / 3.0;; // OK: explicit cast
This strictness catches bugs at compile time. No silent truncation, no mysterious runtime behavior. If your types don't match, Juno tells you immediately.
Running on the JVM also means Juno inherits the JVM's memory safety. No null pointer arithmetic. No buffer overflows. No use-after-free. The garbage collector handles memory management, freeing you to focus on logic instead of manual allocation and deallocation.
Juno isn't trying to be Rust — it doesn't prevent all classes of bugs — but it provides guardrails where they matter most: types and memory.
If Juno's philosophy resonates with you, check out the full documentation to see how these principles translate into practical code. Whether you're building a small tool or exploring language design yourself, Juno offers a clean, focused foundation.
Explore the Docs → Get Started →