Also, all scheduled callbacks are sorted exclusively by time. Sometimes you want a function to only operate after another one to boot. Instead of a single scheduler. These headaches could be solved by creating a simple scheduler datum:
scheduler
var
id = "default" //the string name of the scheduler (read-only)
priority = 0 //the default priority of the scheduler. Schedulers with a lower priority run their scheduled callbacks first, and a higher priority last
tick_lag = 0 //how often this scheduler ticks. 0 = world.tick_lag
New(id,tick_lag,priority)
//creates a new scheduler with a specific string id, tick_lag, and priority
//any created scheduler is inserted in the global.schedulers associative list, sorted by priority.
//creating a scheduler with an id already stored in global.schedulers will delete the old one and replace it with this one.
Del()
//deletes the scheduler and all pending callbacks in the scheduler (the default scheduler will be replaced with a new scheduler if deleted.)
//the default scheduler is created before the world initializes, and will refuse to be deleted, instead just clearing the queue.
This would necessitate a slight change to sleep() and spawn():
sleep(duration,id="default")
spawn(duration,id="default")
Sleep and spawn would have a new argument, referencing a scheduler by id. If the scheduler is not found by id, the default scheduler is used instead.
sleeps/spawns scheduled within the current tick will not obey priority. Only sleeps/spawns scheduled for a future tick will actually obey priority fully.
For one, in a single threaded operation, sleep and spawn as language level constructs should effect that thread, not some weird pseudo-subthread. Schedulers as proposed and their management should be implemented at a library level, not language level.
I'd much rather an actual first-order timer, callback, and maybe lambda (a man can dream, can't he) function support. Something that exists in SS13 code as a second-order product and is an actual joy to use. Another idea might be to allow users to tap into sleep and spawn themselves.
Though, considering BYOND's purpose, it might not be a bad idea to have a scheduler class. I just think it should be very distinctly and clearly separated from the core language.
Also, usage of string ID is an awful idea and will lead to more buggy code. Specially with the given default. The more errors can be identified at compile time, the better. Which is why I'd propose that all methods used by the scheduler be actually attached to it. It will require a global in some instances, sure, but that trade-off is far outweighed by the code simply not compiling if you reference an invalid scheduler.