ID:2250168
 
obj/items/armor/my_armor/Equip(mob/equipper)
.....() // I feel dirty.
// Stuff


I don't think I've ever had a legitimate reason to use the parent operator twice on a single line before today.

If you're wondering that line calls the parent of the parent (which is /obj/items/Equip()) while skipping the parent (/obj/items/armor/Equip()).

.. . ..()


I rewrote it to be less awkward eventually, but I just thought everyone would like to see one awkward line of code that would confuse most people reading it.
It's not that horrible if you hide it behind defines:

#define PARENT ..
#define PARENTCALL .. //Yes, identical, just for sugar

.....() -> PARENT.PARENTCALL()
........() -> PARENT.PARENT.PARENTCALL() //etc.

I'm sure that you still don't have a legitimate reason to do this, but whatevs.
I actually had to skip some default behavior defined under the parent's Equip() that was specific to armor but retain some functionality inside of the default item equip behavior for a special type of armor that was being equipped in a unique way.

Eventually I just adapted the parent Equip() to handle that condition, but it was an interesting step to take when trying to figure out why calling ..() was giving me headaches (a forgotten usage of Equip() under the parent).

There's plenty of legitimate cases for doing this, this simply wasn't really one of them (although it was a perfectly acceptable situation) -- including the fact that it incurs less proc overhead than calling ..() and relying on the parent to ..() itself when you have nothing inside of the parent's call being used.
Wow... nice. I've needed this on multiple occasions.
You can actually use the .. and . operators endlessly, it's just not fun to read later.

.................()


Would compile, it would probably call /datum/Equip(). I'm not sure if the compiler is smart enough to realize you've hit the top-most level to throw out an error.
I was just looking for a way to do this the other day. Thank you!

For an example of where you'd want to use this:

datum
var
list/tick_children
datum/tick_parent
proc
onTick()
var/datum/d, t
for(d in tick_children)
t = tick_children[d]
if(t-world.time<tick_threshold)
d.onTick()
return 1


The default action of datum/onTick() is to call any tick childrens' onTick() command.

I created a set of pipe objects for a boss fight. When they are created, they are tick parented to the boss fight arena so that they are only ticking when the arena is active:

area
slime_boss
Entered(atom/movable/o)
if(istype(o,/obj/slime_boss))
pieces += o
o.TickSubscribe(src)
else if(istype(o,/obj/slimepipe))
o.TickSubscribe(src)
if(istype(o,/obj/slimepipe/pump))
pumps += o
else if(istype(o,/mob/enemy/slime_minion))
++slimespawns
else if(istype(o,/mob/player))
Trigger()
..()


The default slimepipe object's onTick() function sends a pulse down the line:

obj
slimepipe
icon = 'slimepipe.dmi'
dir = SOUTH

var
obj/slimepipe/next
dist = 1

refire = 1#INF

onTick()
if(world.time>=refire)
next.Pulse()
refire = 1#INF
return ..()

proc
Pulse()
if(!next&&dist)
var/turf/t
switch(dir)
if(NORTH)
t = locate(x,y+dist,z)
if(SOUTH)
t = locate(x,y-dist,z)
if(EAST)
t = locate(x+dist,y,z)
if(WEST)
t = locate(x-dist,y,z)
if(t)
next = locate(/obj/slimepipe) in t
if(!t||!next)
dist = 0


But I have a piece of slimepipe that doesn't do this instead, it creates a slime minion when it refires.

obj
slimepipe
end
dist = 0
icon_state = "end"

Pulse()
flick("[icon_state]pump",src)
refire = world.time+5

onTick()
if(world.time>=refire)
var/mob/enemy/e = new/mob/enemy/slime_minion()
e.ForceMove(get_pos(src,1,-2),SOUTH,get_pos_step_x,get_pos_step_y)
refire = 1#INF
return .....()


There are other ways to do this, but this little trick allows me to keep the hierarchy intact.
Lol noobs
I don't think what you did is 'wrong' but there are alternatives.

If you make use of helper methods to divide up your logic then this simple solution becomes available.
obj/item/proc

Equip()
Helper_A()
Helper_B()

Helper_A()
Helper_B()


obj/items/armor/my_armor

Equip()
Helper_A()
Helper_C()

proc
Helper_C()


Equivalently you could invert your logic from items equipping themselves to players and go to players equipping items.

One interesting advantage of this approach is it doesn't assume items only ever equip themselves to the same thing. Maybe that's true in build 10 but what about build 200?

mob/proc

Equip(obj/item/i)

// Armor
if(istype(i,obj/item/armor/my_armor))
HelperA()
HelperC()

else if()
// Some other items

// Default behavior
else
HelperA()
HelperB()

proc
Helper_A()
Helper_B()
Helper_C()

In response to Ter13
I'm not an expert, but from what I've read on the interwebs:
Ter13 wrote:
But I have a piece of slimepipe that doesn't do this instead, it creates a slime minion when it refires.
This sounds like an abuse of inheritance, to have a child of a type that doesn't do what the parent does. It shouldn't be a child of that parent.

For example, the parent could be split up like so:
obj
slimepipe
icon = ...

var
...

proc
Pulse()
// empty

not_end // my naming skills are on point
onTick()
...

Pulse()
...

end
dist = 0
...

onTick()
...

Pulse()
...

There are other ways to do this, but this little trick allows me to keep the hierarchy intact.
Your little trick allows you to bypass the hierarchy, which isn't really keeping it intact.
In response to Kaiochao
Kaiochao wrote:
This sounds like an abuse of inheritance, to have a child of a type that doesn't do what the parent does. It shouldn't be a child of that parent.

*nods*
In response to CrimsonVision
CrimsonVision wrote:
It's not that horrible if you hide it behind defines:

> #define PARENT ..
> #define PARENTCALL .. //Yes, identical, just for sugar
>
> .....() -> PARENT.PARENTCALL()
> ........() -> PARENT.PARENT.PARENTCALL() //etc.
>



Thought I'd mention this doesn't work. Attempted it twice now and always get a compiler error.
In response to FKI
I wrote the above without testing the idea behind the thread (.....()), I merely assumed it worked. I personally have not been able to get .....() to work, however some I know did this for a joke:

#define ^ ..
#define ~ ..()

And had: ^.~ as compiling code.

I can only assume there's something relating to the Byond version (given you can't get it to work via defines, I can't get it to work at all, the other guy gets it working as a winky face and Nadrew obviously got it to work or I doubt he'd make the thread)