ID:170430
 
I have trouble understanding when you would need to use call. Am I missing something or is it useless?
FranquiBoy wrote:
I have trouble understanding when you would need to use call. Am I missing something or is it useless?

It isn't useless. If you want to dynamically call a proc or verb, then call() is the way to go. However, in general, the rule of thumb is not to use it unless you need it.
Having seen call for what seems like the first time, I notice a usr in proc there. Is that ok to do?
In response to DeathAwaitsU (#2)
DeathAwaitsU wrote:
Having seen call for what seems like the first time, I notice a usr in proc there. Is that ok to do?

Unless you're talking about a post in which you saw somebody override call(), which you probably aren't, then it, as always, depends on the context.

You see, Death, usr is basically the last player to do something. It works, however, because instead of being a global variable, it's a variable which is passed down from function to function. That's why if Player A presses mob/verb/Attack() and Player B presses it at the same time, Player A's Attack()'s usr will be Player A, while Player B's Attack()'s usr will be Player B.

Although it is very often wrong in procs, at times, if the developer knows what (s)he's doing, then it's perfectly fine. usr, as a rule, is always safe in DblClick(), Click(), and Stat() because, for example, the player who Click()ed will always be Click()'s usr.

There are other times where it's essential to use both usr and src. For example, in Topic(), the src can be manually defined by the hsrc arument, while usr will always be the hyperlink-clicking player himself!

In sum, as long as you know what you're doing, and you truly do mean usr, and not src, then it's perfectly fine to use usr in proc: usr is not intrinsically evil.
I have trouble understanding when you would need to use call. Am I missing something or is it useless?

It's for having the equivilant of function pointers like in C/C++. Generally in other languages it's used to set up call back functions for asynchronous function calls or event handlers. So if you're writing a library this type of stuff is good for setting up hooks to allow custom tailored behaviour without the user needing to edit the libraries source code.

[Edit]
Anyway here's an example of something you could do. Say the standard spawn didn't do everything you wanted it to do since occasionally you want to take back calls or otherwise monitor your call queue. Heres how you could implement your own version.

//FunctionCall serves as a wrapper class to contain the funciton reference,
//object reference(if needed), and the params to be passed in
FunctionCall
var
source
func
params[]
New(psrc, pfunc, pparams)
source = psrc
func = pfunc
params = pparams
proc
Call()
if(source)
call(source,func)(params)
else
call(func)(params)

//The event queue holds the list of events to be executed and when they
//will be executed/
EventQueue
var
PriorityQueue/events
running = 0
proc
//The function to call to add an event to the list
MySpawn(pfunction,pparams[],ptime,psource)
if(!events)
events = new()
events.Add(new /FunctionCall(psource,pparams,psource),world.time+ptime)
if(!running)
spawn()
_Loop()
_Loop()
var/FunctionCall/fc
running = 1
while(events.head)
if(world.time >= events.head.value)
fc = events.Remove(events.head)
spawn(-1)
fc.Call()
sleep(1)
running = 0


//The rest of the example is the data structure used to store the event queue.
//Although a basic list could have been used a priority queue cleans up
//the implementation of the main loop and makes it much more effecient
PriorityQueue
var
PriorityQueueNode/head

proc
Add(newitem, val)
var/PriorityQueueNode/PQN = new(newitem,val)
var/PriorityQueueNode/prev
var/PriorityQueueNode/iter

if(!head)
head = PQN
return PQN

if(head.value >= PQN.value)
PQN.nextNode = head
head = PQN
return PQN

prev = head
iter = head.nextNode
while(iter && iter.value < PQN.value)
prev = iter
iter = iter.nextNode

PQN.nextNode = iter
prev.nextNode = PQN

return PQN

Remove(item)
var/PriorityQueueNode/iter = head
var/PriorityQueueNode/prev = null
if(head.item == item)
head = head.nextNode
del iter
return item

while(iter && iter.item != item)
prev = iter
iter = iter.nextNode

if(iter)
prev.nextNode = iter.nextNode
del iter
return item
return null

Clear()
while(head)
Remove(head.item)

PriorityQueueNode
var
item
value
PriorityQueueNode/nextNode

New(datum/p_item, pvalue)
item = p_item
value = pvalue


Not exactly the most trivial example but an example of how to make use of it.
In response to Wizkidd0123 (#3)
I was talking about the example the reference uses:

mob
proc
Proc1(Arg)
usr << "Proc1([Arg])"
Proc2(Arg)
usr << "Proc2([Arg])"
verb
call_proc(Proc in list("Proc1","Proc2"))
call(src,Proc)("Hello, world!")


I was just wondering if thats correct.
Thanks everyone, now I understand it

EDIT

Wow, I just realized how useful call can be... thank you more
In response to DeathAwaitsU (#5)
DeathAwaitsU wrote:
I was just wondering if thats correct.

Your use of call() is correct, but unfortunately, your use of usr wasn't. In that situation, you should have used src.

mob
proc
Proc1(Arg)
src << "Proc1([Arg])"
Proc2(Arg)
src << "Proc2([Arg])"
verb
call_proc(Proc in list("Proc1","Proc2"))
call(src,Proc)("Hello, world!")


[edit]
I posted the DM Ref entry usr abuse at [link].

[edit*2]
Please note that although usr is technically OK in the DM Ref example, its use there is very brittle, because if Proc1() or Proc2() were to be called in the wrong place by the developer, then they would have a large chance of failing miserably. It's only OK because usr is being passed down from the verb, call_proc() into Proc1() or Proc2().