DIP33: A standard exception hierarchy

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Apr 2 10:41:04 PDT 2013


On Tue, Apr 02, 2013 at 01:29:00PM -0400, Jonathan M Davis wrote:
> On Tuesday, April 02, 2013 17:56:07 Lars T. Kyllingstad wrote:
> > On Monday, 1 April 2013 at 22:26:39 UTC, Jonathan M Davis wrote:
> > > In general, I'd strongly suggest having subclasses for the various
> > > "Kind"s in addition to the kind field. That way, you have the
> > > specific exception types if you want to have separate catch blocks
> > > for different error types, and you have the kind field if you just
> > > want to catch the base exception.
> > 
> > Then you'd have two points of maintenance when you wish to add or
> > remove an error category.
> 
> True, but it's also trivial to do. But if we had to decide between
> basically putting error codes on exceptions and using sub-classes, I'd
> vote for subclasses in most cases - though errno would need to go the
> error code in the exception route, since it has different meanings in
> different contexts and would risk an absolute explosion of exception
> types anyway; though it should probably be translated to a more
> meaningful exception based on context with the errno exception being
> chained to it - which is what you suggest in the DIP IIRC. In general
> though, I'd favor subclasses, and I don't think that it's all that big
> a deal to give them each specific error codes when you want the base
> class to have an error code like you're suggesting.
[...]

IMO, errno should be stored as-is in a dedicated ErrnoException. Any
interpretation of errno thereof should wrap this ErrnoException inside
another hierarchy-appropriate exception. For example:

	void lowLevelIORoutine(...) {
		if (osRead(...) < 0) {
			throw ErrnoException(errno);
		}
		...
	}

	void libraryRoutine(...) {
		try {
			lowLevelIORoutine(...);
		} catch(ErrnoException e) {
			if (e.errno == ENOENT) {
				// Chain ErrnoException to FileNotFoundException
				throw new FileNotFoundException(e.msg, e);
			} else if (e.errno == ENOSPC) {
				// Chain ErrnoException to DiskFullException
				throw new DiskFullException(e.msg, e);
			} else {
				// etc.
				...
			}
		}
	}

This way, user code can catch IOException rather than ErrnoException,
but errno is still accessible via .next should the user code want to
deal directly with errno:

	void userCode() {
		try {
			auto f = File("/some/path/to/file");
		} catch(IOException e) {
			if ((auto f = cast(ErrnoException) e.next) !is null)
			{
				handleErrno(f.errno);
			}
			...
		}

I think this would be a good use of the current .next field in
Exception.


T

-- 
A mathematician is a device for turning coffee into theorems. -- P. Erdos


More information about the Digitalmars-d mailing list