This is one of my practice during Senior High School period.
hoshimeans both$\mathop{desire}\limits^{欲しい}$ and$\mathop{stars}\limits^{星}$ in Japanese, which also represents my silly wishes: I hope some day I would become the stars I once live up to.
hoshi-lang is a statically-typed, general-purpose programming language with a focus on performance, safety, and modern language features. It is designed to be a simple yet powerful tool for building a wide range of applications.
This project is currently under active development and is a personal exploration into language design and implementation.
- Object-Oriented: hoshi-lang's OOP is based on a composition model using
interface,struct, andimpl. - Generic Programming: Supports generic programming with
templates for both functions and structs. - Operator Overloading: Allows for custom behavior for operators like
+,-,*,/, etc. - Memory Safety: Automatic Reference Counting (ARC) for memory management.
- Type Introspection: Runtime type inspection with
typeidandinterfaceof. - Dynamic Casting: Safe casting of interface objects back to their concrete
structtype usingdyn_cast. - Modular Programming: Supports modules with the
usestatement. - Variadic Arguments: Functions can accept a variable number of arguments.
- Lambda Expressions: Concise syntax for creating anonymous functions.
- Threading: Support for multi-threaded programming.
- Rich Standard Library: A growing standard library with support for strings, vectors, file I/O, and more.
use lang "builtin"
use io "std/io"
interface Greeter {
say() : none
}
struct Person {
name: string,
constructor(name: string),
}
impl Person {
constructor(name: string) {
this.name = name
}
}
impl Person : Greeter {
say() : none {
io.println("Hello, " + this.name)
}
}
func main() : int {
let p = Person("world")
let greeter = Greeter(p)
greeter.say()
return 0
}
In hoshi-lang, all data types are heap-allocated objects. This includes primitives like int, bool, etc., which are "boxed" into object wrappers. The compiler and runtime manage these objects through pointers.
All objects share a common header:
| Offset | Field | Type | Description |
|---|---|---|---|
| 0-7 | gc_refcount |
unsigned long long |
The object's current reference count. |
| 8-15 | type_id |
unsigned long long |
A unique ID for the object's runtime type. |
Specific object types then have their own layouts following this header.
Interface objects are special "shell" objects that enable polymorphism. When a struct instance is cast to an interface, a new interfaceObject is created with the following layout:
| Offset | Field | Description |
|---|---|---|
| 0-15 | (Standard Header) | gc_refcount and type_id for the interface object itself. |
| 16-23 | this Pointer |
A pointer to the concrete struct instance that implements the interface. |
| 24-31 | gc_refcount_increase V-Ptr |
A virtual function pointer to the increase GC function for the concrete struct. |
| 32-39 | gc_refcount_decrease V-Ptr |
A virtual function pointer to the decrease GC function for the concrete struct. |
| 40+ | Virtual Method Pointers | A sequence of function pointers to the concrete implementations of the interface's methods (the v-table). |
This structure is created by the compiler via the construct_interface_impl IR instruction.
Memory is managed via Automatic Reference Counting (ARC).
- When an object is created or a reference is copied, its
gc_refcountis incremented. - When a reference goes out of scope or is overwritten, the
gc_refcountis decremented. - When the count reaches zero, the object is deallocated.
The compiler is responsible for generating calls to the appropriate _gc_refcount_increase and _gc_refcount_decrease functions for each type at the right places.
hoshi-lang now supports callable objects and lambda expressions, allowing for more flexible and functional programming styles.
func test_lambda(x: int, y: int, f: func (int, int) : int) : int {
return f(x, y)
}
func main() : int {
let salt = 114514
let closure = func[salt] (x: int, y: int) : int {
return x + y + this.salt
}
let result = test_lambda(2, 3, closure)
return result
}
hoshi-lang now has basic support for multi-threading.
use threading "threading"
use runtime "runtime"
func worker() : none {
runtime.puts("Hello from worker thread!")
}
func main() : int {
let th = threading.Thread(func[] () : none {
worker()
})
th.start()
th.join()
return 0
}
You can now de-structure arrays and structs into individual variables.
let [x, y] = Point(1, 2)
let [a, b, c] = int[3](10, 20, 30)
The alias keyword can be used to create a new name for an existing type.
alias Map = hashMap.HashMap<str.Str, int>
func main() : int {
let m : Map = Map()
m["Hello"] = 0xe1751aff
return 0
}
hoshi-lang's standard library is growing and currently includes:
console: For console input and output.file: An interface for file-like objects.fs: For file system operations.hashMap: A hash map implementation.io: For I/O operations.json: For parsing JSON.math: For mathematical functions.runtime: For runtime-specific functions.str: A string library.threading: For multi-threaded programming.vec: A dynamic array implementation.
macOS / Linux:
make cmake_debug
make build_debug
make packageWindows:
mkdir build
cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release./hoshi_lang [options] <input_file>Options:
-o <output_file>: Specify the output file name.-D <key> <value>: Define a macro.
Below are benchmark results comparing hoshi-lang with other popular languages across various tasks. All benchmarks were performed on a macOS system with an Apple M1 chip.
The following table shows execution times for several computational benchmarks. Lower values are better.
| Benchmark | hoshi-lang | C++ (Clang++) | Python 3 | Java (OpenJDK) |
|---|---|---|---|---|
| Fib(40) | 0.34s | 0.58s | 10.23s | - |
| Basic Type Loop | 0.35s | 0.54s | 9.53s | - |
| JSON Parsing | 0.34s | - | - | - |
| String Ops | 0.18s | 0.39s (O3) | 0.19s | 1.15s |
With the introduction of datastruct, hoshi-lang now supports stack-allocated value types, significantly improving performance for small, short-lived data structures by eliminating heap allocation and ARC overhead.
| Language | Implementation | Result (10M iterations) |
|---|---|---|
| hoshi-lang | Datastruct (Stack) | < 1ms |
| hoshi-lang | Legacy Struct (Heap) | 237ms |
| C++ | Value Type (Stack) | 24ms |
| Java | Heap Object | 6ms |
| Python | Legacy Class | 759ms |
The following sizes were measured for minimal programs in release mode.
| Program | Binary Size (Release) |
|---|---|
size1.hoshi (Minimal) |
~39 KB |
size2.hoshi (Basic Logic) |
~39 KB |
size3.hoshi (Standard Lib) |
~58 KB |
- Syntax Definition
- Language Specification
- IR Handbook
- Data Structures (Value Types)
- Arithmetic and Array
- Callable Objects & Lambda Expressions
- Console I/O
- Direct Assignment
- File System
- Finalizers
- HashMap
- Interface and Implementation
- JSON Parsing
- Macros
- Mathematical Functions
- Null Values and Safety
- Nullable and Raw Check Passes
- Operator Overloading
- Result Type
- Runtime Functions
- String Library
- Structured Bindings
- Templates and Generics
- Optimization Strategy
- Threading
- Type Aliases
- Vector Implementation
- Wrapper Objects
- TODO List