|
What is the rule of thumb for deciding whether to throw an exception or return an error code when something goes wrong?
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
It may depend on your application and whatever is standard practice in your existing code base, if you're dealing with one.
For a system that handles lots of transactions, I strongly advise using an exception only if a transaction should be aborted because of a serious error that also gets logged for debugging. The exception gets caught well down the stack, where bulletproof recovery and logging are initiated. In this type of system, it is very rare for application code to catch exceptions.
The general problem with exceptions is that the caller must know that a function will throw . Even if this is documented by keywords or comments, will the catch actually get written? Nothing forces it to be, whereas it's harder to ignore an error code. And if the catch isn't written, the exception trickles down the stack. What can anyone else make of it? Ultimately it's up to that bulletproof code unless crashing is OK.
Exceptions also have more overhead than error codes, not only in CPU time but in code bulk.
There's also the question of where the finger of blame should point. If someone passes your function a null pointer and you use it, guess where the SIGSEGV occurs? So it's your code that ends up looking crappy, even if the stack trace can point you to the real culprit. I therefore make it a habit to check arguments for validity and to generate a log and return an error code if one is found to be nonsense. This also makes debugging easier for everyone.
It'd be hard to convince me that a system should use exceptions other than sparingly. Having a system that mixes error codes and exceptions seemingly at random makes no sense.
|
|
|
|
|
There is no rule of thumb for choosing between the two. Each one has advantages and disadvantages. There are also more "modern" solutions like std::expected and boost::outcome . If you want some rules of thumb:
- Be consistent. If you have some functions returning an error code and others throwing exceptions you can easily create a big mess.
- Design your error handling mechanism early. Retrofitting any error mechanism is very painful
This may sound terribly immodest, but my own solution, a cross between exceptions and error codes, still seems to me the best compromise. I've used it for almost 20 years so most of it is battle hardened code. The code in the article is a bit old so you might be better off grabbing the latest version from GitHub.
Mircea
|
|
|
|
|
Mircea Neacsu wrote: If you have some functions returning an error code and others throwing exceptions you can easily create a big mess. This sounds to me like 'Use either exceptions or error codes in your program - never both'.
To me, that is similar to 'Define either errors or warnings - never both'. But of course you will not define all warnings as errors.
Mircea Neacsu wrote: my own solution, a cross between exceptions and error codes I am really happy that you added this I hope readers see this as your primary advice, rather than the either/or thinking that you introduced in the beginning.
If you run into a situation that the caller can handle then and there, and go on, is different from a situation which is fatal to some significant operation, so it has to be abandoned. If you want a rule of thumb (but one with many exceptions): If a caller can handle an error code, restore to a 'normal' condition and continue, with no significant operation aborted, the an error code is appropriate. If handling the situation back to normal cannot be done by the caller after the return, but must be reported to some outer level (and possibly to the user), then an exception is more appropriate.
The borderline is certainly not sharp (nor is the line between warnings and errors!), and often a design selection. Some people/environments have raised a 'robustness principle' (based on the rule 'Be tolerant with others, and strict with yourself', codified in RFC 761), doing what is possible recover and continue, while others want to expose, not gloss over problems (e.g. OSI stack protocols, disconnecting on any protocol violations).
Religious freedom is the freedom to say that two plus two make five.
|
|
|
|
|
trønderen wrote: But of course you will not define all warnings as errors You are right. I should have said: "for similar situations use either errors or exceptions." For sure you can use both if you do it in a consistent manner.
trønderen wrote: If a caller can handle an error code, restore to a 'normal' condition and continue, with no significant operation aborted, the an error code is appropriate. If handling the situation back to normal cannot be done by the caller after the return, but must be reported to some outer level (and possibly to the user), then an exception is more appropriate. Indeed! The way I see it, the conundrum of error handling is that, at lower levels you have all the information about what happened but you cannot make any decision. At higher levels, you can make decisions but the amount of information you have is limited (errors have been coerced in a few error codes, exceptions have limited information, etc.). This is not unlike the situation in any organization where higher up executives have increasing decision power and decreasing knowledge about what's going on. Finding the appropriate compromise is difficult both for error handling and for organizations.
Going back to my error code objects solution, one more thing I particularly like is that it makes it immediately clear what functions return error codes. Looking at the signature of a function like:
int read (FILE* f, void* data, int& len); you cannot immediately know if the returned value is the number of bytes read, or an error code or a combination of those. Meanwhile, with my system, a function signature like:
erc read (FILE* F, void* data, int& len); it is clear that it returns an error code. Said error code magically transforms into an exception if not properly treated
Mircea
|
|
|
|
|
Eric Lippert provided a good classification of the different types of exceptions back in 2008:
Vexing exceptions | Fabulous adventures in coding[^]
Whilst he doesn't provide much specific advice, he does say:
Quote: Try to never write a library yourself that throws a vexing exception.
where a "vexing" exception is one that is "thrown in a completely non-exceptional circumstance" - eg: Int32.Parse .
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hello,
I study computer science and know a moderate amount about java and c and a bit about python and c++ when I say a bit I mean I solved leetcode problems with the language and followed along a tutorial on how to automate a process like webscraping with python and I (tried) to implement a neural network in c++.
I enjoy algorithmic/datastructures problems but probably software architecture as well and dont know how to continue picking up knowledge.
I am about to follow a tutorial on writing an interpreter in java and after that I want to learn Rust.
Should I revise my Software Engineering lecture because I forgot almost everything or read something related before doing more projects?
Thanks!
|
|
|
|
|
Choose a single llanguage and stick to it. Until you are really proficient in one lnaguage it is a waste of time trying to learn others. Despite their similarities the differences have a nasty way of tripping you up.
|
|
|
|
|
I enjoy algorithmic problems and have an interest in understanding software systems like compilers, operating systems, vms, databases or webbrowsers. What language do you think I would enjoy the most?
|
|
|
|
|
I cannot tell you what you would enjoy, but I would suggest that C or C++ would be the most useful in the areas that you are interested in.
|
|
|
|
|
Hello,
Thanks for the advice! I’ll focus on mastering one language before branching out to others. I appreciate the guidance.
|
|
|
|
|
I'm considering developing an app (iOS) my customers can use to send me files (typically PDF but could be other types, couple of MB at most). Sending the file has to be simple, just select and click Send. There are may ways to send/submit the file, e.g. (in no particular order):
- E-mail
- Dropbox (or similar)
- FTP
- Web service
- Some horrible custom client/server contraption
The files aren't top secret stuff and it's not the end of the world if the sending fails but but reliability is more important than security and simplicity (on both ends) is a must. I need to be able to group the files I receive by sender.
Any thoughts on what's the best approach?
|
|
|
|
|
When writing software, whether desktop or web-based, I have always separated the view from the view model. For example, in WPF (Microsoft desktop technology), I used MVVM, kept the XAML view as light as possible and put the logic and data access into a separate view model (regular C# class).
One of the main advantages of this is that it makes the view model easy to unit test, as I can set up mock dependencies, set the public properties that would normally be set by dependency injection or property binding and then call methods no the view model to test the code.
Nowadays I do pretty much everything in Blazor server-side, and used the same approach. My .razor file is pure markup, the .razor.cs file usually only contains overloads for the component life-cycle events, and generally passes the request through to the view model (as above).
However, one of my co-workers is encouraging the team to put all code into the .razor.cs file, and use bUnit to unit test the components. Given that we can mock dependencies, set public parameters and call methods, it does look as if this gives all the benefits of a separate view model, without needing the extra file.
Anyone any thoughts as to the advantages or disadvantages of either approach? Thanks
|
|
|
|
|
The whole "view model thing" started with the idea "visual designers" would do views; and "programmers" would do "models"; that "connected" to the view "transparently"; through the magic of "binding"; ignoring that the binding has to understand both; so that there is no "real" separation; and one bleeds into the other; without "seeing" it.
The average life of an app is 5 years. Few run on "so many" platforms that it needs sparate "views" and separate "models" in order to run.
The path of least resistance is not MVVM.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Thanks for the reply, but I'm not sure I agree with you on quite a few points.
View models (in the general sense of any MV* patterns) first came to the public attention in 1979 with Smalltalk, whereas the first visual designers for software development weren't until at least a decade later. Visual Basic was probably the first real visual designer, but didn't came out until 1991. Even if you want to stretch the point and include things like Hypercard, you only get a few more years (1987), still well after view models.
My understanding is that the point of view models was to separate the data access, logic and models from the UI. Yes, this was partly to allow the two to be developed independently, and possibly by different teams, but also (and possibly more importantly) to allow the former to be unit tested, something that was impossible in the early days of UI, and is still not so easy.
However, I don't really see the relevance. The idea of separating code into separate units is still useful, and binding is merely the common agreement between them. It doesn't really imply any bleeding going on. The view model can expose properties to be bound, and it's up to the view to choose whether or not to bind to them. That's not such a strong dependency.
Finally, even assuming your estimate of the average age of an app to be correct (which I would dispute, as I still maintain several projects that have been active for 10, 15 and in one case 25 years), why is that relevant? Length of life is not generally a determining factor in how you structure your projects, and separating layers is not just for multiple platforms.
Don't mean to be rude, but I really don't see how any of your points address my question. Please feel free to clarify if I've missed something.
|
|
|
|
|
I've seem enough questions on "how do I ... in MVVM" to know that it is (mostly) just another albatross.
Other than familiar "CRUD" LOB applictions, MVVM tends to over-complicate things: to the point that development takes longer and desirable features aren't implemented because "they" cannot figure out how to do it without "code behind" (and therefore "breaking" MVVM "rules").
MVVM is a recipe for mediocre software and budget and time overruns.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
OK, I guess our experiences are obviously very different. I find MVVM a fantastic way of keeping the concerns separate, and the ease of unit testing has improved both speed of development and ease of fixing bugs significantly. I've never, ever not implemented something because MVVM got in the way.
To me, MVVM is a recipe for faster and more stable development. As I said, I guess it depends on your experience.
Thanks anyway
|
|
|
|
|
Mr Yossu wrote: one of my co-workers is encouraging the team to put all code into the .razor.cs file
So a single file.
Unless the application is very small or there is zero functionality in that code then no that is a bad idea.
And maybe even for the second it still might not be a good idea.
Since presumably the file is modified by humans (not generated) then obviously the line count is a good demarcation. Is it going to be 100,000 lines long? Now? Or in the next 5 years then absolutely not.
If it is 20 lines long now and will be at most 100 in 5 years then it doesn't matter.
|
|
|
|
|
You might want to post your question in the forum at the bottom of the article. As it is right now, nobody has any clue what you're talking about.
|
|
|
|
|
"Sports" "Toto" "tv" (dot) "com"?
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
Yeah, I didn't even look at the name.
|
|
|
|
|
I am familiar with Excel VBA but new to C# and Visual Basicvisula Studio. I have an Excel file (.xlsm) with several sheets. Using ExcelDataReader, I managed to build a solution to show all sheet names in a combobox control.
I need help in how can I import the selected sheet content in combobox (cboSheet) to the datagridview1
using ExcelDataReader;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using System.Data.SqlClient;
namespace ReadandImportsheet1
{
public partial class Form1 : Form
{
private readonly object con;
public object Break { get; private set; }
public Form1()
{
InitializeComponent();
}
public Form1(object con)
{
this.con = con;
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog fil = new OpenFileDialog();
fil.ShowDialog();
string path = fil.FileName.ToString();
ExcelFileReader(path);
}
public void ExcelFileReader(string path)
{
var stream = File.Open(path, FileMode.Open, FileAccess.Read);
var reader = ExcelReaderFactory.CreateReader(stream);
var result = reader.AsDataSet();
var tables = result.Tables;
foreach (DataTable table in tables)
{
cboSheet.Items.Add(table.TableName);
}
}
private void cboSheet_SelectedIndexChanged(object sender, EventArgs e)
{
string table_name = cboSheet.Text;
SqlConnection Con = new SqlConnection("Provider = Microsoft.ACE.OLEDB.12.0; Data Source = path; Extended Properties = "Excel 8.0; HDR = YES";");
con.Open();
SqlDataAdapter da = new SqlDataAdapter("select * from " + table_name + " ", con);
DataSet ds = new DataSet();
da.Fill(ds);
dataGridView1.DataSource = ds.Tables[0];
dataGridView1.DataBind();
con.Close();
}
}
} I am using Win 11 and Visual Studio 2019 with ExcelDataReader and Exceldatareader.Dataset
Any help in coding will be extremely appreciated as I am new to C# coding and can not get sheet contents into the datagridview control.
modified 23-Feb-24 1:23am.
|
|
|
|
|
Export the Excel as CSV. Then you can see what you're getting the "easy" way.
"Before entering on an understanding, I have meditated for a long time, and have foreseen what might happen. It is not genius which reveals to me suddenly, secretly, what I have to say or to do in a circumstance unexpected by other people; it is reflection, it is meditation." - Napoleon I
|
|
|
|
|
I am familiar with Excel VBA but new to C# and Visual Basicvisula Studio.
|
|
|
|
|
Well aren't you just the most delightful ...
|
|
|
|
|