shrt is a transpiler — a thin layer of syntax sugar that compiles down to plain C++. Any valid C++ is valid shrt. You can mix freely.
The premise is simple:
The language reserves single letters for itself (i, c, s, e, r, f, w, …) so the keywords become mundane and clear, while your variables and functions must be two characters or longer — forcing you to write what you actually mean.
No more int n or auto x hiding in a function.
Be expressive. Be verbose. Be readable.
Anything you don't want shortened, just write the original C++ keyword — e means enum class by default, but if you want a plain C-style enum, type it out. shrt never gets in your way; it only ever adds.
Variable, function, and type names must be at least two characters. Single letters are reserved keywords. Template type parameters (T, U) are exempt.
Source files use .shrt. The transpiler emits .shrt.cpp as an intermediate before the C++ compiler picks it up.
i vector → #include <vector> · li mylib.h → #include "mylib.h"
Prefix any identifier with $ and shrt prepends std:: for you. $vector<int>, $cout, $string.
if and w conditions don't need parentheses. The condition is everything between the keyword and the opening {. Parens still work if you want them.
if health <= 0 { die(); } w running { tick(); }
which replaces switch, the case keyword disappears, just write the label value followed by a colon.
which signal { 1: start(); b; 2: stop(); b; default: r; }
Truthiness-checked fallback. If the left side is falsy, the right side fires. The right side can be an expression (yields a value) or a statement (returns, calls, breaks — anything). Inspired by GCC's ?:, Kotlin's guards, and bash's ${var:-default}.
Player* player = find_player(idx); player ?? r nullptr; player->name ??= "Anonymous"; a health = player->hp ?? 100;
=> always means "what follows is the result."
// expression body int square(int num) => num * num; // standalone lambda a bump = => counter + 1; a snapshot = [=] => counter;
The natural sibling of ??. Chains member access without crashing on null pointers along the way. If any link in the chain is null, the whole expression evaluates to null. Borrowed from Kotlin, Swift, C#.
Pairs gorgeously with the Elvis: player?.name ?? "Anonymous" reads almost as English.
a weapon_name = player?.weapon?.name ?? "fists"; shop?.buy("potion"); // silently skipped if shop is null Player* hero = roster?.find(idx);
Reuses the $ sigil. Anything inside {…} is an expression — interpolated into the string. Transpiles to std::format, so it's type-safe and as fast as printf.
a greeting = $"Hello {name}, you have {coins} gold!"; a report = $"HP {player->hp} / {player->max_hp}"; a math = $"sum = {x + y}";
Thin wrapper around std::cout << … << std::endl. Anything streamable into cout can be piped into p. Composes naturally with $"…" interpolation.
p "starting up"; p $"Hello {name}, gold {coins}"; p player?.name ?? "Anonymous";
Stolen from Go, Zig, and Swift. The statement (or block) following defer is executed at scope exit — no matter how the scope exits (normal return, early return, exception). Fits C++ RAII philosophy without writing a wrapper class for one-off resources.
Transpiles into an anonymous scope-guard whose destructor fires the deferred work — same trick libraries like gsl::finally and scope_guard use, just baked into the language.
void process(k char* path) { a* file = $fopen(path, "r"); file ?? r; defer $fclose(file); // ...work with file... // fclose fires automatically on any exit }
Ten snippets — C++ on the left, shrt on the right. The scroll on the right is always shorter — that's the point.
#include <iostream> int main() { std::cout << "Hello, World!" << std::endl; return 0; }
i iostream int main() { p "Hello, World!"; r 0; }
int fibonacci(int num) { if (num <= 1) return num; return fibonacci(num - 1) + fibonacci(num - 2); }
int fibonacci(int num) => num <= 1 ? num : fibonacci(num - 1) + fibonacci(num - 2);
int gcd(int alpha, int beta) { while (beta != 0) { int temp = beta; beta = alpha % beta; alpha = temp; } return alpha; }
int gcd(int alpha, int beta) { w beta != 0 { int temp = beta; beta = alpha % beta; alpha = temp; } r alpha; }
struct Node { int value; Node* next; }; void print_list(Node* head) { if (!head) return; while (head != nullptr) { std::cout << head->value << " "; head = head->next; } }
s Node { int value; Node* next; }; void print_list(Node* head) { head ?? r; w head != nil { p head->value; head = head->next; } }
class Logger { private: static Logger* instance; Logger() { } public: static Logger* get_instance() { if (instance == nullptr) { instance = new Logger(); } return instance; } };
c Logger { pri: static Logger* instance; Logger() { } pub: static Logger* get_instance() { instance ??= new Logger(); r instance; } };
class Point { int px_, py_; public: Point(int px, int py) : px_(px), py_(py) { } int get_x() const { return px_; } int get_y() const { return py_; } int sum() const { return px_ + py_; } };
c Point { int px_, py_; pub: Point(int px, int py) : px_(px), py_(py) { } int get_x() k => px_; int get_y() k => py_; int sum() k => px_ + py_; };
enum class Direction { North, South, East, West }; int delta_x(Direction dir) { switch (dir) { case Direction::East: return 1; case Direction::West: return -1; default: return 0; } }
e Direction { North, South, East, West }; int delta_x(Direction dir) { which dir { Direction::East: r 1; Direction::West: r -1; default: r 0; } }
#include <vector> #include <unordered_map> #include <string> #include <algorithm> class Solution { public: std::vector<std::vector<std::string>> groupAnagrams(std::vector<std::string>& strs) { std::unordered_map< std::string, std::vector<std::string> > groups; for (const std::string& word : strs) { std::string key = word; std::sort(key.begin(), key.end()); groups[key].push_back(word); } std::vector<std::vector<std::string>> result; for (auto& entry : groups) { result.push_back(std::move(entry.second)); } return result; } };
i vector i unordered_map i string i algorithm c Solution { pub: $vector<$vector<$string>> groupAnagrams($vector<$string>& strs) { $unordered_map< $string, $vector<$string> > groups; f (k $string& word : strs) { $string key = word; $sort(key.begin(), key.end()); groups[key].push_back(word); } $vector<$vector<$string>> result; f (a& entry : groups) { result.push_back($move(entry.second)); } r result; } };
#include <iostream> #include <format> #include <string> struct Weapon { std::string name; int damage; }; struct Player { std::string name; Weapon* weapon; int hp; }; void inspect(Player* player) { if (!player) return; std::string weapon_name = player->weapon ? player->weapon->name : "fists"; int weapon_dmg = player->weapon ? player->weapon->damage : 1; std::cout << std::format( "{} wields {} ({}dmg) — {}hp", player->name, weapon_name, weapon_dmg, player->hp ) << std::endl; }
i iostream i format i string s Weapon { $string name; int damage; }; s Player { $string name; Weapon* weapon; int hp; }; void inspect(Player* player) { player ?? r; a weapon_name = player->weapon?.name ?? "fists"; a weapon_dmg = player->weapon?.damage ?? 1; p $"{player->name} wields {weapon_name} ({weapon_dmg}dmg) — {player->hp}hp"; }
#include <queue> #include <vector> enum class Tile { Floor, Wall, Goal }; struct Cell { int px, py; bool operator==(const Cell& other) const { return px == other.px && py == other.py; } }; std::vector<Cell> bfs( const std::vector<std::vector<Tile>>& grid, Cell start) { std::queue<Cell> frontier; frontier.push(start); auto in_bounds = [&]() { return !grid.empty(); }; if (!in_bounds()) return {}; while (!frontier.empty()) { Cell cur = frontier.front(); frontier.pop(); if (grid[cur.py][cur.px] == Tile::Goal) { return {cur}; } // expand neighbors... } return {}; }
i queue i vector e Tile { Floor, Wall, Goal }; s Cell { int px, py; bool op==(k Cell& other) k => px == other.px && py == other.py; }; $vector<Cell> bfs( k $vector<$vector<Tile>>& grid, Cell start) { $queue<Cell> frontier; frontier.push(start); a in_bounds = => !grid.empty(); in_bounds() ?? r {}; w !frontier.empty() { Cell cur = frontier.front(); frontier.pop(); if grid[cur.py][cur.px] == Tile::Goal { r {cur}; } // expand neighbors... } r {}; }