Link to home
Start Free TrialLog in
Avatar of Jacco
JaccoFlag for Netherlands

asked on

How to get ERangeError when casting Int64 to LongInt (db.pas)

Hello all,

The reason I as this is the following: In DB.pas there is a method TFloatField.GetAsInteger.

It is implemented as follows:

function TFloatField.GetAsFloat: Double;
begin
  if not GetData(@Result) then Result := 0;
end;

function TFloatField.GetAsInteger: Longint;
begin
  Result := Longint(Round(GetAsFloat));
end;

Round returns a Int64 and the result is casted to Integer. My problem is that some developer in my team use AsInteger for numeric(11,0) fields (which delphi translated into TFloatField) and Delphi generates no error at all also when Range Checking is on and Overflow Checking is on ($R- is specified in db.pas). I even tried the following:

function GetAsFloat: Double;
begin
  Result := 4000000000000000000;
end;

{$R+} {$Q+}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(IntToStr(LongInt(Round(GetAsFloat))));
end;

But I never get an error.

My question is the following:
- Can I get an error in D5 for this problem (without rewriting or patching the VCL)
- If so how?
- If it is not possible how should this patching:
  - By disabeling the AsInteger property for TFloatFields
  - By checking in the GetAsFloat for values that do not fit
- What advice do you have when patching the VCL (we want to be able to use a new version of Delphi without to much repatching the new VCL version)

Thanks Jacco
Avatar of Cynna
Cynna

Jacco,

If I understood you correctly, you want GetAsInteger function to raise ERangeError exception. You are wondering why this doesnt't happen when you try to convert obviously too large value for LongInt, right?

Solution
----------------

Get rid of the typecast - change GetAsInteger function from:

   Result := Longint(Round(GetAsFloat));

 to    

   {$R+} {$Q+}
   Result := Round(GetAsFloat);



Explanation
----------------

When you perform a typecast you are actually telling compiler:
"Don't check this assignment, I know what I'm doing".

So, regardless of {$R+}, when you did Longint(...) you told compiler to trust your judgement, and not to waste time implementing a range check code.
In your case, casting was redundant, as Int64 and LongInt have assignment-compatibility.

So, directly assigning Int64 to LongInt will firstly check if value you are about to assign to LongInt falls within the LongInt range, which is exactly what you need, right?
Avatar of Jacco

ASKER

Thanks Cynna,

You have explained one part of the question.

The code mentioned is in DB.pas of the Delphi VCL. The second part is how to handle this. Do I patch the VCL? We have a team of developers that would mean spreading a Delphi patch? Or is there a simpler solution.

I want some advice on how to go ahead with this.

I can award you 100 pts for explaining why $R+ $Q+ didn't help in this case, and what typecasting integers does.

Regards Jacco
create your own version?

type
  TRangeFloatField = class(TFloatField)
  protected
    procedure GetAsInteger: Integer; reintroduce;
  end;

...

procedure TRangeFloatField.GetAsInteger: Integer;
begin
  Result := Round(GetAsFloat);
end;


... and in later parts of your code

MyInteger := TRangeFloatField(MyFloatField).AsInteger;




not tested though, but I think it should work.




HTH
DragonSlayer
Avatar of Jacco

ASKER

Thanks DragonSlayer,

Ok, but how will I fool the TDataSet to create a TRangeFloatField in stead of a TFloatField in the IDE?

The team of programmers must not easily make a mistake. We use TTable, TQuery, TAdsTabe and TAdsQuery a lot.

One mistake can cause a disaster. The advantage tables have a "autoinc" field numeric(11,0). Both FoxPro apps and Delphi apps increase the numbers. One developer used

FieldByName('autoinc').AsInteger := FieldByName('autoinc').AsInteger + 1

Which is logical but cause all kinds of errors...

Regards Jacco

Regards Jacco
It can create TFloatField, you just typecast it to TRangeFloatField in code.
Avatar of Jacco

ASKER

Hi DragonSlayer,

What if a developer forgets to typecast...

Are there any other solutions?

Regards Jacco
I think there are no other ways :(
ASKER CERTIFIED SOLUTION
Avatar of Cynna
Cynna

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Jacco

ASKER

Thanks Cynna,

Fortunately we do not use packages (just one 6.5 MB exe) otherwise we would have to distribute a new BPL as well. Developers on the other hand need both altered PAS and DCU since some don't compile the Delphi sources...

I will flag Borland :)

I will award you the 300 points.

DragonSlayer if you want some points as well please tell me.

Regards Jacco
Avatar of Jacco

ASKER

Here you are
it's okay, points are up to you :)
Avatar of Jacco

ASKER