ID:2796083
 
Resolved
A new __IMPLIED_TYPE__ pseudomacro has been added. This can be used in situations similar to those the new() and locate() procs use.
Applies to:DM Language
Status: Resolved (515.1607)

This issue has been resolved.
Let's say I want to create a new /mob/moth, and typecast it at the same time. While I could do...

var/mob/moth/player = new /mob/moth


...this creates a lot of visual noise, and carries the potential of putting the wrong type on either end, causing bugs. Instead, I can do:

var/mob/moth/player = new


...which, while harder to grep, causes a lot less bugs. This is a case of DM using the inferred type of /mob/moth.

On tgstation, we have a proc that essentially wraps new called "allocate". The point is so we can guarantee it gets cleaned up at a certain point. However, we are required to write the whole thing out like this:

var/mob/moth/player = allocate(/mob/moth)


...which creates the same noise as new. It would be nice to be able to receive the inferred type.

The implementation of this should be able to easily support cases where parameters are put in afterwards, as well. For instance:

var/no_type = allocate(/mob/moth, location)
var/mob/moth/player = allocate(location)


...should be trivial to implement.
I don't really like giving implementation suggestions for feature requests, but this might help to give an idea for what I mean by the "implementation of extra parameters" should be trivial part.

I do not want to have to check to make sure the first parameter is a path. That would hurt!

Here is a rough, contrived idea just to give an idea of how a DM coder could create this interface trivially:

              // v Some special syntax/marker to say "this is the inferred type"
/proc/create_mob(@bikeshed_type, name) // You can then use this as a variable to refer to the type.
var/mob/M = new(bikeshed_type)
M.name = name
return M

// When you have no inferred type, you have to provide the type as normal
var/no_infer = create_mob(/mob/moth, "Mothblocks")

// When you provide a type, it is treated like an argument
var/mob/inferred = create_mob("Mothblocks")
Also, since someone has asked, yes this can be a macro, but I don't want a macro.

This:

var/mob/moth = allocate("Mothblocks")


...is extremely clear on what it does, while this:

ALLOCATE(/mob, moth, "Mothblocks")


...is clunky, and is much harder to understand what is going on. DM code should just read like DM code.
There is also only one reason that this:

var/mob/moth = allocate("Mothblocks")


would not be identical in compilation to this:

var/mob/moth = allocate(/mob, "Mothblocks")


...and that is to support something like this:

var/mob/moth = call(.proc/allocate)("Mothblocks")


...but I think in the interest of performance and flexibility, doing this roundabout call just shouldn't pass any inferred type.
A much easier suggestion to implement would be a keyword that evaluates to the implied type at compile time, which you could use in a macro expansion. That removes a lot of gray areas around positional arguments which are raised whenever you have an optional first argument to a function.

So if the keyword was imp_type,
/proc/actual_allocate(type) {...uses variable arguments...}
#define allocate(args...) actual_allocate(imp_type, args)
var/mob/long/reader/unfriendly/path/sorry = allocate()
I'd be very open to having a keyword for the implied type, although I don't like "imp_type" as that keyword.

Also I think there needs to be a keyword for the current compile-time type path (whether it's in a proc or when defining vars), and one for the current proc reference.
Lummox JR resolved issue with message:
A new __IMPLIED_TYPE__ pseudomacro has been added. This can be used in situations similar to those the new() and locate() procs use.