Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Max Facetime
Apr 18, 2009

tef posted:

*make it a warning in the ide, no-one ever ignores those*

you know who else ignored warnings?

that's right, hitler


tef posted:

if you're writing throws you're really saying 'i return a value or this error'. make it a return type you idiot.

how is 'I can return a value or I can return this error and i'm going to make you guess' an improvement?

Adbot
ADBOT LOVES YOU

Shaggar
Apr 26, 2006

Progressive JPEG posted:

fwiw in reenux land, an unlinked file isn't really gone until its last fd is closed. If you successfully opened it and are holding it open, its still there.

dunno what windows does for this though, I've gotten to where I just assume they just go with whatever behavior is most :newfap: where file access is concerned

windows has different locks and you cant write a file with read locks or modify locks.

im thinking more like "whoops someone unplugged the fiber from the san". the os can probably handle brief outages just fine with its internal write cache but at some point your state is invalid and you cant proceed.

JawnV6
Jul 4, 2004

So hot ...

Cocoa Crispies posted:

xml suppositories

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

MononcQc posted:

A return value you don't match on, depending on the type system and runtime system, will not compile (equivalent to your checked exceptions), or generate an exception (where it is truly exceptional).

so the idea is that instead of having two separate return code paths (return and throw) each of which is only designated to do one thing, you have one return code path that can do all sorts of stuff that j-language people can't even comprehend because their brains have been stunted by java and knockoffs

MononcQc
May 29, 2007

I have a strong belief in the propensity of programmers, even very competent ones, to introduce bugs in their own code, and to do even more so when it's code handling errors that should never happen.

"Oh look, problem X happened. Let's take immediate action silently to cover it up"

then 5 weeks later "data is weird, and behavior of app X changed when I do this"

"Oh, seems like my problem fix changed some invariant that was originally assumed and just made a very obvious problem into a very silent one. Sorry, we lost a few weeks of correct data and we now need to fix the data and correct the program, again!"

There just are times when poo poo should fail as loudly as possible. Encouraging devs to handle poo poo they haven't properly thought of seems to be a great way to foster that behavior. If you want to retry poo poo, you need to do it from a stable state, that you know is correct. If you do it improperly, you risk adding more instability in the state and generally making things worse later in the future.

This often happens when you handle an exception that's a symptom of a more serious underlying error, and you keep treating it superficially, applying band-aids until you can't take it anymore.

There's this kind of truth that everyone knows, that there are diminishing returns on making software bug-free. At some point it's no longer worth fixing everything ever because you just won't. Yet, there's this huge effort at making sure everything is handled, and doing things without any safety net.

There's this assumption that an error happening at run-time should mean the end of the world for the stack. Usually because once bad stuff starts happening, we have no idea how to get back to a healthy state. We assume all failures to be catastrophic and impossible to handle, or trivial and manageable (and managed). There's no idea of trivial poo poo not being handled because it wasn't economically viable, even though the real world has this happen constantly.

The whole thing smells like someone saying "let's use hygiene to make sure humans never get sick". There's little effort being put in giving your software the equivalent of an immune system, just washing your hands and disinfecting everything a lot. We aim to prevent errors, not deal with them when they inevitably happen.

Things like distributed systems going for availability are the closest thing to it, I think, because they don't see failure as this "once in a hundred years" thing, but as a very frequent reality that will happen all the time, even within a happy, healthy system.

E: typo

MononcQc fucked around with this message at 19:02 on Feb 5, 2013

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

MononcQc posted:

Things like distributed systems going for availability are the closest thing to it, I think, because they don't see failure as this "once in a hundred years" thing, but as a very frequent reality that will happen all the time, even within a happy, healthy system.

i'm supposedly going to be a riak_core expert at erlang dc this saturday, and i haven't really ever touched riak_core lol;

MononcQc
May 29, 2007

Cocoa Crispies posted:

so the idea is that instead of having two separate return code paths (return and throw) each of which is only designated to do one thing, you have one return code path that can do all sorts of stuff that j-language people can't even comprehend because their brains have been stunted by java and knockoffs

There's more than one kind of exception.

You have exceptions nobody is expected to handle. The kind of "I am in twilight zone" poo poo.
You have exceptions for exceptional cases you can expect. Going out of memory or file descriptors, for example.
You have exceptions for frequent cases you expect the programmer to deal with.
You have exceptions for programmer errors where they obviously did something bad that the compiler won't catch (invalid regex pattern, for example)
You have exceptions people piggy-back ride into non-local returns and should always be caught, without anything special to do with them except return

