Here's a quick example:
mob/verb
create_exception()
throw new /exception ("error", osrc = src)
world/Error(exception/E)
world << "___Exception caught: \ref[E]"
for(var/x in E.vars)
world << "[x]: [E.vars[x]]"
//using osrc to show that nothing is copied from the original exception
exception
var
osrc
New(name, file, line, osrc)
. = ..()
src.osrc = osrc
world << "___Exception created: \ref[src]"
for(var/x in vars)
world << "[x]: [vars[x]]"
example output:
___Exception created: [0x21000000]
name: error
desc:
file: Super Saiyan X
line:
osrc:
tag:
type: /exception
parent_type: /datum
vars: /list
___Exception caught: [0x21000001]
name: Exception thrown: error (/exception)
desc: proc name: create exception (/mob/verb/create_exception)
source file: exception_test.dm,5
usr: (src)
src: Super Saiyan X (/mob)
src.loc: null
call stack:
Super Saiyan X (/mob): create exception()
file: exception_test.dm
line: 5
osrc:
tag:
type: /exception
parent_type: /datum
vars: /list
It'd make more sense if the exception world/Error() receives is the same as the one thrown, rather than the runtime generated by an un-caught throw. It'd be cool if it could fill in the same missing info (file, line, desc) if not provided in the exception creation. This lets us provide extra information for logging purposes, which would otherwise be lost in world/Error(). Through, when a non-exception object is thrown, it should still probably keep the current behavior.
Otherwise, the behavior of the throw instruction is exactly the same as that of CRASH(), except for the name of exception object being passed to the new runtime.