-
Notifications
You must be signed in to change notification settings - Fork 544
. = ..(), or the art to write something simple in a complicated way
. = ..()
is a common structure in the codebase. It uses an esoteric notation to do something relatively common, and simple, that we will try to explain below.
If you just want to know what the heck this means, and you are comfortable with (very) elementary object-oriented programming notions and ideas, just skip to the end (To remember).
.
is a built-in variable which exists in all byond procs. It is the default value being returned, and its initial value is null
.
Unrigorously, you can view it as something being "added" to your procs when you hit compile. For instance :
/proc/thing()
. = TRUE
world.log << "Welcome byond!"
Gets compiled as :
/proc/thing()
var/. = null
. = TRUE
world.log << "Welcome byond!"
return .
It should be noted that return
, return .
or nothing at all at the end of a proc are strictly equivalent and will yield the same result.
..()
is, in a proc, the way to call the parent's version of this proc.
Even for a proc that wasn't defined previously, ..()
is valid syntactically (it'll just do nothing at all).
Example :
/datum/proc/thing()
world.log << "Welcome byond!"
/datum/child/thing()
world.log << "I'm the child datum!"
..() // Will display, "Welcome byond!"
..()
implicitly passes any arguments the "main" proc being called had. Essentially,
/datum/child/thing(var/arg1, var/arg2)
// Something
..(arg1, arg2)
and
/datum/child/thing(var/arg1, var/arg2)
// Something
..()
Are equivalent. It is preferred not to pass the arguments unless you want to change them.
BYOND WARNINGS
Below are two very common errors/bugs due to byond strange syntax and structures. Try not to do them.
- Overriding a proc that already exists
Byond allows you to override a proc in the same "type", not just for the children types. You can also override said proc in any file. The proc the further down in the file tree is the one that actually gets compiled.
Essentially :
/datum/proc/getTotalHealth()
return health
// Further away in the codebase...
/datum/getTotalHealth()
return (..() + extra_health)
Is completely valid syntax, and the later proc will be the one that gets compiled.
You should avoid this coding practice, as it can makes things harder to debug and understand what's going on in the code.
In such the above example, ..()
is simply /datum/proc/getTotalHealth()
- Named arguments
This situation is better explained with a concrete example. Let's assume we have a proc defined for a religion, with some subtypes :
/datum/religion/convert(var/mob/living/preacher, var/mob/living/subject)
/datum/religion/retard/convert(var/mob/living/preacher, var/mob/living/subject)
Then, we code a functionality on the main proc, adding a new arg, but we forget to update the child, which makes it look like this :
/datum/religion/convert(var/mob/living/preacher, var/mob/living/subject, var/can_renounce = TRUE)
// Do something
/datum/religion/retard/convert(var/mob/living/preacher, var/mob/living/subject)
. = ..()
if (subject)
subject.adjustBrainLoss(100) // Welcome to the club
Then, we'll try to code something calling convert
like this :
convert(mob_1, mob_2, can_renounce = TRUE)
This will compile correctly, however, because in /datum/religion/retard/convert
we omitted the can_renounce
variable, this will runtime and BYOND will not understand what is happening (and will produce a rather unhelpful error message).
You must remember that if you try to use named arguments (like can_renounce
here), you have to define those in all children of the procs. However, if you do not use named arguments, extra args are kept.
Now that we saw what .
and ..()
, we have to combine both.
.
is the default value being returned.
..()
calls the parent.
. = ..()
calls the parent, store the value returned, and at the end of the proc, this value will be what's returned.
A rarer, but no less esoteric, byond construct is .....
(yes, 5 (five) dots). It returns the "type" of the proc being called, which can then be passed around (for instance, to call it manually).
For instance :
/datum/x/y/proc/test()
world.log << "[.....]" // /datum/x/y/proc/test
/datum/x/y/z/test()
world.log << "[.....]" // /datum/x/y/z/test