---
# System prepended metadata

title: Objects

---

# Objects

An object is just an *instance* of *something*.
In BYOND, an object-oriented programming langauge, objects can **inherit** from other objects.
This means they have an "Is A" relationship.

Example:

```DM

/datum
    var/a_variable = 1
    
/datum/subclass
    var/b_variable = 2

/atom
    var/c_variable = 3

/obj
    var/d_variable = 4

/obj/item
    var/e_variable = 5
```

## Inheritance, Types

In the above I defined 5 variables on 5 **types**.
In BYOND, every object has a type. That's what identifies **what the object is.**

Object types can inherit from "higher" types.

### Syntatic Sugar

`b_variable` is on /datum/subclass
This object's real path is /datum/subclass
`e_variable` is on /obj/item.
This object's real path is /datum/atom/movable/obj/item.

Why?
In BYOND, there's a few "base" types of objects (see: [Datatypes](/SV6Mrc0HQzuXOtpCUjog3Q)). Things like /image, /icon, /mutable_appearance, /world, /sound, /client, etc etc.
You can define new variables on most of these (some can't be modified), and override their procs (more in the [Procs](/CEUf9gDvQbmdRhE7TpybRg) section).
But anything **you** define is a subtype of /datum. The real inheritance tree is:
```DM
/datum
    /atom
        /turf
        /area
        /movable
            /mob
            /obj
```
What you see as a coder within the engine is:
```DM
/datum
/atom
/turf
/area
/mob
/obj
```
Note how /atom/movable doesn't have its own "top level shortcut". To access it you just do /atom/movable.

### Inheritance
Any child path of a parent path inherits all of its properties, whether it's a variable or a function.
From the example above,
/datum now has `a_variable`
/datum/subclass has both that and `b_variable`
/obj has `a_variable`, and `c_variable`, and `d_variable`, but not `b_variable` as it doesn't inherit from /datum/subclass - it inherits from /atom/movable, which inherits from /atom, which inherits from /datum
/obj/item has all of that as well as `e_variable`, inheriting from /obj

**Variables inherit the same compile-time/initialization values as the object above them.**
This means if you default a variable to, say, in the example, `a_variable` as 1, and you access it on /obj/item, it'll still have 1 (as long as you didn't change it!)

**Functions inherit the same functionality as the object above them, unless explicitly overridden.**
```
/datum/proc/say_hello()
    world.log << "Hello!"

/datum/subtype/say_hello()
    world.log << "Hi!"
```
Calling say_hello() on:
/datum gets you `Hello!`
/datum/subtype gets you `Hi!`
**/atom** gets you `Hello!` since it wasn't overridden on that level.

Remember from the Procs section that you can call `..()` to call the function override on the same level, or a higher level if there's no other override on the same level.
More on this on [Procs](/CEUf9gDvQbmdRhE7TpybRg).

## Definition

Now for a slightly more practical example
```DM
/datum/example
    var/greeting_text = "Hello!"
    var/owner
    var/datum/message/pending

/datum/example/New(owner, showto)
    owner = owner
    if(showto)
        pending = new(showto)

/datum/example/proc/run()
    world.log << greeting_text
    world.log << "\n"
    world.log << "[owner], you have"
    if(pending)
        world.log << " a message: [pending.text]"
    else
        world.log << " no messages pending."

/datum/message
    var/text

/datum/message/New(text)
    src.text = text

/proc/testrun()
    var/datum/example/E = new("User", "This is a message!")
    E.run()
```

Calling `testrun()` displays:
`Hello!`
`User, you have a message: This is a message!`
The next 3 sections describes what we did here.

## Creation

To create an object, we use the `new` keyword.
`var/datum/example/E = new("User", "Text")`
`var/datum/example/E = new /datum/example("User", "Text")`
```
var/datum/example/E

E = new("User", "Text")
```
Each one is valid.
The actual syntax is `new path(arg1, arg2, ...)`
`path` is not required **if you are assigning it to a typed variable.*** It'll create an object of **that type and exactly that type** via **type inference.**
`()` is not required if you aren't passing in parameters to the **constructor**.

In this codebase, we prefer to use the least bit of `new` syntax we're allowed to. If assigning to a typed variable, there's usually no need to specify the path specifically. If there's nothing in the constructor, don't bother putting the `()`.

