mirror of
https://github.com/Open-Argon/docs.git
synced 2026-10-28 09:43:55 +00:00
173 lines
6.0 KiB
Markdown
173 lines
6.0 KiB
Markdown
# Classes and objects
|
|
|
|
Chloride has "a proper class and inheritance system" (per the project README) — classes
|
|
are real objects, supporting inheritance and introspection.
|
|
|
|
## Defining a class
|
|
|
|
```
|
|
class name do
|
|
this.__init__(self) = do
|
|
term.log("hello world")
|
|
|
|
term.log(name) # the class itself
|
|
term.log(name()) # calling it constructs an instance; prints "hello world"
|
|
```
|
|
|
|
(from [`class_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/class_test.ar))
|
|
|
|
Inside a class body, `this.method_name(self, ...) = do ... ` defines an instance method.
|
|
The first parameter is conventionally named `self` and refers to the instance, similar to
|
|
Python.
|
|
|
|
## Inheritance
|
|
|
|
Pass the parent class in parentheses after the class name:
|
|
|
|
```
|
|
class test(name) do
|
|
this.wow(self) = do
|
|
term.log(self)
|
|
|
|
test().wow()
|
|
```
|
|
|
|
(from [`class_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/class_test.ar)) — `test` inherits from
|
|
`name`.
|
|
|
|
## Public vs. private members
|
|
|
|
Members defined with `this.member = ...` are **public** — accessible from outside the
|
|
class. Members defined with a plain `let` inside the class body are **private** — only
|
|
accessible from within the class's own methods:
|
|
|
|
```
|
|
class some_public_private_statics do
|
|
this.some_public = "hello im public"
|
|
let some_private = "hello im private"
|
|
|
|
this.get_the_private(self) = do
|
|
return some_private
|
|
|
|
term.log(some_public_private_statics.some_public) # OK — public
|
|
term.log(some_public_private_statics.some_private) # errors — private, not accessible
|
|
```
|
|
|
|
(from [`class_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/class_test.ar), which explicitly comments
|
|
that accessing the private member from outside `# will error`)
|
|
|
|
## Static vs. instance members
|
|
|
|
`this.some_public` in the example above is a **static/class-level** member (accessed on
|
|
the class itself, `some_public_private_statics.some_public`, without needing an instance).
|
|
Instance data is normally set inside `__init__` via `self.attr = value`:
|
|
|
|
```
|
|
class custom_range do
|
|
this.__init__(self, stop) = do
|
|
self.stop = stop
|
|
this.__iter__(self) = custom_range_iterator(self.stop)
|
|
```
|
|
|
|
(from [`custom_range.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/custom_range.ar))
|
|
|
|
## The constructor: `__init__`
|
|
|
|
`__init__` runs when the class is called like a function:
|
|
|
|
```
|
|
class something do
|
|
this.__init__(self, x) = do
|
|
self.x = x
|
|
this.f(self) = do
|
|
term.log(self, self.x, self.x = self.x + 1)
|
|
|
|
let instance = something(0)
|
|
instance.f() # logs the instance, its x, and increments x
|
|
```
|
|
|
|
(from [`import_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/import_test.ar), showing that an
|
|
assignment like `self.x = self.x + 1` is itself an expression that returns the assigned
|
|
value — this is why it can appear as a `term.log(...)` argument.)
|
|
|
|
## Operator overloading (dunder methods)
|
|
|
|
Classes can customise how they behave with built-in operators and syntax by implementing
|
|
"dunder" (double-underscore) methods. These are exactly how the built-in types (`number`,
|
|
`string`, `array`, etc.) implement their own behaviour, so you can make your own types work
|
|
just as naturally.
|
|
|
|
| Method | Triggered by |
|
|
|---|---|
|
|
| `__init__(self, ...)` | calling the class, e.g. `MyClass(args)` |
|
|
| `__string__(self)` | converting to a string / `term.log` |
|
|
| `__getitem__(self, key)` | `obj[key]` |
|
|
| `__setitem__(self, key, value)` | `obj[key] = value` |
|
|
| `__contains__(self, item)` | `item in obj` |
|
|
| `__iter__(self)` | starting a `for` loop over `obj` |
|
|
| `__next__(self)` | each step of a `for` loop, on an iterator object |
|
|
| `__equal__` / `__not_equal__` | `==` / `!=` |
|
|
| `__less_than__` / `__less_than_equal__` / `__greater_than__` / `__greater_than_equal__` | `<`, `<=`, `>`, `>=` |
|
|
| `__add__` / `__subtract__` / `__multiply__` / `__division__` / `__floor_division__` / `__modulo__` / `__exponent__` | `+`, `-`, `*`, `/`, `//`, `%`, `**` |
|
|
| `__negation__` | unary `-` |
|
|
| `__hash__` | using the object as a dictionary key |
|
|
| `__name__` | a class-level display name (used by exception types, for example) |
|
|
|
|
### Example: custom subscript / slice handling
|
|
|
|
```
|
|
class x do
|
|
this.__getitem__(self, key) = key
|
|
this.__setitem__(self, key, value) = key
|
|
|
|
term.log(x()[1:2, 2])
|
|
term.log(x()[1:2, 2] = 1)
|
|
```
|
|
|
|
(from [`slice.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/slice.ar))
|
|
|
|
### Example: making a class iterable
|
|
|
|
```
|
|
class custom_range_iterator do
|
|
this.__init__(self, stop) = do
|
|
self.current = 0
|
|
self.stop = stop
|
|
this.__next__(self) = do
|
|
if (self.stop <= self.current) do
|
|
throw StopIteration()
|
|
let result = self.current
|
|
self.current = self.current + 1
|
|
return result
|
|
|
|
class custom_range do
|
|
this.__init__(self, stop) = do
|
|
self.stop = stop
|
|
this.__iter__(self) = custom_range_iterator(self.stop)
|
|
```
|
|
|
|
(from [`custom_range.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/custom_range.ar)) — see
|
|
[`for` loops and iterators](../control-flow/for/README.md) for how this plugs into `for`.
|
|
|
|
## Introspection
|
|
|
|
- `type(obj)` returns an object's class/type.
|
|
- `is_instance(obj, SomeType)` checks whether `obj` is an instance of `SomeType` (or a
|
|
subclass).
|
|
|
|
```
|
|
term.log(type(5)) # number
|
|
term.log(is_instance(5, number)) # true
|
|
```
|
|
|
|
You can also assign to class-level attributes dynamically through `type()`:
|
|
|
|
```
|
|
term.log(type(some_public_private_statics_instance).some_public = 10)
|
|
```
|
|
|
|
(from [`class_test.ar`](https://git.wbell.dev/Open-Argon/Chloride/src/commit/8e1ee06b88200ab112cf34e49efe969030ea435c/tests/class_test.ar))
|
|
|
|
## Next
|
|
|
|
- [Errors and exceptions](../error-handling/README.md) |