You have return values that are valid and represent things that went fine
You have return values that represent weird cases or overloaded meanings (NULL when searching for poo poo)
You have return values that represent compound data types (returning 2-3 items) for performance's sake that need to be re-dispatched.

And yet we're happy to conflate all of them right now, in these two slots.

I truly do not see how adding more semantics to the kind of poo poo people return or throw is a big deal or a bad thing. It should be helpful, in the end, because we all do it already and it just makes programmer intent clearer.

tef
May 30, 2004

-> some l-system crap ->

MononcQc posted:

Things like distributed systems going for availability are the closest thing to it, I think, because they don't see failure as this "once in a hundred years" thing, but as a very frequent reality that will happen all the time, even within a happy, healthy system.


pretty much distributed programming changes the way you look at errors - from something to eliminate to something to handle.

things fail all the time and for no good reason.

tef
May 30, 2004

-> some l-system crap ->

MononcQc posted:

There's more than one kind of exception.

You have exceptions nobody is expected to handle. The kind of "I am in twilight zone" poo poo.
You have exceptions for exceptional cases you can expect. Going out of memory or file descriptors, for example.

mostly your options here are 'stop what you are doing, wait a bit, and start again'. i.e the exceptions you don't want to really catch anywhere but the top layer.

quote:

You have exceptions for frequent cases you expect the programmer to deal with.
You have exceptions for programmer errors where they obviously did something bad that the compiler won't catch (invalid regex pattern, for example)
You have exceptions people piggy-back ride into non-local returns and should always be caught, without anything special to do with them except return

You have return values that are valid and represent things that went fine
You have return values that represent weird cases or overloaded meanings (NULL when searching for poo poo)
You have return values that represent compound data types (returning 2-3 items) for performance's sake that need to be re-dispatched.

And yet we're happy to conflate all of them right now, in these two slots.

these are the 'actually it would be nicer if you had to handle these cases explicitly, either by matching or by returning the value'

quote:

I truly do not see how adding more semantics to the kind of poo poo people return or throw is a big deal or a bad thing. It should be helpful, in the end, because we all do it already and it just makes programmer intent clearer.

basically we have two ways to return data, a local and a non-local return. people seem to think one is for values and one is for errors. i do not think non-local returns are a good feature in code. i am sick of continuation weenies.

tef
May 30, 2004

-> some l-system crap ->
also https://stripe.com/blog/announcing-mosql

wat

Jonny 290
May 5, 2005



[ASK] me about OS/2 Warp
an elephant......with a MUSTACHE?

these guys really think out of the box!

Subscribed.

Blotto Skorzany
Nov 7, 2008

He's a PSoC, loose and runnin'
came the whisper from each lip
And he's here to do some business with
the bad ADC on his chip
bad ADC on his chiiiiip

[img-m_bison_yes]

MononcQc
May 29, 2007

tef posted:

mostly your options here are 'stop what you are doing, wait a bit, and start again'. i.e the exceptions you don't want to really catch anywhere but the top layer.

Depends. You can fail now, try later, give up entirely, retry a different target (what if you have multiple places to store data or whatever), choose to do it silently and wait, or do it loudly and tell the user, etc.

There's a shitload of options, and usually, the way you react in face of uncertainty entirely depends on the problem domain you're in. A web server running out of memory due to overload and a hard real time system doing the same due to other event overloads will need to react differently.


tef posted:

these are the 'actually it would be nicer if you had to handle these cases explicitly, either by matching or by returning the value'

Most of the time, yes. Sometimes, no. I mean matching is always nice, whether you match on return values or exceptions.

What I mean is that log messages tend to have from 3 to N levels of severity (debug, info, warning, error, crash, critical, whatever). Exceptions tend to have 1, and return values, 1 or 2 (ok | error).

I don't particularly care if a model uses return values only, exceptions + return values, option types in return values, or mixed modes where you have both the monadic approach and exceptions. I care about semantics given to users of libraries.

Say I have a file I'm trying to do lookups in. Should passing in an invalid reference prompt the same error level as looking up a key that is not there? Should it be similar to a file not being found? Running out of file descriptors?

There are different error levels and different error sources and it's a bit ridiculous we always conflate them in the same bins. The higher level you are, the worse it becomes.

HTTP error codes could be seen as a somewhat decent approach in there -- a well-defined way to report who is responsible for the error, and in what case, and the client can choose how to handle each category of error, if at all. 100, 200, 300, 400, 500 all have different semantic meanings, and can all be sent as totally legit return values.

