Recent

Author Topic: General / Generic Error Handling  (Read 8950 times)

joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
General / Generic Error Handling
« on: August 28, 2017, 07:45:09 pm »
I'm new to FP, but have previously been using TP, BP, Delphi, VirtualPascal, etc.

Are Exceptions to be considered best practice in the FP environment for error handling? Or is there some error handling / error code enumeration function that I have missed? I'm trying to port a rather big applications where errors were previously handled by returning an error code, and then the error code would be enumerated to an error message and displayed / logged / whatever. Depending on how serious the error was, the application may continue to run or issue a "Fatal Abort".

Should this be done with Exceptions in the FP world, or are there other ways?


marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: General / Generic Error Handling
« Reply #1 on: August 28, 2017, 11:20:27 pm »
FPC has two faces, one more TP like and one more Delphi side, so it is a matter of choosing.

However, even with Delphi, exceptions are mainly meant to pass exceptions in business code up to higher level to keep it simple and cheap. System and more performing code generally avoid exceptions, and handle errors locally as much as possible. (see e.g. trystrtoint)

Or do you mean system/runtime errors ? What do you exactly miss from TP/Delphi?


joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #2 on: August 28, 2017, 11:29:07 pm »
I think a lot of my initial queries come from not being used to playing with FP enough (yet). A lot of the code I'm porting, is based around my own encapsulating units, classes, and functions. They in turn call the underlying stuff, much like an RTL separates the programmer from the OS I guess. When I did the Virtual Pascal (for OS/2) port of this, I tried to emulate as much of what I was already doing into a set of libraries for VP so I didn't have to change too much of the application code. That worked out quite nicely.

This time, I've decided (almost) to go the other way. FP will most likely be the last tool used for the Pascal version of the code, so I try to look for "native" FP functions that does what I need and then take out all IFDEF <platform> that I can and let FP's RTL handle the differences. The problem is that I seem to need to learn the entire FCL, RTL, etc by heart ... or die from lack of patience :)

Psuedo code of what I'm used to:

f := OpenFile ('foo.txt', rO | dW);
if (f < 0) then
  begin
    if (errno = ENOENT) then
      f := CreateFile ('foo.txt', rW | DW)
    else
       DieFatallyAndMakeNoises ('foo.txt', errno);
  end
else
  .. .. ... ...


So in this particular case, I guess I was looking for a standardized set of error codes, 1 - nnnnnn, that can be used universally between all units, on all platforms, to mean the same thing; to be reported to the user, or the log file, or whatever.

(Sorry if this sounds like incoherent ramblings, I've got 32 browser tabs open and three PDF files trying to make sense of the entire structure :) )

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: General / Generic Error Handling
« Reply #3 on: August 28, 2017, 11:40:13 pm »
FPC does not emulate POSIX on win32.

The best principle is to use system (in delphi mode) and sysutils function as much as possible, that avoids 255-260 char length problems, and even has some unicode capabilities.

The errorcodes are mostly system specific though, but afaik OS/2 and win32 are fairly similar there for the base errors, and on Unix it will be mostly the errno returnvalues, so that is fairly straightforward.


joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #4 on: August 28, 2017, 11:44:30 pm »
Right ... but I'd still need to map all this to a "generic" set of values that are IFDEFd around system specifics, right?

Something like (psuedo):

ec_FileNotFound = 1;
ec_PathNotFound = 2;

function mapOStoGeneric (ecOS : longword): longword;
begin
  ifdef os2
      case enoent: mapOStoGeneric := ec_FileNotFound;
      case enopath: mapOStoGeneric := ec_PathNotFound;
  elifdef linux
      case fooFiienoent: mapOStoGeneric := ec_FileNotFound;
      case FooFiienopath: mapOStoGeneric := ec_PathNotFound;
  elifdef win32
  elifdef dos
  endif
end;

and so on ... to get some sort of abstraction.

joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #5 on: September 01, 2017, 08:54:56 am »

So for all FileOpen and FileCreate, for example, the only way of knowing that something went wrong is to look at the handle and see if it's = feInvalidHandle?

How do I know if the error was due to an invalid path, access denied, or some other error ... ?


FPC does not emulate POSIX on win32.

The best principle is to use system (in delphi mode) and sysutils function as much as possible, that avoids 255-260 char length problems, and even has some unicode capabilities.

The errorcodes are mostly system specific though, but afaik OS/2 and win32 are fairly similar there for the base errors, and on Unix it will be mostly the errno returnvalues, so that is fairly straightforward.

Thaddy

  • Hero Member
  • *****
  • Posts: 14199
  • Probably until I exterminate Putin.
Re: General / Generic Error Handling
« Reply #6 on: September 01, 2017, 10:56:53 am »

So for all FileOpen and FileCreate, for example, the only way of knowing that something went wrong is to look at the handle and see if it's = feInvalidHandle?
https://freepascal.org/docs-html/current/user/userap4.html#x190-197000D

So absolutely not. Fully cross platform. Basic capability deficiency. Will be OK in your future...in most but not all cases... :D You may also want to have a look at IOResult and {$I+/-} in the manuals...
Actually, contrary to most programmers, I find manuals a rather good idea? O:-)
« Last Edit: September 01, 2017, 11:13:18 am by Thaddy »
Specialize a type, not a var.

joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #7 on: September 01, 2017, 04:38:27 pm »

OK, thanks. That makes sense. I just got a bit confused. I remember the IOResult handling, etc. from way before I put my own I/O routines everywhere, mostly translated from how they work in C/C++ (the handle I/O kind). I guess I'm back to doing it the "Turbo Pascal" way now, even for the handle based functions :)

So a FileOpen with {$I-} will then generate an RTE from one of those mentioned, if I understand you correctly. Just like the "standard Turbo Pascal I/O" functions?

Thaddy

  • Hero Member
  • *****
  • Posts: 14199
  • Probably until I exterminate Putin.
Re: General / Generic Error Handling
« Reply #8 on: September 01, 2017, 05:32:03 pm »
So a FileOpen with {$I-} will then generate an RTE from one of those mentioned, if I understand you correctly. Just like the "standard Turbo Pascal I/O" functions?
Exactly! Glad to be of help.
Specialize a type, not a var.

joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #9 on: September 01, 2017, 05:33:33 pm »
Thanks  :D

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: General / Generic Error Handling
« Reply #10 on: September 01, 2017, 05:39:19 pm »

So for all FileOpen and FileCreate, for example, the only way of knowing that something went wrong is to look at the handle and see if it's = feInvalidHandle?

Well, that is what Embarcadero specifies, and worse they even discourage these functions, see e.g.  http://docs.embarcadero.com/products/rad_studio/delphiAndcpp2009/HelpUpdate2/EN/html/delphivclwin32/SysUtils_FileOpen.html

So why would FPC be different ? (afaik these were originally Win16-32 related winapi wrappers for TPW->D1->D2 changeovers, and never meant to be published apis)

Quote
How do I know if the error was due to an invalid path, access denied, or some other error ... ?

Use ioresult the old fashioned way. IOResult does have some error mapping. But use the Delphi equivalents AssignFIle etc. See https://www.freepascal.org/docs-html/rtl/system/ioresult.html

Though not all will happen for all targets.

« Last Edit: September 01, 2017, 05:41:24 pm by marcov »

joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #11 on: September 01, 2017, 05:46:43 pm »
This is messy. To put it mildly. So ... what is the best, and most portable (FPC style) way of doing I/O *with* proper error control?

VAR
  FH :THandle;

{$I+}
FH := FileOpen ('C:\NotHere.Txt', fmOpenWrite or fmShareDenyWrite);
writeln ('IOResult ', IOResult);
writeln (FH);
FileClose (FH);
writeln ('IOResult ', IOResult);
{$I-}

I would have expected a RTE in at least two places here.

1) When I open the file, since it's not here, and 2) definitely when I try to close an invalid file handle.

There are many many many thousand lines of code in this application, I wasn't planning on re-writing all the I/O code on top of everything else that needs fixing ...  :o

I realize I can't get away with not knowing *some* quirks, but I don't really want to spend all my porting time learning about quirks. I just want to port the application to a Win32 (or Win64 :)) console application using FPC, and then take it from there ...


joho

  • Jr. Member
  • **
  • Posts: 69
  • Joaquim Homrighausen
    • ~/JoHo
Re: General / Generic Error Handling
« Reply #12 on: September 01, 2017, 05:51:15 pm »
I don't quite understand their comment about "Low Level" either ... what's Low Level about Handle := Open (File, Mode)?! :) You do the same thing when you use an object based class construct like MyStream := New MyStreamClass (Filename, Mode) ... it's just an other way of encapsulating the "low level" calls because you want more logic in your class than the OS I/O functions provide.

Thaddy

  • Hero Member
  • *****
  • Posts: 14199
  • Probably until I exterminate Putin.
Re: General / Generic Error Handling
« Reply #13 on: September 01, 2017, 06:20:57 pm »
Marco has lost me too... :D This was a design goal for FPC: TP compatibility. Which it is, apart from some 16/32 bit niggles.
Specialize a type, not a var.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 11383
  • FPC developer.
Re: General / Generic Error Handling
« Reply #14 on: September 01, 2017, 07:39:49 pm »
I don't quite understand their comment about "Low Level" either ... what's Low Level about Handle := Open (File, Mode)?! :)

Afaik it was a temporary routine to keep TPW code running, where people programmed closer to the winapi. I'm no D1/TPW expert though (I skipped Win3.x entirely, at least for programming purposes).

IOW it never was what you thought it to be, a general, supportable delphi function. FPC never implemented, and the Delphi help also shows this fact.

Keep in mind that deprecated tags on procedural level would not emerge till D2006 or so.

You are not the first, you will not be the last (fileexists on Directories "works" in Delphi even though not documented, however emulating it for the few that didn't care to use undocumented feature will tragically slow down on *nix)

Quote
You do the same thing when you use an object based class construct like MyStream := New MyStreamClass (Filename, Mode) ... it's just an other way of encapsulating the "low level" calls because you want more logic in your class than the OS I/O functions provide.

It's not procedural vs OOP, but documented procedural (assignfile+reset/rewite, documented codes in ioresult) vs semi documented procedural (fileopen, no errorcodes documented)

 

TinyPortal © 2005-2018