# Introduction

## What is stampit

`stampit` is a JavaScript module which implements the [**stamp** specification](https://stampit.js.org/essentials/specification). **Stamps** are composable factory functions.

**Think of&#x20;*****stamps*****&#x20;as classic classes but without any limits, boundaries, or rules.**

The stamps brag large amount of features and things you can do with your objects and/or stamps.

Head straight to the [Quick Start](https://stampit.js.org/api/quick-start) page for code examples.

![Object instances created from classes vs stamps.](https://1681072127-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LBFDyli93b3DkmP1MWz%2F-LBFDzVCs7MXZ5zFrsca%2F-LBFE3SlonIOZYCL91vm%2Fclass_vs_stamp.png?generation=1524985778364294\&alt=media)

## Differences from classes

* Inheritance
  * Classes
    * Classes do child+parent+parent+parent... inheritance chains. See picture above.
    * When you extend a class you link class prototypes.
  * Stamps
    * Stamp are single object + single prototype. See picture above.
    * When you "extend" you separately merge [methods](https://stampit.js.org/api/methods), separately merge [properties](https://stampit.js.org/api/properties), separately merge [static properties](https://stampit.js.org/api/static-properties), separately merge [initializers](https://stampit.js.org/api/initializers) (aka constructors), etc etc etc.
    * That's why it is not just inheritance, but special type of object composition. The stamp composition algorithm is [standardized](https://stampit.js.org/essentials/specification/merging-algorithm).
    * You can influence composition result with your code at runtime using the [composers](https://stampit.js.org/api/composers) feature.
* Object creation
  * Classes
    * In most programming languages you execute only one constructor per class.
    * To pass data to the parent constructor you have to manually call parent constructor `this.super(data)`.
    * To create an object you need to use the `new` keyword: `const object = new MyClass()`.
  * Stamps
    * Stamp executes every initializer (aka constructor) it has.
    * All initializers receive exactly the same set of arguments, no need to manually pass data.
    * The initializer execution sequence is the same as the stamp composition sequence.
    * To create an object you [call stamp](https://stampit.js.org/api/quick-start) as a function: `const object = MyStamp()`.

## History

The original idea of Stamps belongs to [Eric Elliott](https://ericelliottjs.com/). See his [first commit](https://github.com/stampit-org/stampit/commit/ac330e8537e349a9640bbe4a34c63150db445a20) from 11 Feb 2013 in the stampit repository. Since then the idea evolved to the [specification](https://stampit.js.org/essentials/specification) and a whole [ecosystem](https://stampit.js.org/ecosystem/ecosystem-overview) of mini modules.

## Using Stamps

Head straight to the [Quick start ](https://stampit.js.org/api/quick-start)for code examples.

## Ecosystem

Stampit have a lot of helper modules. You can always find the list of official NPM packages here: <https://www.npmjs.com/~stamp>

See more information on the [Ecosystem](https://stampit.js.org/ecosystem/ecosystem-overview) page.

## Quick code example

The example below introduces `GraphPoint` and `GraphLine` stamps (aka blueprints, aka factory functions, aka behaviours).

Let's start by declaring the `Point` stamp.

```javascript
const stampit = require("stampit");

const Point = stampit({
  props: { // default property values
    x: 0,
    y: 0
  },
  init({ x, y }) { // kinda constructor
    if (x != null) this.x = x;
    if (y != null) this.y = y;
  },
  methods: { // that goes to the prototype
    distance(point) {
      return Math.sqrt((this.x - point.x)**2 + (this.y - point.y)**2);
    }
  }
});
```

That's how you create instance of the above stamp.

```javascript
// Creating instance of the Point.
const point = Point({ x: 12, y: 42 });
// Calling a method.
point.distance({ x: 13, y: 42 }) === 1.0;
```

Now let's "inherit" the `Point` to create a `Circle`. We will add `radius` property to the mix.

```javascript
// kinda inheritance, but not really
const Circle = stampit(Point, {
  props: {
    radius: 1
  },
  init({ radius }) {
    if (radius != null) this.radius = radius;
  },
  methods: { // that goes to the prototype
    distance(point) {
      // Calling the "super class" by instantiating Point stamp
      return Point(point).distance(this) - this.radius;
    }
  }
});
```

When creating instance of the `Circle` you will actually call **TWO** different initialisers (aka constructors). Stamps have multiple initialisers.&#x20;

```javascript
// TWO different initializers will be executed here!!!
const circle = Circle({ x: 12, y: 42, radius: 1.5 });
circle.distance({ x: 14, y: 42 }) === 0.5;
```

Now, declaring couple of additional stamps. We'll use them to enrich JavaScript drawable objects.

```javascript
const Tagged = stampit({
  props: {
    tag: ""
  },
  init({ tag }) {
    this.tag = tag || this.tag;
  }
});

const Colored = stampit({
  props: {
    color: "#000000"
  },
  init({ color }) {
    this.color = color || this.color;
  }
});
```

The `Drawable` behaviour. We have to make sure that developers implement the `draw()` method when using this stamp.

```javascript
const Drawable = stampit(
  Tagged,
  Colored,
  init() { 
    assert(typeof this.draw === "function", "you must implement the draw() method");
  }
);
```

Now let's implement the `GraphPoint` stamp.

```javascript
const GraphPoint = stampit(Drawable, Circle, {
  methods: {
    draw(ctx) {
      ctx.setColor(this.color);
      ctx.drawFilledCircle(this.x, this.y, this.radius);
      if (this.tag) 
        ctx.drawText(this.x + this.radius, this.y + this.radius, this.tag);
    }
  }
});
```

Please, note we are executing **FOUR** intializers here.

```javascript
// FOUR different initializers will be executed here.
const graphPoint = GraphPoint({ 
  x: 12, 
  y: 42, 
  radius: 1.5, 
  color: "red", 
  tag: "start" 
});
graphPoint.draw(someDrawingContext);
```

`Line` primitive.

```javascript
const Line = stampit({
  props: {
    point1: Point({ x: 0, y: 0 }),
    point2: Point({ x: 0, y: 0 })
  },
  init({ point1, point2 }) {
    this.point1 = Point(point1);
    this.point2 = Point(point2);
  },
  methods: {
    middlePoint() {
      return Point({ 
        x: (this.point1.x + this.point2.x) / 2, 
        y: (this.point1.y + this.point2.y) / 2
      });
    }
  }
});

const line = Line({ point1: { x: 12, y: 42 }, point2: { x: 34, y: 40 } });
```

Our final destination - a drawable graph line.

```javascript
const GraphLine = stampit(Drawable, Line, {
  methods: {
    draw(ctx) {
      ctx.setColor(this.color);
      ctx.drawLine(this.point1.x, this.point1.y, this.point2.x, this.point2.y);
      if (this.tag) 
        ctx.drawText(this.middlePoint().x, this.middlePoint().y, this.tag);
    }
  }
});
```

And the usage.

```javascript
const graphLine = GraphLine({ 
  point1: { x: 12, y: 42 }, 
  point2: { x: 34, y: 40 }, 
  color: "red", 
  tag: "March" 
});
graphLine.draw(someDrawingContext);
```

The idea is - separate concerns. We split our logic into several reusable highly decoupled primitive behaviours (Point, Colored, Tagged, Circle, Line).

It's importan to distinguish the "**is**" and "**has**" composition.

The above has:

* `Point` concern and all related functionality in a *separate* stamp.
* `Circle` concern and the related functionality *separated*. `Circle` **is** an extension of the `Point`.
* `Tagged` concern in a *separate* stamp.
* `Colored` concern in a *separate* stamp.
* `GraphPoint` concern **is** `Circle`, `Tagged` and `Colored` concerns combined.
* `Line` concern - it **has** two `Points`.
* `GraphLine` - **is** the `Line` but with additional `Tagged` and `Colored` functionalities.

&#x20;You can't do anything like that with classes. And the resulting code is more readable than classes.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://stampit.js.org/master.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