That you use returns, exceptions, or both does not make any of these values a language concern though. It's always defined at the convention level in a code base. It shouldn't.

tef posted:

basically we have two ways to return data, a local and a non-local return. people seem to think one is for values and one is for errors. i do not think non-local returns are a good feature in code. i am sick of continuation weenies.

They can be nice when escaping deep recursion. Any tree traversal that goes for the full tree depth can be made much, much nicer by using a top-level try / catch and throwing when the result is found. It can also become much faster when your tree has significant depth before finding a value.

Another example could be to use them as events in a nested FSM, where you implement nested states as a regular FSM, and use exceptions / continuations as a way to exit that nested one.

tef
May 30, 2004

-> some l-system crap ->
explicit tail recursion.

tef
May 30, 2004

-> some l-system crap ->
i hate continuations.

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy
re option types/discriminated unions: they kinda blew my mind when i tried learning f#

Shaggar posted:

artisanal exception handling

mods

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

MononcQc posted:

Say I have a file I'm trying to do lookups in. Should passing in an invalid reference prompt the same error level as looking up a key that is not there? Should it be similar to a file not being found? Running out of file descriptors?

What are you as the immediate caller going to do if this fails in any way? Call OS.GetMeMoreFileDescriptors? Probably not. You're going to die (or throw in the key not found sense if the key is an immutable ID type thing or return None() if the lookup is really a TryLookup type thing).

It would certainly be nice for your logger at the root level to inspect the exception itself to determine what error severity to log at though.

There are huge classes of errors that you really can't and shouldn't do anything about. Just die, log it, and move on.

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

i barely GNU her! posted:

re option types/discriminated unions: they kinda blew my mind when i tried learning f#

Algebraic data types / pattern matching are the main thing I miss when coding C#. Tuples for return types (especially without pattern matching) are really awkward and no one wants to create a new class for every stupid method result.

Shaggar
Apr 26, 2006

havelock posted:

What are you as the immediate caller going to do if this fails in any way? Call OS.GetMeMoreFileDescriptors? Probably not. You're going to die (or throw in the key not found sense if the key is an immutable ID type thing or return None() if the lookup is really a TryLookup type thing).

It would certainly be nice for your logger at the root level to inspect the exception itself to determine what error severity to log at though.

There are huge classes of errors that you really can't and shouldn't do anything about. Just die, log it, and move on.

the immediate caller should throw. then an intermediary will wrap the library specific failure in a framework specific one and throw that. then the system exception handler will decide to abort,retry,failure. it might decide oh hey if this storage mechanism fails requeue it for another attempt. or maybe try to send it out this backup mechanism.

in this case we're talking about a larger system where the higher level parts of the system don't want to have to understand anything other than their own exception types. you abstract the low level exceptions from them so your code is re-usable. this way when you add a module that uses BonerLib the system doesn't need to know about the new BonerOverflowException. that work is handled by your interface implementation between the high level system and BonerLib

this is really independent of exceptions vs return types or w/e.

Jonny 290
May 5, 2005



[ASK] me about OS/2 Warp
my eclipse has vim keys now. sweet

Sniep
Mar 28, 2004

All I needed was that fatty blunt...



King of Breakfast

Jonny 290 posted:

my eclipse has vim keys now. sweet

sorry that you have to use eclipse but grats on making it one step better at least

Jonny 290
May 5, 2005



[ASK] me about OS/2 Warp

Sniep posted:

sorry that you have to use eclipse but grats on making it one step better at least

i dont have to but i cant really beat on them to buy me IDEA until i'm actually working on java projects

i have no problems with eclipse in my current role, it meets my needs and does not actively piss me off
i even do yosvape code on it at home

MononcQc
May 29, 2007

havelock posted:

What are you as the immediate caller going to do if this fails in any way? Call OS.GetMeMoreFileDescriptors? Probably not. You're going to die (or throw in the key not found sense if the key is an immutable ID type thing or return None() if the lookup is really a TryLookup type thing).

It would certainly be nice for your logger at the root level to inspect the exception itself to determine what error severity to log at though.

There are huge classes of errors that you really can't and shouldn't do anything about. Just die, log it, and move on.

If I pass it a bad handler, I most definitely want to die in most cases. Something went bad.

If I'm not finding data in a file, I might want to keep going and look for the next file for the data I'm searching for. I might also be searching in order to add that value only if it doesn't exist yet, in which case it is totally expected and not exceptional at all not to find it.

