iPhone vs Android

H. S. Teoh via Digitalmars-d digitalmars-d at puremagic.com
Wed Sep 14 07:43:29 PDT 2016


On Wed, Sep 14, 2016 at 05:19:45AM -0700, Jonathan M Davis via Digitalmars-d wrote:
> On Tuesday, September 13, 2016 16:13:05 H. S. Teoh via Digitalmars-d wrote:
> > On Tue, Sep 13, 2016 at 03:19:54PM -0700, Jonathan M Davis via Digitalmars-d
> > wrote: [...]
> >
> > > But none of the code that's marked @nogc can throw an exception
> > > unless you're either dealing with pre-allocated exceptions (in
> > > which case, they're less informative),
> >
> > I don't see why pre-allocated exceptions would be less informative.
> > You can always modify the exception object before throwing it, after
> > all.  In fact, I've always wondered about the feasibility of a @nogc
> > exception handling system where the exception is emplaced onto a
> > fixed static buffer, so that no allocation (except at the start of
> > the program) is actually necessary. Of course, chained exceptions
> > throw(!) a monkey wrench into the works, but assuming we forego
> > chained exceptions, wouldn't this work around the problem of being
> > unable to allocate exceptions in @nogc code? (Albeit with its own
> > limitations, obviously.  But it would be better than being unable to
> > use exceptions at all in @nogc code.)
> 
> As Walter points out, it's a problem if exceptions are ever saved
> (which some code does need to do). The fact that you lose chaining as
> you pointed out is also a problem.

Honestly, I've never actually run across a real-life case where chained
exceptions matter. Most of the code (that I work with, anyway) involve
simply throwing an exception when some problem occurs, and the catch
block simply prints the error message and aborts the current operation.
I agree that chained exceptions are theoretically cool and everything,
but I haven't actually found myself needing them.


> You also have problems because the file, line, and message of the
> exception either aren't going to be specific to when that exception is
> thrown, or you have to set them all before throwing, in which case you
> have issues with if/when the exception is reused.

Clearly, if a static buffer is to be used for emplacing the exception,
you'll have to sacrifice some things.  But I'm just saying that the
limitations aren't as onerous as it may seem at first, and in fact
covers a lot of common use cases.


> And regardless of all of that, the fact that string is used for the
> message throws a wrench in things for @nogc, since that's going to
> require GC allocation unless you cast something to string, and then
> you have serious problems if you need to mutate it later, since you'll
> end up violating the compiler guarantees for immutable.

Most uses of exceptions in code that I've seen involve setting a static
string as the message. This does not require GC allocation.

Granted, it's also relatively common to make the exception message more
verbose / informative, e.g. using format() to embed specific details
about the problem besides the static message string. My own code uses
this idiom quite often. This would have to be sacrificed, or some other
workaround found, of course.


[...]
> > There's nothing about the 'throw' keyword that requires GC
> > allocation.  It's just that `throw new Exception(...)` has become a
> > standard incantation. The exception object itself can, for example,
> > be emplaced onto a static buffer as I propose above.
> 
> Yes, there are ways to work around allocating an exception with new
> right before throwing it, but that's really how things are designed to
> work, and there are serious problems with any attempt to work around
> it.  At minimum, it makes throwing exceptions to be a lot more of a
> pain then it is when using the GC [...]

I disagree. There is nothing about 'throw' that requires the use of
'new'.  A further development of the emplacement idea is to
pre-initialize a region allocator specifically for throwing exceptions,
then you can write:

	throw makeException("Error occurred", ...);

where makeException is a global function that allocates the exception
using the region allocator (which is initialized at startup). The catch
block then deallocates the region and re-initializes it.  This is not
that much more painful than writing:

	throw new Exception("Error occurred", ...);

This is just a quick-n-dirty example, of course. In an actual
implementation you'd templatize makeException() so that you can create
different exception types, e.g.:

	throw make!UserDefinedException("...", ...);

Filename, line numbers, etc., can be easily accomodated the same way
they're currently handled in exception ctors.


> But the fact that the workarounds either require that you don't have
> unique, independent exceptions or that you know that you need to
> manually free the exception after catching it is a serious problem.
> And that's without even taking the exception chaining into account.
[...]

Using a preinitialized region allocator, we no longer have such
limitations.


T

-- 
GEEK = Gatherer of Extremely Enlightening Knowledge


More information about the Digitalmars-d mailing list