How to use exceptions

H. S. Teoh hsteoh at qfbox.info
Thu Aug 11 23:50:58 UTC 2022


On Thu, Aug 11, 2022 at 11:06:45PM +0000, Adam D Ruppe via Digitalmars-d-learn wrote:
> You might find my recent blog post interesting too:
> 
> http://dpldocs.info/this-week-in-d/Blog.Posted_2022_08_01.html#exception-template-concept
> 
> and a draft of some more concepts:
> http://arsd-official.dpldocs.info/source/arsd.exception.d.html
> 
> 
> I also find the lack of information disturbing, but I also hate
> formatting it all into strings, so I wanted to experiment with other
> options there that avoid the strings.

I think the OP's idea is somewhat different: adding contextual
information to a propagating exception that the throwing code may not
have access to.

I've often encountered this situation: for example, I have a program
that's driven by script, and contains a bunch of code that does
different computations which are ultimately called by the script parser.
There may be an error deep inside a computation, e.g., a vector was zero
where it shouldn't be, for example, and this may be nested inside some
deep expression tree walker. So it throws an exception.  But the
resulting message is unhelpful: it merely says some obscure vector is
unexpectedly zero, but not where the error occurred, because the
expression walk code doesn't know where in the script it is. And it
*shouldn't* know -- the filename/line of a script is completely
orthogonal to evaluating expressions; for all it knows, it could be
invoked from somewhere else *not* from the input script, in which case
it would be meaningless to try to associate a filename/line with the
exception.  Expression evaluation code should be decoupled from parser
code; it shouldn't need to know about things only the parser knows.

And besides, if the expression code wasn't invoked from the parser, the
exception shouldn't include filename/line information where there isn't
any. It should be the parser that tacks on this information when the
exception propagates up the call stack from the lower-level code. In
fact, the exception should acquire *different* contextual information on
its way up the call stack, depending on what triggered the upper-level
call. If the expression evaluation was invoked, say, by network code,
then the exception when it arrives at the catch block ought to carry
network source IP information, for example.  If it was invoked by
simulation code, then it should carry information about the current
state of the simulation.

In the other direction, if the expression evaluator code calls, say,
std.conv.to at some point, and .to throws a conversion error, then the
outgoing exception should carry some information about where in the
exception the problem happened. There is no way std.conv could know
about this information (and it shouldn't know anyway); the expression
code should be the one tacking this information on.  And as the
exception propagates upwards, it should gather more higher-level
contextual information, each coming from its respective level of
abstraction.

The OP's idea of wrapping throwing code with a function that tacks on
extra information is a good idea.  Perhaps the use of strings isn't
ideal, but in principle I like his idea of exceptions acquiring
higher-level information as it propagates up the call stack.


T

-- 
PNP = Plug 'N' Pray


More information about the Digitalmars-d-learn mailing list