Re: Dealing with exceptions in a drawing stack
On Jan 19, 2009, at 14:54, Graham Cox wrote: Well, it's not really in an unsaveable state. The data model itself isn't damaged by exceptions thrown from the drawing code. However, the visual appearance of the document is badly upset (scrollbars suddenly disappear, rulers get drawn in the middle of the view, etc). The user *thinks* something has gone terribly wrong, panics, and typically closes the document without saving. In fact saving at that point will work OK, but we're finding that users typically think it's become "corrupt" and are loth to save over an earlier version of the document because they think that what they see is what they will get - i.e. saving the document with a corrupted view will make the problem permanent. The end result is the same though - the user has "lost" their data, even though in fact they didn't need to. This is why I need to ensure that a minor glitch when drawing doesn't get blown out of all proportion. So Plan A would be to try to recover the drawing state, turn off your drawing (because presumably the same exception would occur if the window redrew), get safely back to the main event loop, and put up a Save As dialog with a message that the application needs to quit because of an internal error and asking for a place to save a copy of the document? As a user, I'd be sold on that idea, I think. IMO, the issue is (at least initially) a matter of documentation. The NSGraphicsContext class reference is ambiguous and incomplete -- it's not clear whether the current context is saved *in* each state on the state stack, or whether the state stack is *in* the current context, or whether the state *is* the context. There's apparently a setGraphicsState: method which *looks* like it might be what Graham needs to set things back to a known state, but the parameter to this method isn't documented anywhere I could find. The header file is no help at all. The comments refer to save/ restore *context* methods (as opposed to save/restore *state* methods) which apparently don't exist anywhere. If the documentation was clear, I think Graham's strategy for dealing with exceptions would also become clear. Yep, I guess this is getting at the heart of my problem (Thanks for putting it so much more succinctly than I have managed so far!). I guess I'm hoping someone familiar with NSGraphicsContext can help me understand if saving and restoring a context explictly is legal (what happens to all the saved states that were stacked up in the process?) or if not, what is an appropriate alternative. In practice it seems to work, but I need to know that I'm not storing up trouble for myself. The question is whether you're really saving and restore a context, or just states. According to my reading of the documentation, you're not actually going to switch NSGraphicsContext unless you need to do (say) buffered drawing into a NSBitmapImageRep-based context. There's no stack of contexts to reset unless (a) the state save/restore includes the current context or (b) states and contexts are really the same thing. My reading of (most parts of) the documentation suggest that the state consists of the drawing parameters of the context, but not the context itself. So it's unclear why recovering by setting the context (as you tried) has any effect at all (unless you had changed contexts yourself). Now would be a good time for someone who really knows something to jump in and enlighten us. :) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On 20 Jan 2009, at 5:24 am, I. Savant wrote: On Jan 19, 2009, at 12:57 PM, Paul Bruneau wrote: I'm confused by it, since I have been directed in the past by people who know that The Cocoa Way is to have objects know how to draw themselves--via a category if desired. Is there differing opinion on this? (apparently there is...) This is tough to generalize. There is not only differing opinion, but also plenty of room for debate. :-) In the Sketch example, there are different shapes (including "text"), each of which handles drawing somewhat differently. I suspect the decision not to put this into the canvas view is more a matter of organization than architecture. I happen to agree with the decision. There's nothing about the MVC design pattern that demands all drawing code belongs in the view. In the particular case of a drawing application where the shapes to be drawn *are* the data model, how to draw a shape could be viewed as "business logic" for the model. My design follows this approach - the objects draw themselves, because, as you say, the objects *are* the data model. Where an object "carries" additional data that isn't directly part of the drawing, it does so by referencing a separate structure which is handled through conventional controllers and other views as necessary. Since all of this is handled through DrawKit (http://apptree.net/drawkitmain.htm ), you can download it and take it apart if you like - no part of the data model of my app that is not part of the business of rendering objects is called at drawRect: time. If I gave that impression I didn't intend to! However the drawing methodology itself is fairly complex, involving as it does multiple layers, different kinds of objects within a layer, and each object having different methodologies for editing its geometry (e.g. editing the control points of a path versus changing its bounding rect, etc) and the visual appearance of each object handed off to a "style" object that is built up from lists of stroke, fill, gradient, image, text and other operations. The point is that it's very versatile and powerful. I'm also working on making the drawing storage scalable, which adds a further degree of complexity, since storing tens of thousands of objects in a simple array starts to become inefficient (to clarify - nothing is drawn that doesn't need to be drawn according to the view's update rectangles, but at some point you need to decide which objects are affected by an update. Iterating a long list and testing every object is inefficient, so I'm experimenting with BSP storage where given an update region a much smaller subset of objects can be instantly returned). It's also, for the most part, robust - and getting more so. Where different objects are involved in the rendering process, I'm introducing formal protocols in place of informal ones so that non- conformance is easier to detect. This has already realised benefits of eliminating a couple of places where the wrong objects ended up getting accidentally passed to rendering code which was then throwing exceptions - so the proper handling of try/catch is only one strategy among several for making the drawing architecture as solid as possible. Incidentally, if this seems like overkill, a glance at the larger screen shot here might help: http://mapdiva.com. This shows what I'm working on and why simple handling of stroke/fill a la Sketch just doesn't cut it! (and even this screenshot barely scratches the surface of what's possible). I would also mention that currently the drawing time is still hugely dominated by Core Graphics, so it's not like my drawing approach is causing poor performance. IMHO objects that can draw themselves should be NSCell sub-classes or NSView sub-classes (possibly using some primitive drawing rendering support from NSImage, NSString, etc.) and not some model object that has drawing code tacked onto it. These view classes should be told or be able to ask for the data they need to use at render time, ideally pre-prepared / pre-fetched as makes sense. Here I'd disagree. My drawing objects are based neither on NSView nor NSCell, they start from NSObject and gradually specialise, first with properties that are common to all "drawables" and then subclassing for more esoteric variations. NSView is too heavyweight, especially when you could end up with tens of thousands of objects, and NSCell, while lightweight, is also very much designed for use in framework tables, matrixes and controls. Objects that are part of a drawing are not really "control-like" so the NSCell model isn't really that good a fit. It also means a lot of code isn't directly available to the application developer so often behaviours have to be inferred, whereas by writing your own "drawable" object you have complete control over its code and behaviour. In my case the
Re: Dealing with exceptions in a drawing stack
On Jan 19, 2009, at 2:08 PM, Quincey Morris wrote: I don't get this at all (not just the quoted comments, but going all the way back to Graham's original statement). -- If a failure in the drawing code destroys the *data model* (thereby preventing it from being saved) then there's something terribly wrong with the drawing code's design. (Surely, being *drawing* code it only needs read-only access to the data model. Or, if it has drawing-related status to update in the data model, it shouldn't be making structural alterations to the data model whose failure could leave the model in an un-savable state.) In this case, the location of the drawing is irrelevant. Its design is dangerous to the data model no matter where it's implemented. -- If a failure in the drawing code doesn't hurt the data model, but leads to an unending cascade of exceptions from the inconsistent drawing state, then the problem is more about suppressing exceptions so that the document can be saved before the application crashes. I assumed that Graham meant that if his user is creating stuff, then during a draw the graphics get hosed to the point where the user can't save, he will lose the data that he as created in that session. When I worked in graphics, this type of problem was all too common in Illustrator 5.0 I can assure you. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Jan 19, 2009, at 10:16, Shawn Erickson wrote: On Mon, Jan 19, 2009 at 9:57 AM, Paul Bruneau wrote: On Jan 19, 2009, at 2:49 AM, Kyle Sluder wrote: 3) You've over-architected your drawing code. Typically the fewer objects that are responsible for drawing (i.e. view objects) the better. Situations like the one you're describing often arise from making model objects responsible for their own drawing. I was a little disappointed that Graham didn't address this point. I'm confused by it, since I have been directed in the past by people who know that The Cocoa Way is to have objects know how to draw themselves--via a category if desired. I think the point that was trying to made is that you should do all the heavy lifting out side of drawRect: and the only work that takes place in drawRect: is just what needs to take place to render that object. In other words process your data outside of drawRect:, create what objects are needed outside of drawRect:, deal with failures outside of drawRect:, distill what needs to be distilled outside of drawRect: and in drawRect: just draw. I don't get this at all (not just the quoted comments, but going all the way back to Graham's original statement). -- If a failure in the drawing code destroys the *data model* (thereby preventing it from being saved) then there's something terribly wrong with the drawing code's design. (Surely, being *drawing* code it only needs read-only access to the data model. Or, if it has drawing- related status to update in the data model, it shouldn't be making structural alterations to the data model whose failure could leave the model in an un-savable state.) In this case, the location of the drawing is irrelevant. Its design is dangerous to the data model no matter where it's implemented. -- If a failure in the drawing code doesn't hurt the data model, but leads to an unending cascade of exceptions from the inconsistent drawing state, then the problem is more about suppressing exceptions so that the document can be saved before the application crashes. In this case, the location of the drawing is irrelevant. The data model is safe no matter where the drawing is implemented. So why are we discussing whether model objects should draw themselves? IMO, the issue is (at least initially) a matter of documentation. The NSGraphicsContext class reference is ambiguous and incomplete -- it's not clear whether the current context is saved *in* each state on the state stack, or whether the state stack is *in* the current context, or whether the state *is* the context. There's apparently a setGraphicsState: method which *looks* like it might be what Graham needs to set things back to a known state, but the parameter to this method isn't documented anywhere I could find. The header file is no help at all. The comments refer to save/restore *context* methods (as opposed to save/restore *state* methods) which apparently don't exist anywhere. If the documentation was clear, I think Graham's strategy for dealing with exceptions would also become clear. FWIW. (Excuse the rant, please.) ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Jan 19, 2009, at 12:57 PM, Paul Bruneau wrote: I'm confused by it, since I have been directed in the past by people who know that The Cocoa Way is to have objects know how to draw themselves--via a category if desired. Is there differing opinion on this? (apparently there is...) This is tough to generalize. There is not only differing opinion, but also plenty of room for debate. :-) In the Sketch example, there are different shapes (including "text"), each of which handles drawing somewhat differently. I suspect the decision not to put this into the canvas view is more a matter of organization than architecture. I happen to agree with the decision. There's nothing about the MVC design pattern that demands all drawing code belongs in the view. In the particular case of a drawing application where the shapes to be drawn *are* the data model, how to draw a shape could be viewed as "business logic" for the model. For the organizational argument, having a single view that includes the logic to draw every kind of shape (including those added in the future) seems messy and difficult to read / maintain. Stepping aside from API architecture and design patterns, we would logically expect a shape to be responsible for knowing how to represent itself. After all, the canvas merely hosts the shapes (however they're drawn) and provides UI interaction to manipulate them. I'll remind everyone to consider my opening statement (hard to generalize) if it seems like I'm contradicting myself. :-) I am going to be starting a large app that will have many assemblies and sub-assemblies that I want to draw. I had planned on the objects drawing themselves. Should I revisit my thinking? If the assemblies and sub-assemblies are all homogenous (in that they all look more or less the same), I'd say yes, you should reconsider the Sketch-like approach. For an extremely over-simplified example, consider a view that draws many labels. The shape, color, font, etc. of the labels are all the same; merely the text is different. In that case, I'd have the view be 100% responsible for all drawing. Just my opinion, not an edict. :-) -- I.S. ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Mon, Jan 19, 2009 at 9:57 AM, Paul Bruneau wrote: > On Jan 19, 2009, at 2:49 AM, Kyle Sluder wrote: > >> 3) You've over-architected your drawing code. Typically the fewer >> objects that are responsible for drawing (i.e. view objects) the >> better. Situations like the one you're describing often arise from >> making model objects responsible for their own drawing. > > I was a little disappointed that Graham didn't address this point. > > I'm confused by it, since I have been directed in the past by people who > know that The Cocoa Way is to have objects know how to draw themselves--via > a category if desired. I think the point that was trying to made is that you should do all the heavy lifting out side of drawRect: and the only work that takes place in drawRect: is just what needs to take place to render that object. In other words process your data outside of drawRect:, create what objects are needed outside of drawRect:, deal with failures outside of drawRect:, distill what needs to be distilled outside of drawRect: and in drawRect: just draw. IMHO objects that can draw themselves should be NSCell sub-classes or NSView sub-classes (possibly using some primitive drawing rendering support from NSImage, NSString, etc.) and not some model object that has drawing code tacked onto it. These view classes should be told or be able to ask for the data they need to use at render time, ideally pre-prepared / pre-fetched as makes sense. -Shawn ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Jan 19, 2009, at 2:49 AM, Kyle Sluder wrote: 3) You've over-architected your drawing code. Typically the fewer objects that are responsible for drawing (i.e. view objects) the better. Situations like the one you're describing often arise from making model objects responsible for their own drawing. I was a little disappointed that Graham didn't address this point. I'm confused by it, since I have been directed in the past by people who know that The Cocoa Way is to have objects know how to draw themselves--via a category if desired. Is there differing opinion on this? (apparently there is...) I am going to be starting a large app that will have many assemblies and sub-assemblies that I want to draw. I had planned on the objects drawing themselves. Should I revisit my thinking? ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Mon, Jan 19, 2009 at 6:07 AM, Graham Cox wrote: > What does appear to help a lot is saving the current context at the top of > the drawing stack and putting it back explicitly at the end (as per my > previously posted code snippet). If the save/restores are balanced, > effectively this is a no-op, as I'm putting back the same context that I > saved. If an exception occurred, the save/restores are unbalanced, and this > code forces it to balance - thus, the NSScrollView is no longer badly > screwed up and things can progress almost normally. > > My question is, is this in any way legal? > > In other words, the call stack looks like this: > > > @try > { >save graphics state >save graphics state >save graphics state >save graphics state >// normally draw stuff, but may throw > an exception >restore graphics state >restore graphics state >restore graphics state >restore graphics state > } > @catch > { >// if there was an exception, the context stack is unbalanced - how > to rebalance it in a legal way before exiting? > } How about wrapping save/restore in a macro, and expanding them to use @try/@finally? For example: #define SAVE_GSTATE @try { [NSGraphicsContext saveGraphicsState]; #define RESTORE_GSTATE } @finally { [NSGraphicsContext restoreGraphicsState]; } Then use those everywhere instead of the raw calls. Mike ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On 19 Jan 2009, at 6:49 pm, Kyle Sluder wrote: Well it sounds like there are a number of issues here: 1) You're throwing exceptions in drawing code. Even if you catch them so they don't screw up the draw stack, this will be extremely slow and have adverse effects on the drawing. My understanding is that @try is pretty cheap, whereas the @catch is not. Since these exceptions are very rare, the @catch block is not being called routinely, so I'm hoping that it won't impact performance (which is currently swamped by Core Graphics rendering times anyway). 2) You've gotten yourself into a situation in which you're trying to meaningfully recover from an exception but you have to do it from a place with outside of the exception's local context. This is why Cocoa doesn't use exceptions for general circumstance; they're notoriously hard to gracefully recover from. Well, if it means I have to try/catch at every point that I save/ restore the graphics context, so be it, that's what I'll have to do. But I was hoping I could catch it at some top level and "put things right" without this approach being necessary. Cocoa exceptions are not supposed to be reached in shipped code (which I'm sure you are aware). It also sounds like the view state is a critical component of your app's model. This sounds like a Very Bad Idea(TM). On further investigation, it seems that the majority of the "bad state" is caused by the clipping path being set progressively smaller as the drawing stack goes deeper. As you can probably visualise, that isn't unusual. It means though that if an exception occurs the clipping path may be very small when drawRect: returns. On the face of it I can't see why that should matter - (the clipping path should be mine to do with much as I please with drawRect: as long as I always use addClip rather than setClip), in practice this screws up my scrollbars and rulers in the enclosing NSScrollView. That in turn must be because the scrollview is assuming that the contained view's drawRect: will balance all save/restores of the graphics state. If it's possible to recover from the exception, have you considered just fixing the situation, obliterating the graphics context, and redrawing the view? Perhaps calling -[NSView renewGState] will make your view usable again. I hadn't tried renewGState but I have now and it doesn't help. Since the gState is always renewed when the view is focused prior to drawing, that doesn't surprise me. The effects of the unbalanced context stack are felt when exiting drawRect:, not entering it. What does appear to help a lot is saving the current context at the top of the drawing stack and putting it back explicitly at the end (as per my previously posted code snippet). If the save/restores are balanced, effectively this is a no-op, as I'm putting back the same context that I saved. If an exception occurred, the save/restores are unbalanced, and this code forces it to balance - thus, the NSScrollView is no longer badly screwed up and things can progress almost normally. My question is, is this in any way legal? In other words, the call stack looks like this: @try { save graphics state save graphics state save graphics state save graphics state // normally draw stuff, but may throw an exception restore graphics state restore graphics state restore graphics state restore graphics state } @catch { // if there was an exception, the context stack is unbalanced - how to rebalance it in a legal way before exiting? } --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Mon, Jan 19, 2009 at 2:32 AM, Graham Cox wrote: > Naturally I would prefer that no exceptions can ever be thrown in this code. > But the reality of development is, that yes, sometimes they do. Very often > this is from an NSAssert message which are liberally used throughout most of > the code. They are there to catch occasional mistakes on my part, and as > such they do a good job. There are also other situations such as calling an > unimplemented method on an object where the framework will throw. All of > these situations are rare, and when they do occur it's a trigger for a > debugging session to track them down, understand them and prevent them from > happening again. The drawing stack is potentially extremely complex, with > many different objects that can do drawing in an almost infinite number of > variations. (The number of possible combinations of drawing objects + > possible paths + drawing variations is deliberately enormous - far too many > to be able to test every one individually). Well it sounds like there are a number of issues here: 1) You're throwing exceptions in drawing code. Even if you catch them so they don't screw up the draw stack, this will be extremely slow and have adverse effects on the drawing. 2) You've gotten yourself into a situation in which you're trying to meaningfully recover from an exception but you have to do it from a place with outside of the exception's local context. This is why Cocoa doesn't use exceptions for general circumstance; they're notoriously hard to gracefully recover from. 3) You've over-architected your drawing code. Typically the fewer objects that are responsible for drawing (i.e. view objects) the better. Situations like the one you're describing often arise from making model objects responsible for their own drawing. > In many cases the unimplemented method (for example) is harmless, and in > final builds the asserts will go away. But nevertheless there remains a very > small probability that such an exception could arise in shipped code - with > the best will in the world I realise that I'm not going to be able to ship > bug-free code. Right now, the worst effect of the exception is the bad state > it leaves the drawing stack in, which has a knock-on effect far worse than > the original error. This loss of the graphics state basically causes the > user to lose all their data (as it's a drawing app) whereas the original > exception probably amounted to very little and could largely have been > ignored. Cocoa exceptions are not supposed to be reached in shipped code (which I'm sure you are aware). It also sounds like the view state is a critical component of your app's model. This sounds like a Very Bad Idea(TM). > Thus I'd prefer the drawing stack to recover gracefully from exceptions so > that the user can continue using the app at the very least to the point > where they can save their data, and ideally such that there is no > detrimental effect at all. My belief is that that would be a far better app > than one that amplified the smallest bug into an enormous one that pulls the > whole thing over. An occasional drawing glitch is forgivable, but not if it > leaves the app unusable. Also, if a user does run into an occasional drawing > glitch, that's what they'll see and hopefully it'll get reported as a bug > that I'll have some chance of fixing, whereas the whole document just going > blank and "acting weirdly" isn't going to help me in the slightest track it > down, since all I'll know is that it was due to an exception somewhere down > in my drawing code, which is probably 50% of the total code. If it's possible to recover from the exception, have you considered just fixing the situation, obliterating the graphics context, and redrawing the view? Perhaps calling -[NSView renewGState] will make your view usable again. Although this is dependent on separating your model and view. --Kyle Sluder ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On 16 Jan 2009, at 8:33 pm, kyle.slu...@gmail.com wrote: What are you doing that could throw an exception? After all, exceptions are used to indicate programmer error, and are expensive to throw. Something tells me that you shouldn't be worrying about exceptions in your drawing code to begin with. Sorry for not replying earlier - been away from the computer for a few days well-earned break. Naturally I would prefer that no exceptions can ever be thrown in this code. But the reality of development is, that yes, sometimes they do. Very often this is from an NSAssert message which are liberally used throughout most of the code. They are there to catch occasional mistakes on my part, and as such they do a good job. There are also other situations such as calling an unimplemented method on an object where the framework will throw. All of these situations are rare, and when they do occur it's a trigger for a debugging session to track them down, understand them and prevent them from happening again. The drawing stack is potentially extremely complex, with many different objects that can do drawing in an almost infinite number of variations. (The number of possible combinations of drawing objects + possible paths + drawing variations is deliberately enormous - far too many to be able to test every one individually). In many cases the unimplemented method (for example) is harmless, and in final builds the asserts will go away. But nevertheless there remains a very small probability that such an exception could arise in shipped code - with the best will in the world I realise that I'm not going to be able to ship bug-free code. Right now, the worst effect of the exception is the bad state it leaves the drawing stack in, which has a knock-on effect far worse than the original error. This loss of the graphics state basically causes the user to lose all their data (as it's a drawing app) whereas the original exception probably amounted to very little and could largely have been ignored. Thus I'd prefer the drawing stack to recover gracefully from exceptions so that the user can continue using the app at the very least to the point where they can save their data, and ideally such that there is no detrimental effect at all. My belief is that that would be a far better app than one that amplified the smallest bug into an enormous one that pulls the whole thing over. An occasional drawing glitch is forgivable, but not if it leaves the app unusable. Also, if a user does run into an occasional drawing glitch, that's what they'll see and hopefully it'll get reported as a bug that I'll have some chance of fixing, whereas the whole document just going blank and "acting weirdly" isn't going to help me in the slightest track it down, since all I'll know is that it was due to an exception somewhere down in my drawing code, which is probably 50% of the total code. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On 16 Jan 2009, at 10:33, kyle.slu...@gmail.com wrote: What are you doing that could throw an exception? After all, exceptions are used to indicate programmer error, and are expensive to throw. Something tells me that you shouldn't be worrying about exceptions in your drawing code to begin with. What Graham doesn't tell us is whether it is his code or AppKit that is actually throwing the exceptions. I have seen times when Appkit itself inadvertently throws an exception that should be caught internally but isn't. This is usually due to a bug in AppKit itself. Usually these cases show up during development and have to be manually worked around by enclosing the offending call in a try/catch block. If it is his own code, then yes, throwing exceptions this way is not a good idea in Obj-C. (If he came from a C++ background I can see why he would do it though) Matt ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
What are you doing that could throw an exception? After all, exceptions are used to indicate programmer error, and are expensive to throw. Something tells me that you shouldn't be worrying about exceptions in your drawing code to begin with. --Kyle Sluder ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On 15 Jan 2009, at 3:53 pm, Kyle Sluder wrote: This is known as a "continuation". Scheme, for example, often uses them instead of exceptions. Much like a jmp_buf, It contains all of the information necessary to resume execution at the point the continuation is created. In the event of an error, an error handler is invoked with the continuation object, at which point the error handler can inspect the error condition and potentially modify the state such that execution can continue to proceed. It then executes the continuation and the program resumes where it left off. OK, interesting... This isn't the model that exceptions follow, unfortunately. By the time your @catch block has caught the exception, the stack has already been unwound and you can't get it back. That's OK for the stack in general. The problem seems to be it leaves the graphics context stack out of whack. I can obviously deal with this by @catching wherever I have used saveGraphicsState and calling restoreGraphicsState in my catch block before rethrowing, but it's really clunky. What I tried was this: // at my very top level, i.e. [NSView drawRect:] NSGraphicsContext* topContext = [[NSGraphicsContext currentContext] retain]; @try { // make all my other drawing calls, any of which might save/restore the graphics context but also could throw an exception } @catch( NSException* exc ) { // we're back at the top, just ignore the exception here } [NSGraphicsContext setCurrentContext:topContext]; [topContext release]; Which actually seems to work - the view is no longer screwed up and unusable following an exception. However, I'm not sure this is safe, as it's blowing away all the stacked graphics contexts. While that's what I want, I don't know if I'm allowed to just forget they ever existed in this way. --Graham ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: Dealing with exceptions in a drawing stack
On Wed, Jan 14, 2009 at 11:34 PM, Graham Cox wrote: > If an exception is thrown from somewhere down inside this stack, I'd prefer > it if I could continue to draw what can be drawn, rather than have to abort > the drawing altogether which usually leaves the whole view in a weird state > (at which point I'm hosed - I have to abandon that document and create a new > one, which is hardly user friendly). This is known as a "continuation". Scheme, for example, often uses them instead of exceptions. Much like a jmp_buf, It contains all of the information necessary to resume execution at the point the continuation is created. In the event of an error, an error handler is invoked with the continuation object, at which point the error handler can inspect the error condition and potentially modify the state such that execution can continue to proceed. It then executes the continuation and the program resumes where it left off. This isn't the model that exceptions follow, unfortunately. By the time your @catch block has caught the exception, the stack has already been unwound and you can't get it back. --Kyle Sluder ___ Cocoa-dev mailing list (Cocoa-dev@lists.apple.com) Please do not post admin requests or moderator comments to the list. Contact the moderators at cocoa-dev-admins(at)lists.apple.com Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com