If I'm running out of file descriptors and I'm trying to refresh a value cached in memory by looking in a file, I might as well want to keep the value cached as it is (depending on the use case) and retry later, and not necessarily die until it's been N attempts at reading that failed.

Really, the context of the operation defines how important an error is. I keep my position that it would be helpful to be able to classify exceptions in a significant manner. If I can do it by matching on the error value itself, by its class, by return value, by whatever, that can be good enough, I guess, but you depend on conventions to get it right.

It's not related to exceptions vs. returns though.

MononcQc fucked around with this message at 20:16 on Feb 5, 2013

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

Shaggar posted:

the immediate caller should throw. then an intermediary will wrap the library specific failure in a framework specific one and throw that. then the system exception handler will decide to abort,retry,failure. it might decide oh hey if this storage mechanism fails requeue it for another attempt. or maybe try to send it out this backup mechanism.

in this case we're talking about a larger system where the higher level parts of the system don't want to have to understand anything other than their own exception types. you abstract the low level exceptions from them so your code is re-usable. this way when you add a module that uses BonerLib the system doesn't need to know about the new BonerOverflowException. that work is handled by your interface implementation between the high level system and BonerLib

this is really independent of exceptions vs return types or w/e.

Sure. Either log at the root or wrap at system boundaries to hide implementation. Wrapping isn't really 'handling' though in the 'take corrective action' sense.

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

MononcQc posted:

If I pass it a bad handler, I most definitely want to die in most cases. Something went bad.

If I'm not finding data in a file, I might want to keep going and look for the next file for the data I'm searching for. I might also be searching in order to add that value only if it doesn't exist yet, in which case it is totally expected and not exceptional at all not to find it.

If I'm running out of file descriptors and I'm trying to refresh a value cached in memory by looking in a file, I might as well want to keep the value cached as it is (depending on the use case) and retry later, and not necessarily die until it's been N attempts at reading that failed.

Really, the context of the operation defines how important an error is. I keep my position that it would be helpful to be able to classify exceptions in a significant manner. If I can do it by matching on the error value itself, by its class, by whatever, that can be good enough, I guess, but you depend on conventions to get it right.

I agree that the semantics are application dependent and yeah you're dependent on library authors at that point to have provided you the necessary tools to decipher whether the error you're seeing is one you can handle or it isn't. Sometimes this works out. In C# land with database junk, the SqlException class has a ton of extra error information that goes along with it that you could potentially use to determine whether the error was a deadlock, for example, that you should retry.

Aesthetically I definitely prefer a set of patterns to match against an ADT or something over a weird chain of catch statements, but I don't usually have that option.

Shaggar
Apr 26, 2006
right, but it does let you abstract the problem from an implementation specific one to a system specific one.

ex: lets say you have multiple storage implementations for writing an xml document. lets say one is file system and the other is database. both systems have specific errors for when the write fails for whatever reason so maybe you wrap those system specific ones in a DocumentStorageException. then when it gets higher up you could log it and/or retry it, or maybe send it to a different storage mechanism. This would be handled differently from a DocumentFormatException where the document you're storing is malformed and cant ever be successfully stored by any mechanism. Theoretically you catch this before you try to store it but its just an example.

Even if you're just logging and not trying to fix it you're still better off with the DocumentStorageException cause you only need to understand how to log that exception vs knowing how to log both FileIOException and SqlException. sure you can log them as their root Exception class but then you might lose exception specific details.

Shaggar
Apr 26, 2006
idk why you'd ever want to do pattern matching instead of type matching. that would make me want to vomit.

MononcQc
May 29, 2007

havelock posted:

I agree that the semantics are application dependent and yeah you're dependent on library authors at that point to have provided you the necessary tools to decipher whether the error you're seeing is one you can handle or it isn't. Sometimes this works out. In C# land with database junk, the SqlException class has a ton of extra error information that goes along with it that you could potentially use to determine whether the error was a deadlock, for example, that you should retry.

Aesthetically I definitely prefer a set of patterns to match against an ADT or something over a weird chain of catch statements, but I don't usually have that option.

Yeah, I'm definitely going for a wishlist here. I'm used to Erlang giving me {ok, Val} or {error, Reason} as a return value I can pattern match on for stuff I'm expected to handle (but can choose not to because I don't care/know how/want to make it an assertion), use 'throw' for non-local returns, 'error' for programmer errors, 'exit' for stuff that blocks actual execution and should terminate a process. They can be caught or not.

I definitely like this approach where different levels are available for different meanings, but I'd much prefer if they were better supported/explained or enforced. I'd like it if a more monadic approach (with Just and Maybe types/monads) could be used in conjunction with it.

