Nitpick Object Orientation & Traits

Nitpick employs a strict, composition-over-inheritance model. It completely rejects classic class-based inheritance in favor of interfaces (Traits) and isolated data (Structs).

1. Traits and Implementation

A trait defines a set of functions that a type must implement to satisfy a behavioral contract.

trait:Serializable = {
    func:to_bytes = buffer();
};

struct:Message = {
    int32:id;
};

impl:Serializable:for:Message = {
    func:to_bytes = buffer() {
        // ... serialize logic ...
        pass result;
    };
};

2. Dynamic Dispatch

By default, trait implementations are statically resolved at compile-time (monomorphization) to guarantee performance and zero-cost abstraction. If runtime polymorphism is absolutely required, developers must explicitly opt-in using the dyn keyword to create a “fat pointer” trait object.

Message:msg = Message{id: 1};
dyn Serializable:obj = msg;

(Note: Because dynamic dispatch obfuscates the control flow graph, it triggers warnings under strict nitpick-safety profiles).

3. Data Hiding

All struct fields are pub (public) or private by default based on the module visibility rules. To strictly hide internal representations (e.g. for handles or FFI pointers), use the opaque keyword to define a type whose internal layout is entirely unknown to the consumer.

opaque:DatabaseHandle;