Chapter 1: Getting Started
Why Wyn?
Before we write code, let's be clear about what you're learning.
Most programmers use multiple languages daily. Python for scripts. JavaScript for web. Go for services. C++ for performance. Each switch costs mental energy-different syntax, different tooling, different mental models.
Wyn eliminates this. It's designed from the ground up to be:
- Simple enough for quick scripts and prototypes
- Fast enough for systems programming and performance-critical code
- Portable enough to run natively on any platform without a runtime
- Powerful enough to handle complex applications with ease
You're not learning a "scripting language" or a "systems language." You're learning the language. One tool for everything.
Your First Program
Let's prove it. Create a file called hello.wyn:
fn main() -> int {
print("Hello, World!")
return 0
}Run it:
wyn run hello.wynYou should see Hello, World! printed to your terminal. If you do, congratulations-you've just written and run your first Wyn program.
If you don't, we need to install Wyn first.
Installing Wyn
macOS / Linux:
curl -fsSL https://wynlang.com/install.sh | shWindows:
irm https://wynlang.com/install.ps1 | iexFrom source:
git clone https://github.com/wynlang/wyn.git
cd wyn && make && ./wyn installVerify it works:
wyn --version
# Should output: Wyn v1.19.1Wyn ships with a bundled TCC compiler - no external dependencies needed. No GCC, no LLVM, no runtime to install.
Wyn files use the .wyn extension. You can also use .🐉 - both work everywhere.
What Just Happened?
Let's break down that program:
fn main() -> int {Every Wyn program starts with a main function. This is where execution begins. The -> int means it returns an integer-by convention, 0 means success and anything else means an error occurred.
print("Hello, World!")This calls the built-in print function. Notice there's no semicolon-Wyn doesn't require them. The newline is enough.
return 0
}We return 0 to indicate success. The closing brace ends the function.
Both of those are optional. You can drop the -> int and the return 0 entirely:
fn main() {
print("Hello, World!")
}This still compiles and runs, and still exits with status 0. Wyn only makes you write what you actually need. You can return a value from main too, if you want your program's exit code to mean something-return 2 exits with status 2, no -> int required. We'll write it out explicitly through most of this book because it documents intent, but don't feel obligated to type it every time.
A More Interesting Example
Hello World is traditional, but it doesn't show you much. Let's write something that demonstrates what makes Wyn different:
fn main() -> int {
var message = " Hello, Wyn! "
var cleaned = message.trim()
var shouting = cleaned.upper()
var length = shouting.len()
print(shouting)
print("\nLength: ")
print(length)
return 0
}Run this and you'll see:
HELLO, WYN!
Length: 11Here's what's interesting: trim(), upper(), and len() are all methods on the string. You're not passing the string to functions-you're calling methods on the string object.
This might seem like a small difference, but it changes how you think about code. Instead of remembering which function operates on which type, you just type the variable name, hit ., and your editor shows you everything you can do with it.
Method Chaining
Because methods return new values, you can chain them:
fn main() -> int {
var result = " Hello, Wyn! ".trim().upper()
print(result) // HELLO, WYN!
return 0
}This reads left-to-right: take the string, trim it, then uppercase it. No nested function calls, no temporary variables unless you want them.
Immutability by Default
Notice that trim() doesn't modify the original string-it returns a new one:
fn main() -> int {
var original = " hello "
var trimmed = original.trim()
print(original) // " hello " - unchanged
print(trimmed) // "hello" - new string
return 0
}This is deliberate. Immutability prevents entire classes of bugs. When you see a variable, you know its value won't change unless you explicitly reassign it.
How Compilation Works
When you run wyn run hello.wyn, several things happen:
- Lexical analysis: The source code is broken into tokens (keywords, identifiers, operators)
- Parsing: Tokens are organized into an Abstract Syntax Tree (AST)
- Type checking: The compiler verifies types are used correctly
- Code generation: C source code is generated
- Compilation: The bundled TCC compiler produces a native binary (~260ms)
- Execution: The binary runs immediately
For release builds (wyn run hello.wyn --release), the system C compiler is used with -O2 optimization instead of TCC.
The result is a standalone executable. No virtual machine, no interpreter, no runtime dependencies. This is why Wyn programs are fast - they're running directly on the CPU.
Common Mistakes
Forgetting the main Function
fn greet() -> int {
print("Hello!")
return 0
}This compiles, but nothing happens when you run it. Execution starts at main-without one, your functions are never called. Every program needs a main function.
Type Mismatches
fn main() -> int {
return "hello" // Wrong type
}Error: Return type mismatch. Expected int, got string
Wyn is statically typed. The compiler catches these errors before your code runs.
Using Undefined Variables
fn main() -> int {
print(message) // What's message?
return 0
}Error: Undefined variable 'message'
Variables must be declared before use. This prevents typos from becoming runtime bugs.
Understanding Error Messages
Wyn's error messages try to be helpful. When you see an error:
- Read the message carefully-it usually tells you exactly what's wrong
- Check the line number-errors are reported where they're detected, which might be after where they occurred
- Look at the type-many errors are type mismatches
Example:
Error at line 5: Type mismatch
Expected: int
Got: string
var x: int = "hello"
^^^^^^^The caret points to the problem. The message explains what went wrong.
Your Development Environment
You can write Wyn in any text editor, but some make life easier:
VS Code: Install the Wyn extension for syntax highlighting and error checking.
Vim/Neovim: Syntax files are in the repository.
Any editor: As long as it can save plain text, you're fine.
For now, don't worry about fancy tooling. A text editor and a terminal are enough.
What's Next
You've installed Wyn, written your first programs, and understand the basics of compilation. You've seen that Wyn code is object-oriented, that methods are called on values, and that immutability is the default.
In the next chapter, we'll dive deeper into variables and types. You'll learn about Wyn's type system, how type inference works, and what types are available.
But first, try the exercises. They're designed to reinforce what you've learned and catch common misconceptions.
Exercises
Don't skip these. Seriously. Reading about programming isn't the same as programming.
Modify Hello World to print your name instead of "World".
Chain methods: Create a string with leading/trailing spaces, trim it, convert to uppercase, and print the length. Do it all in one expression.
Experiment with methods: Try
lower(),reverse(),contains()on strings. See what they do.Break something: Delete the closing brace of main. What error do you get? Why?
Type mismatch: Try to return a string from main. Read the error message carefully.
Multiple operations: Create a string, get its length, convert the length to a string, and print it. You'll need to look up how to convert integers to strings (hint: it's a method on integers).
Solutions are at the end of the book, but try them yourself first. The mistakes you make now are lessons you won't forget later.
Next: Chapter 2: Variables and Types
Try It Yourself
Install Wyn and run this example:
curl -sSL wynlang.com/install.sh | sh
wyn init hello && cd hello
wyn run src/main.wyn