I'd also like it if I could pattern match on stack traces within my try ... catch, rather than needing to invoke it later and re-raise the exception after matching, in separate steps, which would make it more useful when a higher-level item catches it and chooses whether it knows how to handle it or not, depending on where it was called.

:allears:

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

Shaggar posted:

idk why you'd ever want to do pattern matching instead of type matching. that would make me want to vomit.

One of the patterns you can match on is the type of the object which makes it strictly more powerful.

You also avoid fun stuff like:
Suppose you want to catch a deadlock and retry it, but for other things you have some default handler. You have a catch(SqlException ex) but what you really want is "catch a sql exception whose error number is 12345", so inside your catch block, you have to check a property of ex and if it isn't the one you want you have to duplicate the code in your default catch block because rethrowing would skip it.

MononcQc
May 29, 2007

Shaggar posted:

idk why you'd ever want to do pattern matching instead of type matching. that would make me want to vomit.

Generally they can be seen equivalent if you're working with dynamic languages (lisps that support it, Erlang, Prolog, I think), or static languages with the right types (Haskell, OCaml, SML, etc.). A tag used to wrap your value in a tuple is equivalent to a type you use as a tag, although the statically typed one should be much more efficient in virtually all scenarios.

They're also similar in that they're both much nicer than no matching at all.

hepatizon
Oct 27, 2010

MononcQc posted:

What do you plan to do with that information, generally speaking? Use it to fix the exception? What makes it impossible to fix right away knowing that information? Log it? I guess I can see it could make sense to log upwards if you don't have nice ways to do logging, but it would sound lovely not to be able to log from pretty much anywhere as you need it. Or maybe grouping all the logs together I guess.

What kind of additional information would you add, realistically speaking?

say you have a method that can fail in many different ways. regardless of the way the method fails, you probably want to include its arguments in the error message, along with relevant bits of the object state or whatever. if you take the log-from-anywhere approach, you either a) have redundant code for logging the state, or b) abstract it into a method, which is kinda overkill

it's much easier to append your state, re-throw it so the next method up can do the same, and so on until you reach the catchall that does the actual logging.

the point is that, just like the call stack, the state is a hierarchy that helps you understand how the error arose. it's much easier to let each level worry about its own state

my typical use case is when i'm processing a discrete job that depends on deeply structured data. if the data has a problem (a malformatted date, a missing element), you throw an exception to abort the job. as the exception ascends, it gets extra information attached to it, e.g. the data section, the URL of the API, the basic parameters of the job, etc. so if a job fails, i have a nice error message that shows me the exact problem and how to reproduce it

tef posted:

basically we have two ways to return data, a local and a non-local return. people seem to think one is for values and one is for errors. i do not think non-local returns are a good feature in code. i am sick of continuation weenies.

why? as i understand it, the constraints placed on exceptions (you can only return upward) eliminate the main drawback of non-local returns, which is that they're really confusing

i like the idea of combining return and throw, but it seems like it'd result in lots of boilerplate for methods that don't want to touch the error

hepatizon fucked around with this message at 20:44 on Feb 5, 2013

Shaggar
Apr 26, 2006

havelock posted:

One of the patterns you can match on is the type of the object which makes it strictly more powerful.

You also avoid fun stuff like:
Suppose you want to catch a deadlock and retry it, but for other things you have some default handler. You have a catch(SqlException ex) but what you really want is "catch a sql exception whose error number is 12345", so inside your catch block, you have to check a property of ex and if it isn't the one you want you have to duplicate the code in your default catch block because rethrowing would skip it.

yeah in the SqlException case its kind of annoying as poo poo that they give you a stupid error code instead of a more specific exception type. Personally i blame this on the institutionalized lovely exception handling in c#.

but then you're matching the sqlerror and then throwing the appropriate exception for that specific one back up the chain. You don't really want to throw error 6969420 up to the system exception handler cause it wont know what to do with it unless you hardcode it there. which means you've now got low level implementation code in your high level system code.

if its like a deadlock and you want to retry you return a generic TemporaryFailureException or something similar up to the system exception handler that will know to retry it. This same exception type would be used in other implementations to let the system know of a temporary error.

SqlException is like the worst of both worlds. ugh I hate it.

Shaggar
Apr 26, 2006

MononcQc posted:

