[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] OT: exception handling





On Thu, Apr 5, 2012 at 7:33 PM, Glenn Maynard <glenn@zewt.org> wrote:
(To anyone that wants to save time, this is a tangent that isn't going to lead to changes to WebGL, because it would break too much user code.  If you don't care about this, feel free to ignore it.  I don't mind discussing it--it's still an important topic--but I've changed the subject to avoid derailing the on-topic thread.)

On Thu, Apr 5, 2012 at 7:55 PM, Gregg Tavares (勤) <gman@google.com> wrote:
I'm still not sure what you are suggesting. That calling any function during context lost throws an exception? that sounds far more surprising to me than returning NULL.

I think it's not surprising to anyone unless the only language they're experienced with is C.

We've all dealt with C code which carefully checks for errors from each function call, and we learned how easy that is to get wrong.  The industry learned from that, and languages moved to the exception model, precisely to avoid those problems.  That's why it's so strange to me that WebGL seemed to jump back a decade or two to using the C style of error handling.  We have better error handling models now.

This is not about C vs languages with exceptions. This is about OpenGL/WebGL, a rendering API.
 

The whole point of returning and accepting NULL is that with a few simple rules you have do nothing special during context lost. All the code will just keep running but doing nothing. If every create threw an exception now you'd have to have all kinds of special cases to handle every place you call createXXX. I don't see how that's a win.

You have to do a lot careful, special, manual error handling.  That's not a "simple rule", it's an error-prone mess.

No you don't have to be careful or do lots of special handling. It's very simple. 

For 99% of WebGL programs you have to do 3 things

1) Don't attach stuff to WebGLObjects
2) When compiling/linking if you get failure, ignore that failure if the context is lost
3) If calling getActiveAttrib or getActiveUniform check for null

That's it. Follow those rules and you're done. 

99% of WebGL programs have no reason to call any other get function. If you do not attaching things to WebGLObjects then you don't care if createXXX returns null. the API is designed so that everything is a no-op on lost context.
 

You don't need special cases, and you don't put exception handlers right around the functions; you put them around the larger, higher-level functions causing it to be called.  This is how exceptions are used.

But I have to deal with the exception. Where as it is now I have to deal with nothing. The logic of my code doesn't change. If I have an exception then I get into situations where for example I expected A,B,C,D,E,F to get called in order. I get an exception at C and now D, E, F are left undone. All kinds of side effects can occur. Maybe A, and B pushed work do be done into some queues that D, E and F were expected to process.. Maybe A and B created some temporary collision objects and D, E and F were expected to release. With exceptions all of those come into play. With WebGL's design none of those come into play. All your code will function, WebGL calls will just be no-ops. If you get lost context at C then C,D,E,and F still execute. Since for 99% of WebGL programs all they are doing is pushing data to WebGL, they have no need to query and no need to get anything then it's no different than if the user turned his monitor off or minimized the window. Things don't render but all the code still executes.


 

On Thu, Apr 5, 2012 at 8:00 PM, Ben Vanik <benvanik@google.com> wrote:
> There are no performance issues with using exceptions for synchronous errors like these.
Not true - try/catch deoptimizes every JIT - a simple if (!result) {} is significantly faster and results in smaller _javascript_ code size (as the variable can be renamed - 'try' and 'catch' cannot be).

You're thinking of when try/catch is in a function, but exceptions are normally caught in higher-level functions, further up the stack.  (The entire point of exceptions is that you don't need to handle each error individually at a low level.)  Exception catching up the call stack has no effect on performance in functions below it.

To see the difference, compare:

https://zewt.org/~glenn/exceptions-0.html - no exceptions
https://zewt.org/~glenn/exceptions-1.html - typical, high-level exception handling
https://zewt.org/~glenn/exceptions-2.html - low-level exception handling

#1, the usual pattern, runs at exactly the same speed as #0 (in Chrome 18).  #2 is the case you're thinking of.

Exception handling should be reserved for exceptional situations.

The context being lost--especially asynchronously--is as exceptional a situation as there is.

(Also, as an aside, that's a bit of obsolete common wisdom that came into being under C++, where throwing an exception was very expensive.  It took me a while, when I went from C++ to languages like JS and Python, to shake it off.  It's simply no longer relevant with modern scripting languages; it's common practice in high-level languages to use exceptions for all errors.  For example, all synchronous web APIs throw all errors: XHR, File API, IndexedDB, and so on.)

From someone who has worked with large amounts of shipping, high-quality code written against the current WebGL behavior: the current model works well. Let's not change something that is not broken and actually has many advantages vs. the alternatives.

No, the current model works poorly.  It's very hard to write code that consistently handles null returns due to asynchronous context loss

As pointed out above, it is exceedingly easy to write this code because you can ignore NULL.
 
, and it's even harder (almost impossible) to write tests that verify that those null checks are comprehensive and actually work.  As Gregg points out, bugs due to this model can be found all over the place.

However, as I've said, it's almost certainly too late to fix this, so this is all pretty much moot.

(A thought, though: users could patch their contexts, or WebGLRenderingContext.prototype if they're feeling more invasive, wrapping each function to check for null and throw an exception.  That's a little tricky, since you need to call getError to tell whether a null response is a context lost or a legitimate null response; you'd need some tricks to deal with that without breaking getError.  I think it could be done, though; maybe I'll give it a shot.)

If you want this it's easy. There's already a wrapper here (http://www.khronos.org/webgl/wiki/Debugging) and you don't need to call getError. You can just call gl.isContextLost. Though if you want to call getError there's an example of wrapping it in that code.



 


--
Glenn Maynard