ID:2295065
 
Applies to:DM Language
Status: Open

Issue hasn't been assigned a status value.
I apologize if this has been requested before. I searched with Google and didn't find anything, but the BYOND Forums search doesn't seem to be working for me, so I'm not quite sure.

Currently, if you want to use named args in a proc on an object that has children, any children that override that proc MUST explicitly include all the named args of the parent proc to be assured to work. If said proc is a high-level one common to override (such as New()), this can get overwhelming very quickly. And adding a named arg to a high level of such a proc requires updating every single child, all the way down the tree, even if they don't use the arg in the overridden code.
This can be avoided by providing a parameter list rather than directly using named args, but this is unintuitive and introduces extra overhead.

There are several potential solutions. The following are ranked from best to worst, in my opinion:
1. Any proc which calls ..() does not throw the bad argument runtime, and just passes the arg up the chain. The runtime would still be thrown if the first proc reached that does not call ..() doesn't have the argument.
2. Add a syntax that specifies that a proc should also accept any args its parent possesses. Essentially, add its parent's list of args to its own AFTER the part of compilation that checks if variables are defined. This would have the result of allowing automated inheritance of named args, without ruining readability by allowing use of an arg not specified in the prototype as pictured below. Obviously, args added this way should only be usable as named args.
3. Add a syntax that tells the preprocessor to directly add the parent's list of args to its own. This would work, but would allow for readability nightmares such as this:
/atom/movable/proc/jump(dist = 1)
//Do whatever

//And then off in some entirely different file:
/mob/jump(.., silent = 0) //Or whatever syntax you want
..()
if(!silent)
msg_viewers("[src] jumps [dist] meters!")

The above would be even worse if the var in question shared a name with a var on the object to which the proc belonged, but I couldn't bring myself to do that.
The point is that number 3 is a pretty awful solution, and the others would be greatly preferable.

Syntax: The first option doesn't require any special syntax, but I understand it may not be feasible due to internal differences between named and positional args, or something.
The other two could use a syntax like above, with some special token being used in the prototype, with the args. Alternatively, it could be a setting, like a verb's name. Really anything would work.
I don't really see why there would be a need for this. It's not as if it's hard to declare the same args in the child proc--every language I can think of does it that way, with obvious oddball exceptions like Perl--and also adding new args to the child proc isn't even desirable.
every other language generates a compile time exception if you forget one

byond does not, it generates a runtime exception.

this makes it super annoying
Also, updating a proc that is overridden in 5 million places gets old quickly under byond

a .., operator for child args would be the best way

making ..() compile a flag into the proc that passes named arg runtimes up the parent tree could also be beneficial.

But honestly the runtime flat out makes no sense. specifying too many args isn't a runtime, not specifying enough isn't a runtime, but with named args this is different?
Can you give me an example of that, MSO? I'm curious if there's something that'd make a reasonable last-minute improvement for 512.
basically just a way to paste in the args of the parent.

Its from the op.

/atom/movable/proc/jump(dist = 1)
//Do whatever

//And then off in some entirely different file:
/mob/jump(.., silent = 0) //Or whatever syntax you want
..()
if(!silent)
msg_viewers("[src] jumps [dist] meters!")


The idea being that it would just (at compile time) directly paste in the args from the parent at the location of the .. so that it would effectively be:

/mob/jump(dist = 1, silent = 0)
..()
if(!silent)
msg_viewers("[src] jumps [dist] meters!")


I don't know how hard it would be to implement.

it could also be used for appending rather than prepending (or somewhere in the middle) i suppose, but i can't see why one would want to. If it's easier you could only support it as the first arg.
I still don't get why anyone would want to put additional args in the child proc.
One example, on /tg/, was our movable/throw_at proc.

Certain things that were designed to be thrown by other things had extra args in their throw_at overrides that had defaults.

that's bad, you should have the same args for every single instance of the proc.
It can ruin things if you include args on the parent that aren't on the child (which is what this feature request is about), but unless you're intentionally doing something very bizarre, the opposite wouldn't happen.

On the whole, I don't very much like BYOND's strict single inheritance system, but streamlining this kind of mess is one of the few things it could potentially accomplish very well.
In response to Optimumtact
Optimumtact wrote:
that's bad, you should have the same args for every single instance of the proc.

No. You shouldn't.

If you expect the caller to only call the proc on objects it types as the base, sure.

But if you have contexts that call overridden procs on childs it knows are childs, it does not need to be restricted to the original args, as long as the original args exist.

And seriously... what about New()?

The same would apply to New because it is an override.

In that case I don't think you can pass named args to New() from new(), so i don't know that it applies to this thread, but it is a common example of childs having more (and some times completely different) args then parents
So is this a possibility, or should I go ahead and start designing around the limitation?