Generally they can be seen equivalent if you're working with dynamic languages (lisps that support it, Erlang, Prolog, I think), or static languages with the right types (Haskell, OCaml, SML, etc.). A tag used to wrap your value in a tuple is equivalent to a type you use as a tag, although the statically typed one should be much more efficient in virtually all scenarios.

They're also similar in that they're both much nicer than no matching at all.

yeah I get that they work differently in different languages and im not really gonna get down on dynamic vs static (which u obv know which i'd prefer). my real concern is discoverability for the developer that a thing could throw an exception. check that poo poo, yo.

havelock
Jan 20, 2004

IGNORE ME
Soiled Meat

Shaggar posted:

but then you're matching the sqlerror and then throwing the appropriate exception for that specific one back up the chain. You don't really want to throw error 6969420 up to the system exception handler cause it wont know what to do with it unless you hardcode it there. which means you've now got low level implementation code in your high level system code.

if its like a deadlock and you want to retry you return a generic TemporaryFailureException or something similar up to the system exception handler that will know to retry it. This same exception type would be used in other implementations to let the system know of a temporary error.

SqlException is like the worst of both worlds. ugh I hate it.

Why would you throw it back up the chain if you know how to handle it right there?



Also, to be clear, you advocate having 10000 specific exception types to represent very finely grained error conditions and also that you should be forced by the language to list out every exception type you don't handle in the method signature?

raminasi
Jan 25, 2005

a last drink with no ice

i barely GNU her! posted:

re option types/discriminated unions: they kinda blew my mind when i tried learning f#

watch out, if you use them too much you get addicted and do stupid poo poo like pulling out part of your c# app into a separate f# project just so you can use them

Shaggar
Apr 26, 2006

havelock posted:

Why would you throw it back up the chain if you know how to handle it right there?



Also, to be clear, you advocate having 10000 specific exception types to represent very finely grained error conditions and also that you should be forced by the language to list out every exception type you don't handle in the method signature?

you cant handle it right there is what im saying. that's why you throw it.

and yes I would prefer a combination of more specific sqlexception types combined with enums for detailed typing. gently caress integer error codes. you obviously probably cant do a specific exception for every sql error, but you absolutely could have exceptions for the most common errors and then more generic exceptions for groups of errors.

like do this: http://docs.oracle.com/javase/6/docs/api/java/sql/SQLException.html
instead of this: http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlexception.aspx

its just loving dumb that Microsoft cant have some code based mechanism for telling you what the exception means without you having to google an integer.

Cocoa Crispies
Jul 20, 2001

Vehicular Manslaughter!

Pillbug

GrumpyDoctor posted:

watch out, if you use them too much you get addicted and do stupid poo poo like pulling out part of your c# app into a separate f# project just so you can use them

why wouldn't you implement a hard part ofy our app in a more powerful language? masochism?

Elos
Jan 8, 2009

hey shaggar is LUA a p-language?

tef
May 30, 2004

-> some l-system crap ->
is hello world less than 10 lines? p-lang

Adbot
ADBOT LOVES YOU

MononcQc
May 29, 2007

hepatizon posted:

say you have a method that can fail in many different ways. regardless of the way the method fails, you probably want to include its arguments in the error message, along with relevant bits of the object state or whatever. if you take the log-from-anywhere approach, you either a) have redundant code for logging the state, or b) abstract it into a method, which is kinda overkill

it's much easier to append your state, re-throw it so the next method up can do the same, and so on until you reach the catchall that does the actual logging.

the point is that, just like the call stack, the state is a hierarchy that helps you understand how the error arose. it's much easier to let each level worry about its own state

my typical use case is when i'm processing a discrete job that depends on deeply structured data. if the data has a problem (a malformatted date, a missing element), you throw an exception to abort the job. as the exception ascends, it gets extra information attached to it, e.g. the data section, the URL of the API, the basic parameters of the job, etc. so if a job fails, i have a nice error message that shows me the exact problem and how to reproduce it
It's possible I'm a bit too used to using Erlang in my every day job. The stack trace is part of default error logging, including arguments to the failing function. The logger is native to the VM (can be overridden), and is available by sending a log message to it from anywhere, blocking or not.

Having a try ... catch at each level is also an impossibility in a language that requires last call optimization -- a try ... catch adds a stack frame there, dropping the ability to do tail calls at all. If you don't catch an exception, it just bubbles up until the process is killed and it gets auto-logged.

I see what you mean by adding data though and can see it as useful. Usually I think I'd start adding details to logging after our servers start dumping a few errors I can't figure out. I'm sure if we were shipping to customers and couldn't modify code on-demand we'd take a somewhat different approach.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply