日本語

Classes

LuneScript supports class-based object-oriented programming.

Definition and Instantiation

Classes are defined with the class keyword and instantiated with new.

class MyClass {
    pri let val: int;
    
    // Constructor
    pub fn __init( val: int ) {
        self.val = val;
    }
    
    // Method
    pub fn func(): int {
        return self.val;
    }
}

let obj = new MyClass( 10 );
print( obj.func() ); // 10

Accessors

Accessors can be automatically generated in the format {getter, setter} during member definition.

class Data {
    pri let mut val: int {pub, pub}; // getter=pub, setter=pub
    pub fn __init( val: int ) { self.val = val; }
}
let mut d = new Data( 1 );

$ Operator

To access an automatically generated getter, prepend $ to the member name. This is syntactic sugar that is internally converted into a call to the get_MemberName() method.
For setter, a method named set_MemberName is generated.

Why not "properties"?
LuneScript intentionally avoids "properties" (a style found in some languages where method calls look like direct access). This ensures that developers can clearly distinguish between a simple data assignment/reference and a method call with potential side effects directly in the source code.

class Data {
    pri let mut val: int {pub, pub};
    pub fn __init( val: int ) { self.val = val; }
}
let mut d = new Data( 1 );
print( d.$val ); // Getter call ($ sign)
d.set_val( 20 ); // Setter call (set_MemberName)
print( d.$val );

Omitting Access Control

If a setter is not needed, omit the second specification or specify non.

class AccessorTest {
    pri let val1: int {pub};       // Getter only (no setter)
    pri let val2: int {pub, non}; // Same as above
}

Immutable Return Value

To make the return value of a getter immutable, append &.

class ListWrapper {
    pri let mut list: List<int> {pub&, pub};
}
// $list returns &List<int> (read-only), so it cannot be modified

Inheritance and Overriding

Single inheritance is possible with extend. The override keyword is mandatory for overriding methods.

class Base {
    pub fn func() { print( "Base" ); }
}

class Sub extend Base {
    pub override fn func() {
        super(); // Parent class call
        print( "Sub" );
    }
}

In a subclass constructor, you must call super() at the beginning.

Abstract Classes

A class that has methods without implementation (abstract fn) must be defined as an abstract class.

abstract class Animal {
    pub abstract fn cry();
}

Interfaces

Interfaces can be used instead of multiple inheritance. Interfaces do not have implementations.

interface Runner {
    pub fn run();
}

class Dog extend (Runner) {
    pub fn run() { print( "Run!" ); }
}

When implementing multiple interfaces, write it as extend (IF1, IF2).

A feature that exposes (delegates) the methods of a composed (contained) object as if they were its own.

class Inner {
    pub fn foo() { print("Inner.foo"); }
}
class Wrapper {
    pri let inner: Inner;
    advertise inner; // Expose public methods of inner as methods of Wrapper
}

Mapping

By declaring extend (Mapping), reciprocal conversion with Map (JSON-like objects) becomes possible.

class User extend (Mapping) {
    let name: str {pub};
    let age: int {pub};
}

// Create from JSON (Map)
let user = unwrap User._fromMap( { "name": "John", "age": 20 } );
// Convert to Map
let map = user._toMap();

Prototype Declarations

Used when writing the implementation of a method later (or in a separate file). Useful when mutual references are needed.

class Test {
    pub fn func(); // Declaration only
}
// Implementation
pub fn Test.func() {
    print( "impl" );
}