Is it my fault?
-
Eddy Vluggen wrote:
An insert is not a validation-routine. Yes, you can try to not use an exception, but if it complicates the code for an unmeasurable "speed optimization", you are still writing crappy code.
The code in question is regarding checking if an item is in a collection, ie it is validating the contents of the collection.
Eddy Vluggen wrote:
if it complicates the code for an unmeasurable "speed optimization", you are still writing crappy code.
It does the opposite.
if (!data.Contains(i))
{
data.Add(i);
}data[i].Value = x;
The above is clear to anyone who reads it what the rules and logic are.
try
{
data[i].Value = x;
}
catch
{
data.Add(i);
data[i].Value = x;
}The above is less obvious, doesn't read as well and is more ambiguous. So not using exceptions in this instance makes the code clearer and 10x faster. It's a no-brainer.
Eddy Vluggen wrote:
They do not "add up", unless you are using exceptions for simple logic.
Which is what we're talking about; using exceptions to dictate predictable and expected logic flow.
F-ES Sitecore wrote:
Which is what we're talking about; using exceptions to dictate predictable and expected logic flow.
Wasn't said in those words, so you could expect me to pound on the obvious. Also doesn't have anything to do with your webserver, does it? :)
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
F-ES Sitecore wrote:
Which is what we're talking about; using exceptions to dictate predictable and expected logic flow.
Wasn't said in those words, so you could expect me to pound on the obvious. Also doesn't have anything to do with your webserver, does it? :)
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
It doesn't have anything to do with web servers, no. That was just an example of why performance gains can matter even if they are small. I know you're trying to drag the discussion away from the technical because your technical arguments have fallen flat.
-
It doesn't have anything to do with web servers, no. That was just an example of why performance gains can matter even if they are small. I know you're trying to drag the discussion away from the technical because your technical arguments have fallen flat.
F-ES Sitecore wrote:
It doesn't have anything to do with web servers, no. That was just an example of why performance gains can matter even if they are small.
Which is why I already explained with a simple example that adding to a collection can be expensive; that's a strawman-argument as you will, but it isn't different from the webserver-example.
F-ES Sitecore wrote:
I know you're trying to drag the discussion away from the technical because your technical arguments have fallen flat.
If it had, you'd be quoting it and explaining why :D But, I can always appreciate a thread were we argue for arguings sake :thumbsup:
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
Jon McKee wrote:
You're conflating contexts. Think of things from the perspective of the class. A File class' only purpose is to manipulate a file. Singular. A developer specifies a path. You have every expectation that file should exist. Now you're a Collection class. You handle an object set. Plural. A developer specifies an object. You have two options now: 1) the object set is well-defined, the object should exist, 2) the object set is not well-defined, the object might exist. The big difference is that the Collection relies on the properties of the set while the File relies on the properties of the individual.
Lots of nonsense.
Jon McKee wrote:
Collections are more abstractly complex than Files.
So, a string is more complex than an Sql Server database-file now? And the string determines your approach?
Jon McKee wrote:
Agreed. Unless it's appropriate. In which case it's simply inefficient to use exceptions.
The only example I have seen that could be called "inappropriate" is where a try-catch is if you use it for a single check. Whether it is efficient depends on how often an exception is raised.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
Eddy Vluggen wrote:
Lots of nonsense.
Nah, was trying to simplify a thought and failed I guess. A File is a bad example because it accesses a collection at the end of the day too; it isn't truly singular. I was attempting to explain that a collection, because it's a set of elements, has intrinsic properties that an element that isn't itself a collection doesn't have. These properties can (help) determine lots of design decisions including the best method of accessing elements of that collection. That's why
File.Open
throws exceptions yetFile.Exists
is still made available - they're for sets that have different properties. If you deal with a file or files which frequently don't exist, you can use that check instead of exceptions. If you deal with a file or files which almost always do exist, you can rely on exceptions. -
Eddy Vluggen wrote:
Lots of nonsense.
Nah, was trying to simplify a thought and failed I guess. A File is a bad example because it accesses a collection at the end of the day too; it isn't truly singular. I was attempting to explain that a collection, because it's a set of elements, has intrinsic properties that an element that isn't itself a collection doesn't have. These properties can (help) determine lots of design decisions including the best method of accessing elements of that collection. That's why
File.Open
throws exceptions yetFile.Exists
is still made available - they're for sets that have different properties. If you deal with a file or files which frequently don't exist, you can use that check instead of exceptions. If you deal with a file or files which almost always do exist, you can rely on exceptions.Jon McKee wrote:
If you deal with a file or files which frequently don't exist, you can use that check instead of exceptions.
If you expect that the file not might exist, then it not existing is not really something exceptional. In an environment with a lot of people manipulating the FS, relying on the exception might be cheaper than doing the actual check (which might have race-conditions attached). In a database the difference can become more outspoken - depending on how much additional checks the database-server has to make. Of course, on does not use an exception-handling routine instead of a logical
if
.Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
-
Something not being in a collection isn't by definition a bug. It might be in your case. If
y
should approach 0 with your collection then exceptions would be the way to go. This has more to do with the data your collection services and the qualities of that data. If you have a unique set for your domain, then the collection will probably rarely run into an access outside of that domain. If the domain is generic then accesses outside of the registered or active parts of the domain will probably be much more common.Well, perhaps "bug" was over-stating my opinion a bit, perhaps "poorly-developed" is a better term, and as I stated in my edit -- searching for a parameter by name (and probably members of other collections as well) is a code smell. Best to avoid it. In many cases, the developer will know what's in a collection. This is true of the program I was working on -- I know the parameter is in there, I even know that it's at index 0, so why search for it by name? BUT, I write a lot of library/framework code that others might use (yeah, as if), so I need to keep "lesser developers" in mind. :-D As luck would have it, I was just re-reading a "List of Principles" of Programming Languages and saw this: "Localized Cost: Users should only pay for what they use; avoid distributed costs." -- MacLennan, 1987 I would apply this to the current discussion as: "Programs which call GetParameter only when the parameter is known to exist should not have to pay for the double-checking that would benefit only other programs." Is my code still violating that Principle? Yes. Because my GetParameter function tries to be provider-neutral, it has protection against calls that return NULL (e.g. Oracle) -- a program that uses SQL Server will still be paying that cost with no benefit to itself. However, the test for NULL is much less than the double-search.
-
Well, perhaps "bug" was over-stating my opinion a bit, perhaps "poorly-developed" is a better term, and as I stated in my edit -- searching for a parameter by name (and probably members of other collections as well) is a code smell. Best to avoid it. In many cases, the developer will know what's in a collection. This is true of the program I was working on -- I know the parameter is in there, I even know that it's at index 0, so why search for it by name? BUT, I write a lot of library/framework code that others might use (yeah, as if), so I need to keep "lesser developers" in mind. :-D As luck would have it, I was just re-reading a "List of Principles" of Programming Languages and saw this: "Localized Cost: Users should only pay for what they use; avoid distributed costs." -- MacLennan, 1987 I would apply this to the current discussion as: "Programs which call GetParameter only when the parameter is known to exist should not have to pay for the double-checking that would benefit only other programs." Is my code still violating that Principle? Yes. Because my GetParameter function tries to be provider-neutral, it has protection against calls that return NULL (e.g. Oracle) -- a program that uses SQL Server will still be paying that cost with no benefit to itself. However, the test for NULL is much less than the double-search.
I see where you're coming from given that example. I tend to enjoy writing more dev-oriented tools as well. Abstractions such as labels/names don't bother me though. In my mind there's no difference between representing a key via integer or string if you're free to make the choice; they're both just abstractions in this context. The only requirement for a key is a unique set of bits however that ends up implemented. I recently watched a great Computerphile[^] video where he was touching on the subject of abstraction using assemblers. Apparently John von Neumann thought assemblers were harmful because they took more processing time. Neumann thought this was wholly unnecessary because you could simply manually address the program making a double-pass by the assembler a waste of time (double because you need to scan for forward-jumping labels first). Got me thinking about the more general debate topic when you have multiple techniques to accomplish effectively the same thing and how advantages/disadvantages can sometimes be relative to the developer or the architecture.
-
I do a lot with ADO.net, and I use parameters as much as I can. Recently I was working on this method:
private static System.Data.IDbDataParameter GetParameter ( this System.Data.IDbCommand CMD , string Name ) { System.Data.IDbDataParameter result ; if ( CMD.Parameters.Contains ( Name ) ) { result = (System.Data.IDbDataParameter) CMD.Parameters \[ Name \] ; } else { result = CMD.CreateParameter() ; result.ParameterName = Name ; CMD.Parameters.Add ( result ) ; } return ( result ) ; }
It gets a parameter by name or creates one with the provided name if there isn't one already. After a while I decided to change it to avoid the call to Contains (the getter and Add have to check for existence anyway) and use
try/catch
to detect the absence of the parameter:private static System.Data.IDbDataParameter GetParameter ( this System.Data.IDbCommand CMD , string Name ) { System.Data.IDbDataParameter result ; try { result = (System.Data.IDbDataParameter) CMD.Parameters \[ Name \] ; } catch ( System.IndexOutOfRangeException err ) { result = CMD.CreateParameter() ; result.ParameterName = Name ; CMD.Parameters.Add ( result ) ; } return ( result ) ; }
And it was good. Until today. And Oracle.
Oracle.DataAccess.Client.OracleParameterCollection
returnsNULL
when the parameter doesn't exist! :mad::mad::mad: I had to revert back to the earlier code. :sigh: Edit: After a little more experimentation, I find that other ADO.net Providers I have handy also differ from Microsoft's lead -- four vendors, four outcomes. But, then again, MSDN doesn't say what should happen in this situation! Anyway, I have since decided that the whole concept of the above code was a bad idea -- I know whether or not the parameter exists and I should act accordingly. In any case, I rarely have to get a parameter by name -- it's a code smell. Here, then, is an improved GetParameter (by Name), with no trying to Create and Add missing parameters -- I don't intend to call this when I know the parameter doesn't exist. When a parameter doesn't exist, it is consistent in its behavior, so the caller canIf you are concerned about finding the maximal intersection of readability, performance and reliability, it is advised to ALWAYS use the `bool TryGet( key, out value )` pattern and avoid `bool Contains( key )` like the plague. Moreover, after a TryGet returns false, do not use the Add method since it checks AGAIN for the existence of the item. Instead, use the set indexer to assign the value to the key's index. `if (!items.TryGet( key, out T value )) { value = GetNewValueLogic( key ); items[key] = value }` Extremely readable, and it provides the best possible performance in all cases.
-
If you are concerned about finding the maximal intersection of readability, performance and reliability, it is advised to ALWAYS use the `bool TryGet( key, out value )` pattern and avoid `bool Contains( key )` like the plague. Moreover, after a TryGet returns false, do not use the Add method since it checks AGAIN for the existence of the item. Instead, use the set indexer to assign the value to the key's index. `if (!items.TryGet( key, out T value )) { value = GetNewValueLogic( key ); items[key] = value }` Extremely readable, and it provides the best possible performance in all cases.
A good suggestion; but the
IDataParameterCollection
interface doesn't provide aTryGet
method. As far as I can see, none of the concrete implementations do either. Personally, I think ConcurrentDictionary[^] provides a better API than the standardDictionary
:// Get the item with the specified key if it exists;
// otherwise, pass the key to the lambda method to create a new item, and add it to the dictionary:
T value = items.GetOrAdd(key, GetNewValueLogic);
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
A good suggestion; but the
IDataParameterCollection
interface doesn't provide aTryGet
method. As far as I can see, none of the concrete implementations do either. Personally, I think ConcurrentDictionary[^] provides a better API than the standardDictionary
:// Get the item with the specified key if it exists;
// otherwise, pass the key to the lambda method to create a new item, and add it to the dictionary:
T value = items.GetOrAdd(key, GetNewValueLogic);
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Apologies. That's not an API that I was familiar with. I'm shocked that a TryGet isn't provided!
-
Jon McKee wrote:
Of course you shouldn't avoid using them when appropriate. Exceptions are for exceptional circumstances.
Doesn't look like they are only used in "exceptional" circumstances if I look at the .NET reference code :)
Jon McKee wrote:
Collection classes implement search/find methods because an item not being in the collection is not exceptional.
They can be exceptional; it depends on what the programmer (me) is expecting. If I specify an item from the collection over the index that doesn't exist, I'll get an exception.
Jon McKee wrote:
Since searching or indexing into the collection has to occur anyways, the method saves time by returning a simple boolean rather than invoking the exception stack. As you point out in your link though, if this is front-end code the user probably wouldn't notice even if they could generate 10,000 exceptions back-to-back. In that scenario it comes down to what you define as best practices.
Best practice means not to discourage the use of exceptions, simply because someone thinks that they slow the system. As you can see, it doesn't take much time to invoke the entire exception stack, as it can be done several thousand times in a second. Too many idiots avoiding exceptions altogether and using booleans instead :thumbsup: If it is an error, throw an exception, it is that simple.
Bastard Programmer from Hell :suss: If you can't read my code, try converting it here[^] "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
Eddy Vluggen wrote:
Best practice means not to discourage the use of exceptions, simply because someone thinks that they slow the system. As you can see, it doesn't take much time to invoke the entire exception stack, as it can be done several thousand times in a second.
I've seen a few exceptions that consumed viscerally measurable time, but they were thrown deep in the stack, but the first exception handler that could catch them was in or near the main routine, many layers up the call stack. Hence, there was a lot of stack to unwind.
Eddy Vluggen wrote:
Too many idiots avoiding exceptions altogether and using booleans instead :thumbsup: If it is an error, throw an exception, it is that simple.
Too many people being too lazy to use their God given brains as intended. Programming is, after all, all about thinking. Best practices are intended to serve as rules of thumb, not ironclad rules.
David A. Gray Delivering Solutions for the Ages, One Problem at a Time Interpreting the Fundamental Principle of Tabular Reporting