-- OPINION WARNING --
`new` is also used to create non /datums. BYOND has other top level objects like /icon, /world, /list, etc. To create those, **look up on the BYOND ref for how those work** (we'll cover them a bit later on too) and pass in the necessary arguments. **We prefer you use BYOND's "make this thing" procs for those, instead of new,** i.e.
Not preferred (but also allowed):
```
var/list/L = new()
var/icon/I = new('file.dmi', "state")
```
Preferred:
```
var/list/L = list()
var/icon/I = icon('file.dmi', "state")
```

### Constructors
Objects have a constructor named `/New()`.
You may override this constructor to pass in arguments during `new()` which are **immediately ran.**

In general, you should always call `..()` in New()

#### Atoms
More on this in the Atoms section, but, Atom/New(loc) **always** has `loc` as the first parameter, of **where to create the atom.**

#### So what's this Initialize() business?
You may notice in our codebase that every /atom and deriviative of it has /Initialize(mapload) instead of /New(loc) being used.
The explanation for why is too lengthy for a beginner's guide to BYOND so ~~harass~~ ping your favorite maintainer politely to ask for why wwe do this.
The short of it is **we cannot control when /New() is called, and this is awful. We however, can and do control when /Initialize(mapload) is called. This is more powerful and structured, and allows us to do more modular code.** Do not use /New() instead of /Initialize() for instantiation behavior for /atoms unless you know what you are doing, if you are coding a SS13 codebase with /Initialize() in it.

#### Call order
As mentioned in the Procs section, procs have an order to them. Be careful with New() and Initialize() calls of subtypes to things, as the order code runs **does matter.**

#### WARNING
Object variables instantiate before the /New() call.
It's perfectly valid and legal to do, say,
```
/datum/example
    var/datum/example/other = new
```
And other will be created (and its New() called) before the New() call of the first you tried to create (if you're an experienced coder you'll realize that the example code here will create an infinite loop and crash the server. Hence why **it's important to opt to instantiate things in New() if your object needs it, NOT in the variables.** We don't control the initialization order of the variables as opposed to New(), and we hate it when we can't control things because then it can behave erratically!)

## Access

**Access** an object's variables with
`object.variablename`
**Call** an object's functions with
`object.functionname()`

`.` is the object access operator. You'll use this a ton.
It requires a typed variable.
**Even if the object stored in a variable has a variable or function, you cannot use it with `.` unless it is *casted* to that type.**
A reminder on what typed variables are:
`var/datum/example/thing` <-- `thing` is the variable name, `/datum/example` is the variable's type. You can assign anyhting to this and BYOND will let you, but *please*, only assign sensical things to it (e.g. don't assign some /atom to it for fun).

### References
**Assigning a variable to an object using variable = object is called *referencing* an object.** Referenced objects are kept in memory because BYOND assumes you're still using it.
Setting a variable with an object in it to `null` is called **clearing the reference.** The object isn't necessarily deleted, you just clear the "hard reference" to it. See garbage collection section.

### `:`
If you read the BYOND guide like I told you, you'll note that `:` is called the runtime lookup operator, and doesn't require a typed variable.
Convenient, yes?

**This is entirely banned in our codebase. Unlike with atom /New(), this is non negotiable.** It is a horrific practice. The type checks are done by the compiler and serve to help **you**, the coder, notice when you're doing something wrong. `:`'s being done wrong will pass the compile and **runtime error later, leading to a headache.** There's nothing wrong with this in theory... *if your coders are 100% perfect and never make mistakes*. Seriously, don't try it.

## Deletion

In BYOND, deleting an object is done by
`del O` where O is an object.

This is banned in our codebase, because it's time for a quick primer in **garbage collection!**

### Garbage Collection
BYOND (like literally every other computer program in current technology) has finite amounts of storage and resources.
Every object you create spends these resources. You'll eventually run out if you don't sweep up and remove things you don't need, and the server will crash.

#### Analogy
Stolen from some codebase:

Imagine an object as a TV in a living room.
When someone enters to watch TV, they turn it on.
Others coming into the room will just watch the TV, and leave when they're done.
Being polite people, **whoever exits last, has the responsibility of turning the TV off.**

When you ask a datum to delete itself with `qdel(yourdatum)`, it asks everyone to stop and leave the room.

#### Explanation
The TV here is our object. We only have so many of those (because we have a limited amount of memory to store objects!) and we can only **reuse the memory used to store the TV if it's turned off.**
People coming in and turning on the TV is the first time someone references an object.
People leaving and turning off the TV when everyon's gone is everyone being polite and clearing their references, *freeing* the memory for use again.

#### Outcomes
- The TV asks everyone to stop.
    - Soft deletion: Everyone leaves and turns the TV off. This is fast, seamless, and the only correct way to delete something.
    - Hard deletion: Everyone leaves except for some people who refuses to leave (holding references instead of clearing them). **Someone has to walk in, drag the people out, and turn the TV off by force.** This is hilariously slow and is a severe issue for performance.
- Everyone watching decides they're done with the TV and leaves.
    - References are cleared (the last person turned the TV off): This is a soft deletion in essence and the TV's resource is recycled for use again.
    - References are kept (the TV was left on): **THIS IS A MEMORY LEAK.** This is even worse than hard deletion, and will eventually **crash the server.**

#### Wait, the TV has more than one channel though? What if someone changes it?
That's irrelevant to our analogy. Infact I can't think of a good enough analogy for it but I typed this to be funny.
That's called a "race condition". We won't cover it now, because we don't want to scare you and it's too complicated. See [Timing/Synchronization/Threading](/HVU-IBzWRWOOQyTgrn5-jw)

### Destroy(), qdel()
`del` deletes an object instantly. BYOND is told to scan for any references to it and set them to `null`, and free the memory. It's what hard deletion done by our **custom garbage collector from /tg/** does when it detects a soft deletion didn't work.
This is laggy, and terrible.
While you could theoretically code this to be fast, yeah, let's be honest, codebases with hundreds if not more than a thousand coders aren't going to do this right.

Hence, we introduce, `Destroy()`.
All cleanup logic is done here. Datums should:
- Clean up anything they're using (if they are using an internal datum datastructure that no one else is using, delete it)
    - Strings, numbers, etc, don't need to be nulled or cleaned up, BYOND does that automatically
    - Lists should be nulled, along with everything else
- Null their references to other objects
- **Call `..()` and set return value to something reasonable, like `QDEL_HINT_QUEUE` by default, or `QDEL_HINT_LETMELIVE` for a "legal" way of resisting deletion, or `QDEL_HINT_IWILLGC` for "forget about me, assume I'll garbage collect without being checked for it".**
    - You usually just do `. = ..()`. If you're a beginner you have no use of the others, as screwing up while using them can be especially dangerous for server stability!

### Wiping references

BYOND operates off **reference counting.** When all references to an object are gone, it'll be automatically freed for reuse, which is very fast.
This also means that circular references are especially dangerous.

Say you have two objects.
The first one references the other in a variable.
The second one references the first.
This will **never** soft delete, until either the chain is broken, or the garbage collector (you *did* use `qdel()` right?) detects that it's been 1-2 minutes and the thing is still lingering, and hard deletes it.

## References General

All datums have a reference to their memory location. This is gotten by `\ref[datum]`, or `REF(datum)` on our codebase.
All datums can have a **tag** set. A tagged datum will never be garbage collected, as the **tag counts as a global reference.**
You can try to get a datum using `locate()` passing in either the reference, or the tag.

**As a new coder, you should generally not touch tags on our SS13 codebase.** It takes some know-how to use properly, and screwing it up can have consequences. We currently use this for mobs.
REF() is just \ref but it returns the tag if the datum is flagged to use it. Don't worry about it as a new coder, just use REF().

### Weak References
This is very important.
See, **the string memory location you get from REF() or \ref is not a hard reference, and will not stop garbage collection.**
You can use this to make what's called "weak references" for when you want to hold an object without preventing its garbage collection if it's not being used anymore.

Use `WEAKREF()` and `/datum/weak_reference` (or was it `/datum/weakref`) for this purpose. **Do not attempt to snowflake your own as a new coder or I promise you it will blow up.** There's little use for weak references anyways.

### Procs
**Datums in a running or sleeping function are hard-referenced there!**
This is why we like addtimer() instead of spawn() and similar (see [Timing/Synchronization/Threading](/HVU-IBzWRWOOQyTgrn5-jw)) as our custom things **do not hard reference and prevent garbage collection.**
