Re: Dealing with exceptions in a drawing stack

2009-01-19 Thread Quincey Morris

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

2009-01-19 Thread Graham Cox


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

2009-01-19 Thread Paul Bruneau

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

2009-01-19 Thread Quincey Morris

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

2009-01-19 Thread I. Savant

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

2009-01-19 Thread Shawn Erickson
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

2009-01-19 Thread Paul Bruneau

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

2009-01-19 Thread Michael Ash
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

2009-01-19 Thread Graham Cox


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

2009-01-18 Thread Kyle Sluder
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

2009-01-18 Thread Graham Cox


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

2009-01-16 Thread matt . gough


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

2009-01-16 Thread kyle . sluder
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

2009-01-14 Thread Graham Cox


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

2009-01-14 Thread Kyle Sluder
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