Docs
Everything you need to know about noCap's syntax and features.
Variables
Variables in noCap are decalred using the fr keyword.
fr num = 42;
noCap uses dynamic typing - variable types are automatically inferred from their values. The language supports the following primitive types:
fr num = 42; // integer
fr pi = 3.14; // float
fr message = "Hello world"; // string
fr isFalse = cap; // boolean (false)
fr isTrue = noCap; // boolean (true)
fr empty = ghosted; // similar to null/nil in other languages
Arithmetic operations can be peformed between strings, integers and floats:
fr sum = 5 + 10; // 15
fr product = 4 * 2.5; // 10.0
fr strings = "Hello " + "World"; // "Hello World"
fr complex = "Result: " + (3 + 4.5); // "Result: 7.5"
Arrays and Maps
For complex data types, noCap supports arrays and maps. Arrays can contain multiple items of different types and use 1-based indexing (starting from 1, not 0):
fr arr = [1, "hello", cap];
arr[3]; // cap
arr[0]; // error: out of bounds
arr[1] = 2; // [2, "hello", cap];
Maps are key-value collections that support all primitive types as keys, including strings, numbers, and booleans:
fr map = {
"hello": "world",
cap: "lie",
1+2: 3
}
map[cap]; // "lie"
map[3]; // 3
map[noCap] = "truth"; // {"hello": "world", cap: "lie", 3: 3, noCap: "truth"}
Functions
Functions in noCap are declared using the cook keyword. You can return values from functions using yeet. If no explicit return is provided, the last statement is returned by default.
cook greet(name) {
yeet "Hello, " + name + "!";
}
cook calculateAge(birthYear) {
2025 - birthYear; // Implicit return
}
greet("Alice"); // Hello Alice!
calculateAge(2000); // 25
noCap functions are first-class citizens, which means they can be assigned to variables and passed around as arguments to other functions. This enables powerful patterns like closures and currying.
fr createDiscountCalculator = cook(discountRate) {
yeet cook(price) {
fr discount = price * (discountRate / 100);
yeet price - discount;
}
}
fr studentDiscount = createDiscountCalculator(15);
studentDiscount(100); // 85
Builtins
Apart from the user defined functions, noCap comes with a few built in functions.
The most common one you’ll see is caughtIn4K, which prints anything to the console:
caughtIn4K("Hello world!");
// You can also pass multiple items
// which will be printed on separate lines
caughtIn4K(cap, 1, "yo");
Next is count which is used to get the count of characters in a string or items in array or keys in a map:
count("len"); // 3
count([1,2]); // 2
count({ cap: "lie" }); // 1
spread generates arrays from strings or number ranges:
spread("cap"); // -> ["c", "a", "p"]
spread(1,4); // -> [1, 2, 3, 4]
And lastly slide lets you push items to an array:
fr items = [1,2,3,4];
items = slide(items, 5); // [1,2,3,4,5]
Logical Operators
noCap supports all the standard logical operators, which can be used to produce boolean output.
5 >= 6; // cap
6 > 5; // noCap
5 is 6; // cap
5 aint 6; // noCap
nah (5 >= 6); // noCap
You can also combine multiple logical operators using and / or:
cap is noCap or 7 >= 6; // noCap
5 is 5 and 2 aint 6; // noCap
Lastly all values other than ghosted and cap are considered truthy in logical contexts:
2 or cap; // noCap
nah 12; // cap
ghosted and 12; // cap
"" and 0; // noCap
Control Flow
noCap allows you to perform actions if some boolean conditions are met using vibe and nvm:
fr isLoggedIn = cap;
vibe(isLoggedIn is cap) {
yeet "Please log in";
} nvm {
yeet "Welcome back!";
}
For multiple conditions you can use unless
fr score = 68;
vibe(score > 70) {
yeet "great score";
} unless(score > 50) {
yeet "not bad";
} nvm {
yeet "no";
}
Loops
Lastly noCap also has loops which allow you to iterate over arrays or maps using the stalk in syntax.
fr sum = 0;
stalk (i in spread(1,4)) {
sum = sum + i;
}
fr scores = {"Alice": 90, "Bob": 85, "Carol": 95};
stalk(person in scores) {
caughtIn4K(person + " scored " + scores[person]);
}
For loops that run until a condition is true, use onRepeat:
fr countdown = 5;
onRepeat(countdown > 0) {
caughtIn4K("T-minus " + countdown);
countdown = countdown - 1;
}
And you can also skip entries in a loop using pass and break out of a loop using bounce
fr numbers = [12, -5, 8, 0, 15];
stalk(num in numbers) {
vibe(num < 0) {
pass; // Skip negative numbers
}
vibe(num is 0) {
bounce; // Stop when we hit zero
}
caughtIn4K("Processing: " + num);
}