ID:2140538
 
So static vars are vars attached to a type or path that is the same across all instances of that type/path (the official name is 'global' but that is confused with actual global vars so i'll call them static vars)

You can use static variables two ways, 1, a proc var that remains between calls of the proc, and 2, a datum var that is the same across all instances of that datum*.
*datum or object means a generic term for datums, atoms, mobs, obj, turfs, images, clients, etc any "thing" that can have new vars attached to it by the programmer, as well as child types

Proc var:
/proc/getid()
var/static/nextid = 1
. = nextid++

(Note: the part after a = only runs on the first call, afterwards nextid will keep it's value between calls, so the next call would return 2, then 3, then 4, and so on.)

Datum var:
/datum/thingy
var/id
var/static/nextid = 1
/datum/thingy/New()
id = nextid++


Merged:
/datum/thingy
var/id
/datum/thingy/New()
id = getid()
/datum/thingy/proc/getid()
var/static/nextid = 1
. = nextid++

(Note:with datum proc static vars, its also shared across all instances of that datum.)

If you are wondering why you've never heard of this var modifier, it's because it's "officially" called global, both global or static can be used interchangeably:

/proc/getid()
var/global/nextid = 1
. = nextid++


However, it is easy to get them confused with proper global vars:

var/nextid = 1
/proc/getid()
. = nextid++
//same thing as above, but should only be used if your proc also has a variable named nextid:
//. = global.nextid


The `global` var modifier and global variables have 0 relation, and this is confusing, luckily the `static` var modifier does the exact same thing, so that is what I'd advise you use.


It's important you learn to properly abuse these, as they are faster, don't slow down compile time, and are better than using globals (don't ask why globals are hated on, just know that every college course around Object Oriented Programming will say the same thing, most usage of them is a product of bad design and/or laziness. It's like goto, to be used only if all other options aren't appropriate)

Performance wise, static proc and datum vars are as fast as (and in some cases faster then) proc vars, the fastest kind of variable.

Compile wise global variables and defines both slow down compile time, because now at every variable during compile, byond has to search the big list of global variables and current defines to see if the name is in that list, a non-trivially complex operation so if you can shunt it into a var/static or var/static/const in the proc or type, you get speed without slowing down compile time. I should point out that profiling compile slowdowns is finicky at best, so this entire paragraph can be taken with a grain of salt.

And finally, when defining a variable, you should always aim to give it the smallest scope it needs. This allows you to better control the flow of information between parts of your code, and starting out with this mindset allows you to clearly see in your mind what code will access a given variable, avoids name conflicts with other parts of code, and makes debugging issues easier since you reduced the amount of lines that can even access a given variable, so no unexpected changes. Static vars are just another tool that allows you to avoid abusing globals.

Need to have 1 var shared between multiple "objects"? Rather than make it a global (or a define if it's read only), make it a static or static/const variable on the nearest parent type.

Need a proc to store info between calls that only that proc will access? Rather than make it a global var, make it a proc var.

Need to do both at once? Rather than make it a global var, make it a static proc var on a proc on that datum.

I'm sure there are other examples.
Yeah, static variables are very handy at times.

One thing I am wondering though in regards to memory handling:

proc/get_some_id()
var/static/x = 0
. = ++x


In the case of the above, is it accurate to say that the variable x, once initialized, will always remain in memory?

I suppose this wouldn't be a huge deal if used sparingly, but better these questions be asked than not.
In response to FKI
It seems that all global variables, including proc globals, are initialized at world startup. They stay in memory forever.

For globals containing objects, it's usually best to lazy-initialize them.
IIRC, the memory for global vars is allocated at world start, so changing a global from null to 1 won't make any difference in the memory footprint. They are very unlike datum vars, because they can be looked up directly.
I wish there were polymorphic versions of these typed global variables, it would make certain code I have a lot cleaner. Ooh that or enums.
Can static properties of a class be accessed without an instance of that class?

like
/obj/cube
var/static/sides = 6


and in a completely different namespace....

var/numberofsidesinacube = /obj/cube.sides

Basically is there any way to retrieve, and/or modify those vars, without having to first instantiate a new cube and then read the property off its instance?

I know i can do:

var/obj/cube/mycube = new /obj/cube
var/numberofsidesinacube = mycube.sides

but that's kind of a pain
You can access static variables without initializing the object, but you'd still need a variable pointing at the datum.
datum
my_datum
var/static/some_var = 10

mob
verb
SetValue()
var/datum/my_datum/something
something:some_var = 20

SeeValue()
var/datum/my_datum/something
usr << something:some_var // 20 if used after the above.

NewValue()
var/datum/my_datum/something = new()
usr << something.some_var // Also 20.


It saves initializing things, but doesn't save much typing. It does alter the initial value when creating new datums of that type, which is pretty helpful. You'll also get variable defined but not used warnings for all three of the above verbs.
In response to Nadrew
You can also access non-static, non-reference (objects) vars with initial() if you typecast a path stored in a var as itself (or a higher path of it that also contains the var you want.

#define BRUTE "brute"

/obj/item
var/damage_type = BRUTE

var/obj/item/I = /obj/item
world << initial(I.damage_type) //"brute"
You'll also get variable defined but not used warnings for all three of the above verbs.

This currently deters me. There doesn't seem to be a way to avoid that warning.