Delphi Rounding

Hello All:

    I need to get currency numbers to properly round - I tried 
x:=round(Y*100)/100; but that does not consistently round in the traditional 
US manner of .5 to the next 1.

    I wrote the following function to accomplish this:



    class function  TCommonPM.PRound(NumToRound: Currency): Currency;
Var Subtotal: Currency;
    Sub2: Integer;
begin
  Result:=NumToRound;
  Subtotal:=NumToRound*100;
  Sub2:=Trunc(Subtotal);
  If Subtotal-Sub2>=0.50 Then
    Sub2:=Sub2+1;
  Result:=Sub2/100;
end;



   Is there a better way to do this ??? Should it be done in assembler ??? I 
noticed that the code in system for round is in assembler.

procedure       _ROUND;
asm
        { ->    FST(0)  Extended argument       }
        { <-    EDX:EAX Result                  }

        SUB     ESP,8
        FISTP   qword ptr [ESP]
        FWAIT
        POP     EAX
        POP     EDX
end;

Thank you

Neil Huhta
0
Neil
4/3/2012 6:39:03 PM
embarcadero.delphi.win32 2183 articles. 0 followers. Follow

129 Replies
1950 Views

Similar Articles

[PageSpeed] 46
Get it on Google Play
Get it on Apple App Store

Neil Huhta wrote:
> Hello All:
> 
>     I need to get currency numbers to properly round - I tried 
> x:=round(Y*100)/100; but that does not consistently round in the traditional 
> US manner of .5 to the next 1.
> 

That is not proper rounding.  The proper rounding method is if it is .5 then you 
round to the nearest even number.  Delphi does proper rounding (often referred 
to as Bankers rounding since it introduces less error over a large random 
distribution of numbers).

-- 
Jeff Overcash (TeamB)
       (Please do not email me directly unless  asked. Thank You)
And so I patrol in the valley of the shadow of the tricolor
I must fear evil. For I am but mortal and mortals can only die.
Asking questions, pleading answers from the nameless
faceless watchers that stalk the carpeted  corridors of Whitehall.
              (Fish)
0
Jeff
4/3/2012 7:05:03 PM
Jeff:

    You are correct but I am also correct. I do not want to use bankers 
rounding for my purposes -

   proceeding forward - should I be changing my rounding routine to assembly 
for speed ??? Or - is it ok to leave my routine as it is.



Neil



"Jeff Overcash" <jeffovercash@mindspring.com> wrote in message 
news:457973@forums.embarcadero.com...
> Neil Huhta wrote:
>> Hello All:
>>
>>     I need to get currency numbers to properly round - I tried
>> x:=round(Y*100)/100; but that does not consistently round in the 
>> traditional
>> US manner of .5 to the next 1.
>>
>
> That is not proper rounding.  The proper rounding method is if it is .5 
> then you
> round to the nearest even number.  Delphi does proper rounding (often 
> referred
> to as Bankers rounding since it introduces less error over a large random
> distribution of numbers).
>
> -- 
> Jeff Overcash (TeamB)
>       (Please do not email me directly unless  asked. Thank You)
> And so I patrol in the valley of the shadow of the tricolor
> I must fear evil. For I am but mortal and mortals can only die.
> Asking questions, pleading answers from the nameless
> faceless watchers that stalk the carpeted  corridors of Whitehall.
>              (Fish)
0
Neil
4/3/2012 7:36:05 PM
Neil Huhta wrote:

> Hello All:
> 
>  I need to get currency numbers to properly round - I tried x:=round(Y*100)/100; but that does
> not consistently round in the traditional US manner of .5 to the next 1.

Neil,

Look at SimpleRoundTo (in the maths unit) or maybe this would do:
{code}
result := trunc(NumToRound * 100 + 0.5) / 100
{code}
assuming you want to round to the nearest cent.

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/3/2012 10:22:49 PM
On Tue, 3 Apr 2012 11:39:03 -0700, Neil Huhta <nhuhta@digital.net>
wrote:

>Hello All:
>
>    I need to get currency numbers to properly round - I tried 
>x:=round(Y*100)/100; but that does not consistently round in the traditional 
>US manner of .5 to the next 1.

It uses bankers rounding.  .5 rounds to the nearest even number.
0
Loren
4/4/2012 12:38:12 AM
"Neil Huhta" wrote
> I need to get currency numbers to properly round - I tried 
> x:=round(Y*100)/100; but that does not consistently round ...

Neil,
If you must have rounding according to a specific rule,
then you may want to use my rounding routines from the
code central routine ID: 21909, DecimalRounding (JH1).
  http://cc.embarcadero.com/Item/21909
In use with currency type, the values are normally read
into and out of floating binary point variables like double.
These routines from the code central module routines round
input values to fit as closely as possible to an output
number with desired number of decimal fraction digits.
Because, in general, numbers with decimal fractions cannot
be exactly represented in IEEE-754 floating binary point
variables, error limits are used to determine if the input
numbers are intended to represent an exact decimal fraction
rather than a nearby value. Thus, an error limit will be
taken into account when deciding that a number input such
as 1.295, which internally in float form is represented as
1.29499 99999 …, really should be considered exactly 1.295
and that 0.29999 99999 ... really should be interpreted as
0.3 when applying rounding rules.
Nine rounding rules are implemented.
HTH, JohnH
0
John
4/4/2012 1:40:34 AM
You may avoid convertion to / from double and rounding issue as such:

{code}
class function TCommonPM.PRound(NumToRound: Currency): Currency;
var V64: Int64 absolute Value; // to avoid any floating-point precision issues
    Decimals: integer;
begin
  Decimals := V64 mod 10000;
  dec(V64,Decimals);
  if Decimals>=500 then
    inc(Value,10000); // round up
  result := Value;
end;
{code}

This will work for values >0, perhaps to be enhanced for negative values.

See http://blog.synopse.info/post/2011/11/08/Currency-is-your-friend
0
Arnaud
4/4/2012 6:08:18 AM
> {quote:title=Neil Huhta wrote:}{quote}
> Hello All:
> 
>     I need to get currency numbers to properly round - I tried 
> x:=round(Y*100)/100; but that does not consistently round in the traditional 
> US manner of .5 to the next 1.
> ...
> Neil Huhta
You should use Math.SetRoundMode to setup behaviour of the Math.SimpleRoundTo the way you like.
0
Mikola
4/4/2012 9:26:10 AM
> {quote:title=Neil Huhta wrote:}{quote}
> Hello All:
> 
>     I need to get currency numbers to properly round - I tried 
> x:=round(Y*100)/100; but that does not consistently round in the traditional 
> US manner of .5 to the next 1.
> 
>     I wrote the following function to accomplish this:
> 
> 
> 
>     class function  TCommonPM.PRound(NumToRound: Currency): Currency;
> Var Subtotal: Currency;
>     Sub2: Integer;
> begin
>   Result:=NumToRound;
>   Subtotal:=NumToRound*100;
>   Sub2:=Trunc(Subtotal);
>   If Subtotal-Sub2>=0.50 Then
>     Sub2:=Sub2+1;
>   Result:=Sub2/100;
> end;
> 
> 
> 
>    Is there a better way to do this ??? Should it be done in assembler ??? I 
> noticed that the code in system for round is in assembler.
> 
> procedure       _ROUND;
> asm
>         { ->    FST(0)  Extended argument       }
>         { <-    EDX:EAX Result                  }
> 
>         SUB     ESP,8
>         FISTP   qword ptr [ESP]
>         FWAIT
>         POP     EAX
>         POP     EDX
> end;
> 
> Thank you
> 
> Neil Huhta

I've done the same for some currency items I wanted to round according to rules given in a spec document i.e. >=0.50 is +1. Pence in this case.

Would you gain by using assembler instead of what you've written?

Personally, I don't think that either me or my users would ever benefit from the microscopic amounts of time I'll have saved.
0
Sion
4/4/2012 12:41:10 PM
>> I need to get currency numbers to properly round - I 
>> tried x:=round(Y*100)/100; but that does not consistently
>> round in the traditional US manner of .5 to the next 1.


<Mikola Petrivskiy> wrote
> You should use Math.SetRoundMode to setup behavior
> of the Math.SimpleRoundTo the way you like.

Mikola, 
The rounding mode controls the floating binary-point 
operation of the FPU.  It will not always produce the 
desired result when binary fractions are used to represent 
decimal fraction numbers.
Regards, JohnH
0
John
4/4/2012 12:51:30 PM
Jeff Overcash wrote:

> Neil Huhta wrote:
> > Hello All:
> > 
> >     I need to get currency numbers to properly round - I tried 
> > x:=round(Y*100)/100; but that does not consistently round in the
> > traditional US manner of .5 to the next 1.
> > 
> 
> That is not proper rounding.  The proper rounding method is if it is
> .5 then you round to the nearest even number.  Delphi does proper
> rounding (often referred to as Bankers rounding since it introduces
> less error over a large random distribution of numbers).

By default, Delphi does use banker's rounding (round to nearest even)
indeed, but that is not necessarily "proper rounding". There are
several ways to round, and which one is "proper" depends on the
situation. You can tell the FPU which one you want to use.
-- 
"UNIX is simple. It just takes a genius to understand its
 simplicity." -- Dennis Ritchie
0
Rudy
4/4/2012 8:40:22 PM
Rudy Velthuis (TeamB) avait prétendu :
> Jeff Overcash wrote:
>
>> Neil Huhta wrote:
>>> Hello All:
>>> 
>>>     I need to get currency numbers to properly round - I tried 
>>> x:=round(Y*100)/100; but that does not consistently round in the
>>> traditional US manner of .5 to the next 1.
>>> 
>> 
>> That is not proper rounding.  The proper rounding method is if it is
>> .5 then you round to the nearest even number.  Delphi does proper
>> rounding (often referred to as Bankers rounding since it introduces
>> less error over a large random distribution of numbers).
>
> By default, Delphi does use banker's rounding (round to nearest even)
> indeed, but that is not necessarily "proper rounding". There are
> several ways to round, and which one is "proper" depends on the
> situation. You can tell the FPU which one you want to use.

I spend yhe whole day of yesterday to find rounding problems in my 
application :

The FPU has no support for Round up 0.5 to next 1. You can round always 
up, always down, simply truncate or round to next half or even but you 
cannot round 0.5 to next 1.

The embedded way to do this using Delphi is to use

X := Math.SimpleRoundTo(Y)

Beware of Math.RoundTo because it uses FPU rounding.

Neil, X := Round(Y*100)/100 is not good because Round uses FPU rounding 
and Y is converted to Extended, so the Result is an Extended and if X 
is a Currency, the conversion is done by the FPU. The other caveat of 
your method is that it don't work for negative numbers.

SimpleRoundTo uses the same algorithm but do things in order to avoid 
using Round.

You can round currencies 0.5 to next 1 using this function that don't 
uses Extended or any conversion (and it works for negative numbers too) 
:

{ Idea come from Synopse }
function RoundCurrency(const Value: Currency): Currency;
var
  V64: Int64 absolute Result;
  Decimals: Integer;
begin
  Result := Value;
  Decimals := V64 mod 100;
  Dec(V64, Decimals);
  case Decimals of
    -99 .. -50 : Dec(V64, 100);
     50 ..  99 : Inc(V64, 100);
  end;
end;

I also found several rules :

* Never use Single or Doubles in computations involving currencies.
* Beware of conversions from Extended to Currency
* Beware of conparisons between Extended and Currency
* Beware of X64 because Extended is mapped to Double and there is no 
more type like Extended on 80 bits (but you can find on on CodeCentral)

As an example :

procedure RunCheckRound3;
var
  F: Extended; { Mapped to Double on X64 }
  C: Currency;
begin
  F := 2.62496;
  C := SimpleRoundTo(F, -4);
  F := SimpleRoundTo(C);
  C := SimpleRoundTo(C);
  {$IFDEF CPUX86}
    Assert(F <> C);
  {$ELSE}
     Assert(F = C);
  {$ENDIF}
  Assert(SameValue(F, C));
end;

-- 
Pierre
0
Pierre
4/5/2012 7:41:50 AM
"Pierre Yager" <pierre.yager@crisalid.com> wrote
> ... [spent] whole day of yesterday to find rounding problems ...

Pierre,  
If you must use floating binary-point variable types like single, 
double, or extended for holding decimal fraction numbers, then 
you really should be using something like DecimalRounding_JH1, 
which is available from 
  http://cc.embarcadero.com/Item/21909
to do your decimal rounding.   DecimalRounding_JH1 will do the 
following types of rounding.
Rgds, JohnH

Type tDecimalRoundingCtrl =    {The defined rounding methods}
   (drNone,    {No rounding.}
    drHalfEven,{to nearest or to even whole number. Bankers}
    drHalfPos, {to nearest or toward positive.}
    drHalfNeg, {to nearest or toward negative.}
    drHalfDown,{to nearest or toward zero.}
    drHalfUp,  {to nearest or away from zero.}
    drRndNeg,  {toward negative.                    Floor}
    drRndPos,  {toward positive.                    Ceil }
    drRndDown, {toward zero.                        Trunc}
    drRndUp);  {away from zero.}

The following DecimalRound function is for doing the best possible 
job of   rounding floating binary point numbers to the specified 
NDFD.  MaxRelError is the maximum relative error that will be 
allowed when determining the cut points for applying the rounding 
rules.

Function DecimalRound
   (Value: extended;     {Input value to be rounded.}
    NDFD: integer;       {# decimal fraction digits to in result.}
    MaxRelErr: double;   {Max relative error to assume in input value.}
    Ctrl: tDecimalRoundingCtrl = drHalfEven)  {Rounding rule}
    : extended;

{ The following functions have a two times "epsilon" error built 
  in for the single, double, and extended argument respectively: }

Function DecimalRoundSgl (Value: single; NDFD: integer;
                Ctrl: tDecimalRoundingCtrl = drHalfEven): extended;

Function DecimalRoundDbl (Value: double; NDFD: integer;
                Ctrl: tDecimalRoundingCtrl = drHalfEven): extended;

Function DecimalRoundExt (Value: extended; NDFD: integer;
                Ctrl: tDecimalRoundingCtrl = drHalfEven): extended;

More Reading:
Report No: 8070            Status: Closed
  RoundTo and SimpleRoundTo are very sick
  http://qc.embarcadero.com/wc/qcmain.aspx?d=8070
Report No: 8143            Status: Closed
  Replace RoundTo and SimpleRoundTo
  http://qc.embarcadero.com/wc/qcmain.aspx?d=8143
Report No: 8399            Status: Open
  System initialization differences are allowed to affect 
      FPU Control Word
  http://qc.embarcadero.com/wc/qcmain.aspx?d=8399
Report No: 28022            Status: Open
  Add Fixed and Floating Decimal Point Numbers to Delphi
  http://qc.embarcadero.com/wc/qcmain.aspx?d=28022
Report No: 50577            Status: Open
  Add FloatToHex and HexToFloat functions to RTL
  http://qc.embarcadero.com/wc/qcmain.aspx?d=50577
Report No: 67248            Status: Open
  Add a better date-time variable type
  http://qc.embarcadero.com/wc/qcmain.aspx?d=67248
Report No: 78256            Status: Open
  IsNAN returns wrong result and IsInfinite causes exception.
  http://qc.embarcadero.com/wc/qcmain.aspx?d=78256
Report No: 79687            Status: Open
  RoundTo gives wrong results
  http://qc.embarcadero.com/wc/qcmain.aspx?d=79687
Also Google for decimal "hidden-value problem"
-.-
0
John
4/5/2012 12:09:58 PM
John Herbster a formulé la demande :
> "Pierre Yager" <pierre.yager@crisalid.com> wrote
>> ... [spent] whole day of yesterday to find rounding problems ...
>
> Pierre,  

> If you must use floating binary-point variable types like single, 
> double, or extended for holding decimal fraction numbers, then 
> you really should be using something like DecimalRounding_JH1, 
> which is available from 
>   http://cc.embarcadero.com/Item/21909
> to do your decimal rounding.   DecimalRounding_JH1 will do the 
> following types of rounding.

John,

I gave a look a your DecimalRounding unit. It looks like you spent 
countless hours on the floating point numbers problem.

What is the state of this problem in XE2 (Update 4) ? Looks like most 
of your reports are still not closed, several years after.

The most complex computations I have to do is to compute VAT and 
compound discounts on several amounts. I made my best to use the 
Currency data type everywhere but I think the Delphi compiler silently 
convert intermediate results to Extended and back to Currency which may 
cause rounding errors from time to time.

Can I rely on Math.SimpleRoundTo() method to get intermediate results 
back to Currency data types or should I use your DecimalRounding 
methods ?

-- 
Pierre
0
Pierre
4/5/2012 1:21:05 PM
Pierre Yager wrote:

> Rudy Velthuis (TeamB) avait prétendu :
> > Jeff Overcash wrote:
> > 
> >> Neil Huhta wrote:
> >>> Hello All:
> >>> 
> >>>     I need to get currency numbers to properly round - I tried 
> >>> x:=round(Y*100)/100; but that does not consistently round in the
> >>> traditional US manner of .5 to the next 1.
> >>> 
> >> 
> >> That is not proper rounding.  The proper rounding method is if it
> is >> .5 then you round to the nearest even number.  Delphi does
> proper >> rounding (often referred to as Bankers rounding since it
> introduces >> less error over a large random distribution of numbers).
> > 
> > By default, Delphi does use banker's rounding (round to nearest
> > even) indeed, but that is not necessarily "proper rounding". There
> > are several ways to round, and which one is "proper" depends on the
> > situation. You can tell the FPU which one you want to use.
> 
> I spend yhe whole day of yesterday to find rounding problems in my 
> application :
> 
> The FPU has no support for Round up 0.5 to next 1. You can round
> always up, always down, simply truncate or round to next half or even
> but you cannot round 0.5 to next 1.
> 
> The embedded way to do this using Delphi is to use
> 
> X := Math.SimpleRoundTo(Y)
> 
> Beware of Math.RoundTo because it uses FPU rounding.
> 
> Neil, X := Round(Y*100)/100 is not good because Round uses FPU
> rounding and Y is converted to Extended, so the Result is an Extended
> and if X is a Currency, the conversion is done by the FPU. The other
> caveat of your method is that it don't work for negative numbers.
> 
> SimpleRoundTo uses the same algorithm but do things in order to avoid 
> using Round.
> 
> You can round currencies 0.5 to next 1 using this function that don't 
> uses Extended or any conversion (and it works for negative numbers
> too) :
> 
> { Idea come from Synopse }
> function RoundCurrency(const Value: Currency): Currency;
> var
>   V64: Int64 absolute Result;

Ouch! That is ugly code (as is any other code using absolute). And not
entirely correct, as Currency is scaled by 10000, not by 100.

--  
Rudy Velthuis [TeamB]        http://rvelthuis.de

"If you haven't got anything nice to say about anybody, come sit 
 next to me." -- Alice Roosevelt Longworth (1884-1980)
0
Rudy
4/5/2012 2:11:53 PM
> Ouch! That is ugly code (as is any other code using absolute). And not
> entirely correct, as Currency is scaled by 10000, not by 100.

I want to round my currencies to 2 decimals...

-- 
Pierre
0
Pierre
4/5/2012 2:28:05 PM
Pierre Yager avait écrit le 05/04/2012 :
>> Ouch! That is ugly code (as is any other code using absolute). And not
>> entirely correct, as Currency is scaled by 10000, not by 100.
>
> I want to round my currencies to 2 decimals...

About the use of absolute... you know that

type
  TUnionRecord = record
  case Boolean of
    False: (L: Word; H: Word);
    True:  (W: Cardinal);
  end;

Is nothing more than another way to use "absolute" ?

-- 
Pierre
0
Pierre
4/5/2012 2:32:44 PM
Pierre Yager wrote:

> Pierre Yager avait écrit le 05/04/2012 :
> >> Ouch! That is ugly code (as is any other code using absolute). And
> not >> entirely correct, as Currency is scaled by 10000, not by 100.
> > 
> > I want to round my currencies to 2 decimals...
> 
> About the use of absolute... you know that
> 
> type
>   TUnionRecord = record
>   case Boolean of
>     False: (L: Word; H: Word);
>     True:  (W: Cardinal);
>   end;
> 
> Is nothing more than another way to use "absolute" ?

No, it isn't. It does some kind of type checking, and the record must
be packed, BTW. Absolute is the worst you can use.

-- 
"Mr. Madison, what you've just said is one of the most insanely 
 idiotic things I have ever heard. At no point in your rambling, 
 incoherent response were you even close to anything that could 
 be considered a rational thought. Everyone in this room is now 
 dumber for having listened to it. I award you no points, and 
 may God have mercy on your soul." -- from movie Billy Madison
0
Rudy
4/5/2012 7:11:11 PM
Pierre Yager wrote:

> John Herbster a formulé la demande :
> > "Pierre Yager" <pierre.yager@crisalid.com> wrote
> >> ... [spent] whole day of yesterday to find rounding problems ...
> > 
> > Pierre,  
> 
> > If you must use floating binary-point variable types like single, 
> > double, or extended for holding decimal fraction numbers, then 
> > you really should be using something like DecimalRounding_JH1, 
> > which is available from 
> >   http://cc.embarcadero.com/Item/21909
> > to do your decimal rounding.   DecimalRounding_JH1 will do the 
> > following types of rounding.
> 
> John,
> 
> I gave a look a your DecimalRounding unit. It looks like you spent 
> countless hours on the floating point numbers problem.
> 
> What is the state of this problem in XE2 (Update 4) ? Looks like most 
> of your reports are still not closed, several years after.
> 
> The most complex computations I have to do is to compute VAT and 
> compound discounts on several amounts. I made my best to use the 
> Currency data type everywhere but I think the Delphi compiler
> silently convert intermediate results to Extended and back

Then use my Decimal type:

  http://rvelthuis.de/programs/decimals.html

It may be a little slow (no FPU support), but it is very accurate in
the defined range. You can choose the number of decimals.


-- 
"You can know the name of a bird in all the languages of the 
 world, but when you're finished, you'll know absolutely nothing
 whatever about the bird... So let's look at the bird and see
 what it's doing -- that's what counts. I learned very early 
 the difference between knowing the name of something and knowing
 something." -- Richard Feynman
0
Rudy
4/5/2012 7:16:42 PM
Tom Brunberg wrote:

> Neil Huhta wrote:
> 
> > Hello All:
> > 
> >  I need to get currency numbers to properly round - I tried
> > x:=round(Y*100)/100; but that does not consistently round in the
> > traditional US manner of .5 to the next 1.
> 
> Neil,
> 
> Look at SimpleRoundTo (in the maths unit) or maybe this would do:
> {code}
> result := trunc(NumToRound * 100 + 0.5) / 100
> {code}
> assuming you want to round to the nearest cent.

That probably mixes floating point with Currencym which is not
necessarily a good idea. I would do:

{code}
  Result := Trunc(NumToRound * Currency(100) + Currency(0.5)) /
Currency(100);
{code}

But that only works for positive values of NumToRound.
-- 
Rudy Velthuis

"Knowing others is intelligence; knowing yourself is true
 wisdom. Mastering others is strength; mastering yourself is
 true power."
 -- Lao Tzu
0
Rudy
4/5/2012 7:47:07 PM
>> you really should be using something like DecimalRounding_JH1, 
>> which is available from 
>>   http://cc.embarcadero.com/Item/21909

> What is the state of this problem in XE2 (Update 4)?

Pierre,

I do not know.  
But I doubt that there is much improvement in numeric processing.

> Looks like most of your reports are still not closed.

True.  But, I am not a mainstream programmer.
 
> ... Currency type ... I think the Delphi compiler silently converts
> intermediate results to Extended and back to Currency.

I suspect so.  Addition and subtraction may be exceptions.

> which may cause rounding errors from time to time.

These rounding problems usually occur because the ordinary
programmer cannot easily know the exact numbers that he is 
dealing with.  

For example, consider a test of x := round(x*100)/100 rounding: 
  procedure TForm1.Button1Click(Sender: TObject);
  {sub}Procedure Display(aLabel: string; e: extended);
    var s: string;
    begin
      s := ExactFloatToStrEx(e);
      Memo1.Lines.Add(aLabel + ' = ' + s);
    end;
  var e1, e2, e3: extended; d1, d2, d3: double; s: string;
  begin
  { Test Extended: }
    e1 := StrToFloat(Edit1.Text);
    Display('e1',e1);
    e2 := e1*100;
    Display('e2',e2);
    e3 := round(e2)/100;
    Display('e3',e3);
  { Test Double: }
    d1 := e1;
    Display('d1',d1);
    d2 := 100*d1;
    Display('d2',d2);
    d3 := round(d2)/100;
    Display('d3',d3);
  end;

With an input of 0.115, the results e3 and d3 look kind of normal:
e1 = + 0.01499 99999 99999 99999 96950 68138 98845 18779 35403 
         89975 53288 93661 49902 34375
e2 = + 1.5
e3 = + 0.01999 99999 99999 99999 95934 24185 31793 58372 47205 
         19967 37718 58215 33203 125
d1 = + 0.01499 99999 99999 99944 48884 87687 42172 97881 84165 
         95458 98437 5
d2 = + 1.5
d3 = + 0.02000 00000 00000 00041 63336 34234 43370 26588 61875 
           53405 76171 875

With an input of 0.295 their is about a 0.01 difference between 
the extended (e3) and double (d3):
e1 = + 0.29499 99999 99999 99998 80737 76102 65945 12259 18019 
         19043 06411 74316 40625
e2 = + 29.49999 99999 99999 99826 52765 24023 19290 55880 75518 
          60809 32617 1875
e3 = + 0.28999 99999 99999 99999 24105 84792 60146 89619 47830 
         39391 04080 20019 53125
d1 = + 0.29499 99999 99999 98445 68776 55247 80843 40691 56646 
         72851 5625
d2 = + 29.5
d3 = + 0.29999 99999 99999 98889 77697 53748 43459 57636 83319 
         09179 6875

> Can I rely on Math.SimpleRoundTo() method to get intermediate 
> results back to Currency data types or should I use your 
> DecimalRounding methods?

I do not recommend SimpleRoundTo.  

DecimalRounding_JH1 has a lot of experience and no known problems.
However, I do recognize that it is not the only way to solve the 
problems with using floating binary-point variables for representing
decimal fraction numbers.  I have been working on another method 
myself.

For future reading, you might also like to investigate Microsoft's 
VAR_DECIMAL and IEEE 854 standards.  -- and of course Rudy's
decimal number object.

Rgds, JohnH
0
John
4/5/2012 8:42:08 PM
Apologies for hi-jacking this thread but Rudy's comment has raised my
interest.

I have seen "absolute" being used around but have never used it myself,
as I do not understand it - could be a good thing ;-)


Rudy Velthuis (TeamB) wrote:

>No, it isn't. It does some kind of type checking, and the record must
>be packed, BTW. Absolute is the worst you can use.

Are you saying that a programmer should avoid using the "absolute"
keyword? If so, why? What is so bad in using it?

Cheers,
Nick


-- 
Nicholas Ring

6/04/2012 12:43:32 PM

XanaNews Version 1.19.1.347  [Portable ISpell]
0
Nicholas
4/6/2012 2:52:45 AM
Rudy Velthuis (TeamB) wrote:

> Tom Brunberg wrote:
> > Look at SimpleRoundTo (in the maths unit) or maybe this would do:
> > {code}
> > result := trunc(NumToRound * 100 + 0.5) / 100
> > {code}
> > assuming you want to round to the nearest cent.
> 
> That probably mixes floating point with Currencym which is not
> necessarily a good idea. I would do:

Well, how do you avoid using floating point in any non-trivial monetary calculations?

> {code}
>   Result := Trunc(NumToRound * Currency(100) + Currency(0.5)) / Currency(100);
> {code}

Except it doesn't compile (E2089 Invalid typaecast).

> But that only works for positive values of NumToRound.

Indeed, and the fix is easy:

{code:delphi}
function RoundAssymetricToCents(NumToRound: currency): currency;
var
  negate: integer;
begin
  if NumToRound < 0 then negate := -1 else negate := 1;
  Result := Trunc(NumToRound * 100 + negate * 0.5) / 100;
end;
{code}

Cheers
Tom

-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/6/2012 9:33:12 AM
"Tom Brunberg" <nospam@to.me> wrote

> ... how do you avoid using floating point in
> any non-trivial monetary calculations? ...

Tom, 

A few programmers from the accounting side of the business 
prefer to do storage and calculations of money values using 
the smallest unit (e.g. cents or pennies) in integer form.

Rgds, JohnH
0
John
4/6/2012 11:34:00 AM
"Nicholas Ring" wrote
>
> Are you saying that a programmer should avoid using the "absolute"
> keyword? If so, why? What is so bad in using it?

absolute instructs the compiler to define a new variable at the same address 
as another that already exists.

For example

var
  mcf : TCustomForm absolute form1;

Absolute, as a directive, completely bypasses all typechecking--basically 
you're telling the compiler to shut up and just do it. Obviously, such an 
approach has some perils.

While the above would work (a TForm is a TCustomForm), that also means that 
the absolute approach isn't necessary--you could also have written

var
  mcf : TCustomForm;
begin
  mcf := form1;

or just use form1 directly with any method expecting a TCustomForm and been 
just fine. You'd be better off with the latter approach, in fact, because 
you're not defeating Delphi's strong typing rules. Lying to or coercing a 
compiler is generally a bad thing.

There are particular, very specialized, circumstances where absolute can be 
a shortcut--for example, coercing one record type to aonther because you 
know the field(s) of interest to be at the same offset.

But as mentioned, you're paying a steep price in safety to do this. and the 
need to do it might be considered a code smell.

bobD
0
Robert
4/6/2012 12:00:03 PM
Nicholas Ring wrote:

> Apologies for hi-jacking this thread but Rudy's comment has raised my
> interest.
> 
> I have seen "absolute" being used around but have never used it
> myself, as I do not understand it - could be a good thing ;-)

No, it is the worst feature Delphi offers. Forget about it.

-- 
"They never open their mouths without subtracting from the 
 sum of human knowledge." -- Thomas Brackett Reed
0
Rudy
4/6/2012 4:50:28 PM
Tom Brunberg wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Tom Brunberg wrote:
> > > Look at SimpleRoundTo (in the maths unit) or maybe this would do:
> > > {code}
> > > result := trunc(NumToRound * 100 + 0.5) / 100
> > > {code}
> > > assuming you want to round to the nearest cent.
> > 
> > That probably mixes floating point with Currencym which is not
> > necessarily a good idea. I would do:
> 
> Well, how do you avoid using floating point in any non-trivial
> monetary calculations?

By using my Decimal type. Or by using Currency exclusively.

-- 
"I don't want to achieve immortality through my work; I want to 
 achieve immortality through not dying."
 -- Woody Allen (1935-)
0
Rudy
4/6/2012 4:51:43 PM
John Herbster wrote:

> "Tom Brunberg" <nospam@to.me> wrote
> 
> > ... how do you avoid using floating point in
> > any non-trivial monetary calculations? ...
> 
> Tom, 
> 
> A few programmers from the accounting side of the business 
> prefer to do storage and calculations of money values using 
> the smallest unit (e.g. cents or pennies) in integer form.

What about percentages?


-- 
"Where it is a duty to worship the sun, it is pretty sure to be
 a crime to examine the laws of heat."
 -- John Morley
0
Rudy
4/6/2012 4:52:17 PM
Rudy Velthuis (TeamB) wrote:

> Tom Brunberg wrote:
> > Well, how do you avoid using floating point in any non-trivial
> > monetary calculations?
> 
> Or by using Currency exclusively.

Doesn't avoid floats at all.

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/6/2012 5:30:17 PM
John Herbster wrote:

> "Tom Brunberg" <nospam@to.me> wrote
> 
> > ... how do you avoid using floating point in
> > any non-trivial monetary calculations? ...
> 
> Tom, 
> 
> A few programmers from the accounting side of the business 
> prefer to do storage and calculations of money values using 
> the smallest unit (e.g. cents or pennies) in integer form.

John, I understand that. After all, accounts are always recorded to the cent.

Mind you that i commented on Rudys statement:
> That probably mixes floating point with Currencym which is not
> necessarily a good idea.
But the Delphi currency type uses the fpu internally even for simple additions so you can't avoid
floats by using the Currency type.

Cheers
Tom

-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/6/2012 5:40:23 PM
"Rudy Velthuis (TeamB)" wrote
>
> No, it is the worst feature Delphi offers. Forget about it.

Why is it worse than any other unchecked hard cast--since that's basically 
what it is?


bobD
0
Robert
4/7/2012 1:24:52 AM
>> A few programmers from the accounting side of the business 
>> prefer to do storage and calculations of money values using 
>> the smallest unit (e.g. cents or pennies) in integer form.

"Rudy Velthuis (TeamB)" <newsgroups@rvelthuis.de> wrote
> What about percentages?

Rudy,
It depends on what you want to do with them.  If you are thinking 
of computing sales taxes, the state will tell you how to use them 
and how to they want the penny rounding done.
Rgds, JohnH
0
John
4/7/2012 1:34:32 AM
>> > ... how do you avoid using floating point in
>> > any non-trivial monetary calculations? ...

>> A few programmers from the accounting side of the business 
>> prefer to do storage and calculations of money values using 
>> the smallest unit (e.g. cents or pennies) in integer form.
 

"Tom Brunberg" <nospam@to.me> wrote 
> John, I understand that. After all, accounts are always 
> recorded to the cent.  ... 
> But the Delphi currency type uses the fpu internally even
> for simple additions so you can't avoid floats by using the
> currency type.

Tom,  
But, the conversions from currency to float and then add will 
then fix the representation errors during the conversion back 
to currency and give the exact correct sum.
Rgds, JohnH
0
John
4/7/2012 1:42:52 AM
John Herbster wrote:

> >> > ... how do you avoid using floating point in
> >> > any non-trivial monetary calculations? ...
> 
> >> A few programmers from the accounting side of the business 
> >> prefer to do storage and calculations of money values using 
> >> the smallest unit (e.g. cents or pennies) in integer form.
>  
> 
> "Tom Brunberg" <nospam@to.me> wrote 
> > John, I understand that. After all, accounts are always 
> > recorded to the cent.  ... 
> > But the Delphi currency type uses the fpu internally even
> > for simple additions so you can't avoid floats by using the
> > currency type.
> 
> Tom,  
> But, the conversions from currency to float and then add will 
> then fix the representation errors during the conversion back 
> to currency and give the exact correct sum.
> Rgds, JohnH

If you say so. After all, you have the best knowledge.

Cheers
Tom

-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/7/2012 6:31:56 AM
Rudy Velthuis (TeamB) wrote:

> John Herbster wrote:
> 
> > "Tom Brunberg" <nospam@to.me> wrote
> > 
> > > ... how do you avoid using floating point in
> > > any non-trivial monetary calculations? ...
> > 
> > Tom, 
> > 
> > A few programmers from the accounting side of the business 
> > prefer to do storage and calculations of money values using 
> > the smallest unit (e.g. cents or pennies) in integer form.
> 
> What about percentages?

The fractions go to the bank, of course. ;-)

-- 
Peter Below (TeamB)  
Don't be a vampire (http://slash7.com/pages/vampires), 
use the newsgroup archives :
http://codenewsfast.com
http://groups.google.com
0
Peter
4/7/2012 8:55:59 AM
"Robert Dawson" <bd@hillfort.com> wrote in message 
news:458759@forums.embarcadero.com...
> "Rudy Velthuis (TeamB)" wrote
>>
>> No, it is the worst feature Delphi offers. Forget about it.
>
> Why is it worse than any other unchecked hard cast--since that's basically 
> what it is?


Cuz Rudy says so.

-- 
Wayne Niddery (TeamB)
"'Thank you, Occupy Wall Street. With your vivid example of anticapitalist 
squalor, I've been able to convince all three of my children to become 
investment bankers"  - P. J. O’Rourke
0
Wayne
4/7/2012 12:14:01 PM
"Nicholas Ring" <nring.NOSPAM@southcom.com.au> wrote in message 
news:458570@forums.embarcadero.com...
>
> I have seen "absolute" being used around but have never used it myself,
> as I do not understand it - could be a good thing ;-)


It's actually very simple. It's a method of interpreting data in a different 
form than it is declared. In this sense it is similar to a hard cast, or to 
a variant record definition. It is no worse than either and has its uses 
just as those do. As such it also means it can be abused and can potentially 
get you into trouble, but of couse so can *many* features of *any* 
programming language - it is up to the programmer to understand a feature 
when using it.

For example, say you have some array data that, depending on some condition, 
needs to be treated as bytes or words. You could declare variables for it 
like this:

var
  bvals: array [0..7] of byte;
  wvals: array [0..3] of word absolute bvals;

Both bvals and wvals define the *same memory space*. Assigning data to one 
assigns it to both, but you have access to it as both bytes and words 
without manually having to cast or extract it in one or the other form. So 
if you assign bvals with the values
    01, 02, 03, 04, 05, 06, 07, 08
then wvals will have the values
    0102, 0304, 0506, 0708
and vice-versa

The exact same thing could be done by defining a variant record, but if you 
need nothing else in that record then there's not much point over the much 
simpler, and perfectly clear, declarations above.

type
    TMyVals = record
        case integer of
            0:  bvals: array [0..7] of byte;
            1: wvals: array [0..3] of word;
        end;

var
    myvals: TMYVals;

Another example of where it can be used: OnClick events pass the sender as a 
simple TObject. If you need to actually do anything with sender you 
invariably need to cast it to what it really is. So for example

procedure ButtonOnClick(Sender: TObject);
begin
    TButton(Sender).Caption := "New Caption';
end;

procedure ButtonOnClick(Sender: TObject);
var
    button: TButton absolute Sender;
begin
    button.Caption := "New Caption';
end;

Now in this case there is no advantage if there is only 1 or a few lines of 
code. But if there is more code involved that will repeatedly refer to the 
sender parameter, then absolute is a reasonable choice.

In *both* cases, one has to be aware of whether Sender really is always a 
button in this example since this same event (TNotifyEvent type) can be 
assigned to various events of *many* different controls. If that is possible 
in your case then of course one needs to check, e.g.

    if sender is TButton then ...

But in that case, absolute can still be perfectly good to use:

var
    button: TButton absolute Sender;
    listbox: TListbox absolute Sender;
begin
    if sender is TButton then
      button.Caption := "New Caption'
    else if sender is TListBox then
      listbox.Text := 'New Entry';
end;

Obviously the above is a contrived example, but the point is there is 
nothing "evil" or illegitimate about using absolute any more than any other 
language feature. In fact it is far less dangerous than using With, but I 
would never tell others that With should be removed from the language or in 
any way outlawed, only that they need to take great care due to possible 
scoping issues that can create hard to identify bugs. There are no such 
scoping issues with absolute, it is clear what it is doing and the chances 
of someone using it where it makes no sense and thus getting weird errors is 
in fact *extremely* low (unlike With which has been the cause of *many* 
errors).

-- 
Wayne Niddery (TeamB)
"'Thank you, Occupy Wall Street. With your vivid example of anticapitalist 
squalor, I've been able to convince all three of my children to become 
investment bankers"  - P. J. O’Rourke
0
Wayne
4/7/2012 12:57:27 PM
>> > > ... how do you avoid using floating point in
>> > > any non-trivial monetary calculations? ...

>> > A few programmers from the accounting side of the business
>> > prefer to do storage and calculations of money values using
>> > the smallest unit (e.g. cents or pennies) in integer form.

>> What about percentages?

"Peter Below" <none@nomail.please> wrote
> The fractions go to the bank, of course. ;-)

See "salami slicing" or "penny shaving" or "penny rounding fraud"
http://en.wikipedia.org/wiki/Salami_slicing
http://news.softpedia.com/news/E-Trade-Salami-Slice-Fraudster-Sentenced-to-Jail-122150.shtml

I first heard of this fraud while at Purdue University before 1972; but,
I cannot find any historical reference for that case.

--JohnH.
0
John
4/7/2012 1:30:00 PM
Robert Dawson wrote:

> "Rudy Velthuis (TeamB)" wrote
> > 
> > No, it is the worst feature Delphi offers. Forget about it.
> 
> Why is it worse than any other unchecked hard cast--since that's
> basically what it is?

Because hard casts have some minor checks, while this has absolutely
nothing of that kind.

-- 
"Getting an education was a bit like a communicable sexual disease. 
 It made you unsuitable for a lot of jobs and then you had the urge
 to pass it on." -- Terry Pratchett, Hogfather
0
Rudy
4/7/2012 4:07:02 PM
Wayne Niddery wrote:

> "Robert Dawson" <bd@hillfort.com> wrote in message 
> news:458759@forums.embarcadero.com...
> > "Rudy Velthuis (TeamB)" wrote
> > > 
> >> No, it is the worst feature Delphi offers. Forget about it.
> > 
> > Why is it worse than any other unchecked hard cast--since that's
> > basically what it is?
> 
> Cuz Rudy says so.

Well, Rudy says what Rudy thinks. What else?

-- 
Gumperson's Law: The probability of a given event occurring is 
inversely proportional to its desirability.
0
Rudy
4/7/2012 4:07:30 PM
John Herbster wrote:

> >> A few programmers from the accounting side of the business 
> >> prefer to do storage and calculations of money values using 
> >> the smallest unit (e.g. cents or pennies) in integer form.
> 
> "Rudy Velthuis (TeamB)" <newsgroups@rvelthuis.de> wrote
> > What about percentages?
> 
> Rudy,
> It depends on what you want to do with them.  If you are thinking 
> of computing sales taxes, the state will tell you how to use them 
> and how to they want the penny rounding done.
> Rgds, JohnH

Indeed. Most software here wants the cents to be rounded before any
further calculations are done.

-- 
"The first clergyman was the first rascal who met the first
 fool."
 -- Voltaire
0
Rudy
4/7/2012 4:09:20 PM
Peter Below wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > John Herbster wrote:
> > 
> > > "Tom Brunberg" <nospam@to.me> wrote
> > > 
> > > > ... how do you avoid using floating point in
> > > > any non-trivial monetary calculations? ...
> > > 
> > > Tom, 
> > > 
> > > A few programmers from the accounting side of the business 
> > > prefer to do storage and calculations of money values using 
> > > the smallest unit (e.g. cents or pennies) in integer form.
> > 
> > What about percentages?
> 
> The fractions go to the bank, of course. ;-)

That explains why they call it banker's rounding. <g>


-- 
"If you give a man a fish, he will eat for today. If you teach 
 him to fish, he'll understand why some people think golf is 
 exciting." -- P.G. Wodehouse
0
Rudy
4/7/2012 4:09:59 PM
Tom Brunberg wrote:

> Mind you that i commented on Rudys statement:
> > That probably mixes floating point with Currencym which is not
> > necessarily a good idea.
> But the Delphi currency type uses the fpu internally

Yes, but it does not use the floating point types. Currency is a fixed
point type, and Delphi (traditionally) uses the FPU for the 64 bit
*integer* calculations required.

-- 
"Outside of the killings, Washington has one of the lowest
 crime rates in the country."
 -- Marion Barry, former mayor Washington D.C.
0
Rudy
4/7/2012 4:12:32 PM
Tom Brunberg wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Tom Brunberg wrote:
> > > Well, how do you avoid using floating point in any non-trivial
> > > monetary calculations?
> > 
> > Or by using Currency exclusively.
> 
> Doesn't avoid floats at all.

Yes, it does. My decimal type certainly does, but also using Currency
exclusively. Currency only uses the 64 bit integer part of the FPU and
if you use Currency exclusively, no ocnversion should take place.

-- 
"The keenest sorrow is to recognize ourselves as the sole cause
 of all our adversities."
 -- Sophocles
0
Rudy
4/7/2012 4:15:04 PM
"Rudy Velthuis (TeamB)" wrote
>
> Because hard casts have some minor checks,

and what would those be?

bobD
0
Robert
4/7/2012 4:18:11 PM
Robert Dawson wrote:

> "Rudy Velthuis (TeamB)" wrote
> > 
> > Because hard casts have some minor checks,
> 
> and what would those be?

Try to cast floats to integral types or vice versa. Also, while '' (the
empty string) is in fact a nil, PChar('') is not.

Ok, it is not much, but it is still not as bad as absolute.

-- 
"In matters of conscience, the law of majority has no place."
 -- Mohandas Gandhi
0
Rudy
4/7/2012 4:25:25 PM
Rudy Velthuis (TeamB) wrote:

> Robert Dawson wrote:
> 
> > "Rudy Velthuis (TeamB)" wrote
> > > 
> > > Because hard casts have some minor checks,
> > 
> > and what would those be?
> 
> Try to cast floats to integral types or vice versa. Also, while ''
> (the empty string) is in fact a nil, PChar('') is not. 

FWIW, string casts between AnsiString and UnicodeString will even
perform a conversion.
-- 
"The religion of the future will be a cosmic religion, the
 religion which based on experience, which refuses dogma."
 -- Albert Einstein
0
Rudy
4/7/2012 4:31:34 PM
On Sat, 07 Apr 2012 09:15:04 -0700, Rudy Velthuis (TeamB) wrote:

> Tom Brunberg wrote:
<trim>
>> Doesn't avoid floats at all.
> 
> Yes, it does. My decimal type certainly does, but also using Currency
> exclusively. Currency only uses the 64 bit integer part of the FPU and
> if you use Currency exclusively, no ocnversion should take place.

"When floating-point, integer, or packed BCD integer values are loaded 
from memory into any of the x87 FPU data registers, the values are 
automatically converted into double extended-precision floating-point 
format (if they are not already in that format)." (Intel® 64 and IA-32 
Architectures Software Developer’s Manual, 8.1.2., p8-2, Vol. 1 
http://download.intel.com/products/processor/manual/253665.pdf) See also 
section 8.3.3.

Chris
0
Christopher
4/7/2012 5:59:39 PM
On Sat, 07 Apr 2012 09:12:32 -0700, Rudy Velthuis (TeamB) wrote:

> Tom Brunberg wrote:
> 
>> Mind you that i commented on Rudys statement:
>> > That probably mixes floating point with Currencym which is not
>> > necessarily a good idea.
>> But the Delphi currency type uses the fpu internally
> 
> Yes, but it does not use the floating point types. Currency is a fixed
> point type, and Delphi (traditionally) uses the FPU for the 64 bit
> *integer* calculations required.

Please see my response in the thread above.

Chris
0
Christopher
4/7/2012 6:04:29 PM
Christopher Cheney wrote:

> On Sat, 07 Apr 2012 09:12:32 -0700, Rudy Velthuis (TeamB) wrote:
> 
> > Tom Brunberg wrote:
> > 
> >> Mind you that i commented on Rudys statement:
> >> > That probably mixes floating point with Currencym which is not
> >> > necessarily a good idea.
> >> But the Delphi currency type uses the fpu internally
> > 
> > Yes, but it does not use the floating point types. Currency is a
> > fixed point type, and Delphi (traditionally) uses the FPU for the
> > 64 bit integer calculations required.
> 
> Please see my response in the thread above.

In my case, that is below. <g>

-- 
"Do not mind anything that anyone tells you about anyone else.
 Judge everyone and everything for yourself."
 -- Henry James
0
Rudy
4/7/2012 7:58:01 PM
Christopher Cheney wrote:

> On Sat, 07 Apr 2012 09:15:04 -0700, Rudy Velthuis (TeamB) wrote:
> 
> > Tom Brunberg wrote:
> <trim>
> >> Doesn't avoid floats at all.
> > 
> > Yes, it does. My decimal type certainly does, but also using
> > Currency exclusively. Currency only uses the 64 bit integer part of
> > the FPU and if you use Currency exclusively, no ocnversion should
> > take place.
> 
> "When floating-point, integer, or packed BCD integer values are
> loaded from memory into any of the x87 FPU data registers, the values
> are automatically converted into double extended-precision
> floating-point format (if they are not already in that format)."
> (Intel® 64 and IA-32 Architectures Software Developer’s Manual,
> 8.1.2., p8-2, Vol. 1
> http://download.intel.com/products/processor/manual/253665.pdf) See
> also section 8.3.3.

Oh, internal conversion is totally unimportant. There is no external
conversion. The calculation is entirely done as integers, so there is
no rounding error.


-- 
"The truth does not change according to our ability to stomach
 it." -- Flannery O'Connor
0
Rudy
4/7/2012 8:00:09 PM
On Sat, 07 Apr 2012 13:00:09 -0700, Rudy Velthuis (TeamB) wrote:

> Oh, internal conversion is totally unimportant. There is no external
> conversion. The calculation is entirely done as integers, so there is no
> rounding error.

Since we are now clearly talking about different things and have 
different ideas about relevance, there is little point in continuing.

However, I totally agree with your comments on "proper" rounding.

Chris
0
Christopher
4/8/2012 8:09:53 AM
I would like to thank everyone for their insightful comments - you have 
really helped me get a great understanding of this issue.


Neil Huhta




<Sion Jones> wrote in message news:458136@forums.embarcadero.com...
>> {quote:title=Neil Huhta wrote:}{quote}
>> Hello All:
>>
>>     I need to get currency numbers to properly round - I tried
>> x:=round(Y*100)/100; but that does not consistently round in the 
>> traditional
>> US manner of .5 to the next 1.
>>
>>     I wrote the following function to accomplish this:
>>
>>
>>
>>     class function  TCommonPM.PRound(NumToRound: Currency): Currency;
>> Var Subtotal: Currency;
>>     Sub2: Integer;
>> begin
>>   Result:=NumToRound;
>>   Subtotal:=NumToRound*100;
>>   Sub2:=Trunc(Subtotal);
>>   If Subtotal-Sub2>=0.50 Then
>>     Sub2:=Sub2+1;
>>   Result:=Sub2/100;
>> end;
>>
>>
>>
>>    Is there a better way to do this ??? Should it be done in assembler 
>> ??? I
>> noticed that the code in system for round is in assembler.
>>
>> procedure       _ROUND;
>> asm
>>         { ->    FST(0)  Extended argument       }
>>         { <-    EDX:EAX Result                  }
>>
>>         SUB     ESP,8
>>         FISTP   qword ptr [ESP]
>>         FWAIT
>>         POP     EAX
>>         POP     EDX
>> end;
>>
>> Thank you
>>
>> Neil Huhta
>
> I've done the same for some currency items I wanted to round according to 
> rules given in a spec document i.e. >=0.50 is +1. Pence in this case.
>
> Would you gain by using assembler instead of what you've written?
>
> Personally, I don't think that either me or my users would ever benefit 
> from the microscopic amounts of time I'll have saved.
0
Neil
4/9/2012 3:20:06 AM
Wayne Niddery wrote:

> "Nicholas Ring" <nring.NOSPAM@southcom.com.au> wrote in message 
> news:458570@forums.embarcadero.com...
> > 
> > I have seen "absolute" being used around but have never used it
> > myself, as I do not understand it - could be a good thing ;-)
> 
> 
> It's actually very simple. It's a method of interpreting data in a
> different form than it is declared. In this sense it is similar to a
> hard cast, or to a variant record definition. It is no worse than
> either and has its uses just as those do.

I disagree. It is definitely worse than both. Variant records don't
allow managed types like strings, interfaces or dynamic arrays for
obvious reasons. Hard casts have some intelligence (e.g. if you cast a
float, or if you cast a string type, or your own type with implicit or
explicit operators, or if you cast an empty string to PChar), while
absolute has absolutely none whatsoever.

Absolute should, IMO, be completely avoided.

-- 
Rudy Velthuis

"1001 words say more than one picture" -- Chinese proverb
0
Rudy
4/9/2012 9:27:33 PM
Christopher Cheney wrote:

> On Sat, 07 Apr 2012 13:00:09 -0700, Rudy Velthuis (TeamB) wrote:
> 
> > Oh, internal conversion is totally unimportant. There is no external
> > conversion. The calculation is entirely done as integers, so there
> > is no rounding error.
> 
> Since we are now clearly talking about different things and have 
> different ideas about relevance, there is little point in continuing.

No, we are not. We were talking about floating point conversion back
and forth done by the runtime. That does not happen, unless one of the
parts of the expression is indeed a floating point type. What happens
internally, in the FPU, does not matter, as it does not change the
results.

-- 
Rudy Velthuis

"Our government has kept us in a perpetual state of fear, kept
 us in a continuous stampede of patriotic fervor, with the cry
 of grave national emergency. Always there has been some
 terrible evil at home or some monstrous foreign power that was
 going to gobble us up if we did not blindly rally behind it."
 -- General Douglas MacArthur
0
Rudy
4/9/2012 9:30:02 PM
Rudy Velthuis (TeamB) wrote:

> Wayne Niddery wrote:
> 
> > "Nicholas Ring" <nring.NOSPAM@southcom.com.au> wrote in message 
> > news:458570@forums.embarcadero.com...
> > > 
> > > I have seen "absolute" being used around but have never used it
> > > myself, as I do not understand it - could be a good thing ;-)
> > 
> > 
> > It's actually very simple. It's a method of interpreting data in a
> > different form than it is declared. In this sense it is similar to a
> > hard cast, or to a variant record definition. It is no worse than
> > either and has its uses just as those do.
> 
> I disagree. It is definitely worse than both. Variant records don't
> allow managed types like strings, interfaces or dynamic arrays for
> obvious reasons. Hard casts have some intelligence (e.g. if you cast a
> float, or if you cast a string type, or your own type with implicit or
> explicit operators, or if you cast an empty string to PChar), while
> absolute has absolutely none whatsoever.
> 
> Absolute should, IMO, be completely avoided.

Absolute as demonstrated by Wayne can be useful, but use it with care
;-)

Hard casts shouldn't show any form of intelligence and it doesn't when
it comes to floats, but it currently does when it is used on string
types. One could argue that the current implementation of hard casts of
string types adds to the confusion or if it is just an easy way to
switch between string types.

-- 
Pieter

"You'll notice that Nancy Reagan never drinks water when Ronnie
 speaks." -- Robin Williams.
0
Pieter
4/10/2012 12:37:48 AM
Rudy Velthuis (TeamB) wrote:

> Variant records don't
> allow managed types like strings, interfaces or dynamic arrays for
> obvious reasons.

ISTM that the compiler is just dumb when it comes to variant records.
ie given

record
  case foo: Boolean of
    true : str: string;
    false: bar: IInterface;
  end
end

compiler should be able to finalize the record.


ain
0
Ain
4/10/2012 7:19:24 AM
Pieter Zijlstra wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Wayne Niddery wrote:
> > 
> > > "Nicholas Ring" <nring.NOSPAM@southcom.com.au> wrote in message 
> > > news:458570@forums.embarcadero.com...
> > > > 
> > > > I have seen "absolute" being used around but have never used it
> > > > myself, as I do not understand it - could be a good thing ;-)
> > > 
> > > 
> > > It's actually very simple. It's a method of interpreting data in a
> > > different form than it is declared. In this sense it is similar
> > > to a hard cast, or to a variant record definition. It is no worse
> > > than either and has its uses just as those do.
> > 
> > I disagree. It is definitely worse than both. Variant records don't
> > allow managed types like strings, interfaces or dynamic arrays for
> > obvious reasons. Hard casts have some intelligence (e.g. if you
> > cast a float, or if you cast a string type, or your own type with
> > implicit or explicit operators, or if you cast an empty string to
> > PChar), while absolute has absolutely none whatsoever.
> > 
> > Absolute should, IMO, be completely avoided.
> 
> Absolute as demonstrated by Wayne can be useful, but use it with care
> ;-)
> 
> Hard casts shouldn't show any form of intelligence 

But they do. As long as there are no other casts (like the casts in
C++), they should.



-- 
"To err is human -- and to blame it on a computer is even more 
 so." -- Robert Orben.
0
Rudy
4/10/2012 12:48:25 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Variant records don't
> > allow managed types like strings, interfaces or dynamic arrays for
> > obvious reasons.
> 
> ISTM that the compiler is just dumb when it comes to variant records.
> ie given
> 
> record
>   case foo: Boolean of
>     true : str: string;
>     false: bar: IInterface;
>   end
> end
> 
> compiler should be able to finalize the record.

How? If the memory is occupied by a string, the string RTL function to
decrement the refcount should be used. If it is occupied by an
interface, the string routine should NOT be used, but Release should be
called on te interface.

IOW, the compiler CAN'T take care of this. It can't know which of the
variant parts is valid.

-- 
"Religion is what keeps the poor from murdering the rich."
 -- Napoleon
0
Rudy
4/10/2012 12:51:16 PM
Rudy Velthuis (TeamB) wrote:

> Ain Valtin wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > Variant records don't
> > > allow managed types like strings, interfaces or dynamic arrays for
> > > obvious reasons.
> > 
> > ISTM that the compiler is just dumb when it comes to variant
> > records.  ie given
> > 
> > record
> >   case foo: Boolean of
> >     true : str: string;
> >     false: bar: IInterface;
> >   end
> > end
> > 
> > compiler should be able to finalize the record.
> 
> How? If the memory is occupied by a string, the string RTL function to
> decrement the refcount should be used. If it is occupied by an
> interface, the string routine should NOT be used, but Release should
> be called on te interface.
> 
> IOW, the compiler CAN'T take care of this. It can't know which of the
> variant parts is valid.

Yes it can - it could/should use the case tag (foo in my example) to
deside which variant part is valid and how to finalize the record.


ain
0
Ain
4/10/2012 2:39:59 PM
Ain Valtin wrote:
> Rudy Velthuis (TeamB) wrote:
>
>> Ain Valtin wrote:
>>
>>> Rudy Velthuis (TeamB) wrote:
>>>
>>>> Variant records don't
>>>> allow managed types like strings, interfaces or dynamic arrays for
>>>> obvious reasons.
>>>
>>> ISTM that the compiler is just dumb when it comes to variant
>>> records.  ie given
>>>
>>> record
>>>    case foo: Boolean of
>>>      true : str: string;
>>>      false: bar: IInterface;
>>>    end
>>> end
>>>
>>> compiler should be able to finalize the record.
>>
>> How? If the memory is occupied by a string, the string RTL function to
>> decrement the refcount should be used. If it is occupied by an
>> interface, the string routine should NOT be used, but Release should
>> be called on te interface.
>>
>> IOW, the compiler CAN'T take care of this. It can't know which of the
>> variant parts is valid.
>
> Yes it can - it could/should use the case tag (foo in my example) to
> deside which variant part is valid and how to finalize the record.

Except that, IIRC, the same record can be used in different places with 
a different "tag" meaning, while still holding the same set of bytes.
Now, when it is time to release the record, how would you know which 
finalize to call? I wouldn't, but I'd be happy to be taught how to do it.
0
Olivier
4/10/2012 2:43:37 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Ain Valtin wrote:
> > 
> > > Rudy Velthuis (TeamB) wrote:
> > > 
> > > > Variant records don't
> > > > allow managed types like strings, interfaces or dynamic arrays
> > > > for obvious reasons.
> > > 
> > > ISTM that the compiler is just dumb when it comes to variant
> > > records.  ie given
> > > 
> > > record
> > >   case foo: Boolean of
> > >     true : str: string;
> > >     false: bar: IInterface;
> > >   end
> > > end
> > > 
> > > compiler should be able to finalize the record.
> > 
> > How? If the memory is occupied by a string, the string RTL function
> > to decrement the refcount should be used. If it is occupied by an
> > interface, the string routine should NOT be used, but Release should
> > be called on te interface.
> > 
> > IOW, the compiler CAN'T take care of this. It can't know which of
> > the variant parts is valid.
> 
> Yes it can - it could/should use the case tag (foo in my example) to
> deside which variant part is valid and how to finalize the record.

That would break a lot of code. And it would make the tag required,
which is not the case right now, and which is not desired either.

-- 
"The purpose of computing is not numbers but insight." 
 -- Richard Hamming
0
Rudy
4/10/2012 3:15:09 PM
Olivier Sannier wrote:

> Ain Valtin wrote:
> > Rudy Velthuis (TeamB) wrote:
> > 
> >> Ain Valtin wrote:
> > > 
> >>> Rudy Velthuis (TeamB) wrote:
> > > > 
> >>>> Variant records don't
> >>>> allow managed types like strings, interfaces or dynamic arrays
> for >>>> obvious reasons.
> > > > 
> >>> ISTM that the compiler is just dumb when it comes to variant
> >>> records.  ie given
> > > > 
> >>> record
> >>>    case foo: Boolean of
> >>>      true : str: string;
> >>>      false: bar: IInterface;
> >>>    end
> >>> end
> > > > 
> >>> compiler should be able to finalize the record.
> > > 
> >> How? If the memory is occupied by a string, the string RTL
> function to >> decrement the refcount should be used. If it is
> occupied by an >> interface, the string routine should NOT be used,
> but Release should >> be called on te interface.
> > > 
> >> IOW, the compiler CAN'T take care of this. It can't know which of
> the >> variant parts is valid.
> > 
> > Yes it can - it could/should use the case tag (foo in my example) to
> > deside which variant part is valid and how to finalize the record.
> 
> Except that, IIRC, the same record can be used in different places
> with a different "tag" meaning, while still holding the same set of
> bytes.  Now, when it is time to release the record, how would you
> know which finalize to call? I wouldn't, but I'd be happy to be
> taught how to do it.

In old Pascal, only the part that corresponded to a certain tag was
accessible. So if the tag said the variant part was an interface, you
would not be able to store a string in str and could only access bar.

Well that is exactly what we don't want in Delphi, AFAICT.

-- 
"If you live long enough, you'll see that every victory turns 
 into a defeat." -- Simone de Beauvoir
0
Rudy
4/10/2012 3:58:35 PM
Rudy Velthuis (TeamB) wrote:

> And it would make the tag required,
> which is not the case right now, and which is not desired either.

It would make tag required only if you want to have managed types in
variant part. If you don't use tag, then the you'll get current
behaviour, ie no managed types in variant part is allowed.


ain
0
Ain
4/10/2012 5:43:37 PM
Olivier Sannier wrote:

> > Yes it can - it could/should use the case tag (foo in my example) to
> > deside which variant part is valid and how to finalize the record.
> 
> Except that, IIRC, the same record can be used in different places
> with a different "tag" meaning, while still holding the same set of
> bytes.  Now, when it is time to release the record, how would you
> know which finalize to call? I wouldn't, but I'd be happy to be
> taught how to do it.

I don't quite get what do you mean but I see no problem implementing
it... it just requires initializing the record's tag to default value
and when it is changed then execute housekeeping stuff - kind of like
compiler adds AddRef / Release for interface types behind the scene.


ain
0
Ain
4/10/2012 5:43:38 PM
"Ain Valtin" <ask@when.you.really.need.it> wrote in message 
news:459325@forums.embarcadero.com...
>>
>> IOW, the compiler CAN'T take care of this. It can't know which of the
>> variant parts is valid.
>
> Yes it can - it could/should use the case tag (foo in my example) to
> deside which variant part is valid and how to finalize the record.


Since the record can change at RUN time how can it be resolved at COMPILE 
time? It cannot. At compile time there is no tag to case.

-- 
Wayne Niddery (TeamB)
"'Thank you, Occupy Wall Street. With your vivid example of anticapitalist 
squalor, I've been able to convince all three of my children to become 
investment bankers"  - P. J. O’Rourke
0
Wayne
4/10/2012 5:49:16 PM
Wayne Niddery wrote:

> "Ain Valtin" <ask@when.you.really.need.it> wrote in message 
> news:459325@forums.embarcadero.com...
> > > 
> >> IOW, the compiler CAN'T take care of this. It can't know which of
> the >> variant parts is valid.
> > 
> > Yes it can - it could/should use the case tag (foo in my example) to
> > deside which variant part is valid and how to finalize the record.
> 
> 
> Since the record can change at RUN time how can it be resolved at
> COMPILE time? It cannot. At compile time there is no tag to case.

Compiler would emit code which finalizes the record based on the value
of the case tag.


ain
0
Ain
4/10/2012 6:02:47 PM
On Tue, 10 Apr 2012 00:19:24 -0700, Ain Valtin
<ask@when.you.really.need.it> wrote:

>Rudy Velthuis (TeamB) wrote:
>
>> Variant records don't
>> allow managed types like strings, interfaces or dynamic arrays for
>> obvious reasons.
>
>ISTM that the compiler is just dumb when it comes to variant records.
>ie given
>
>record
>  case foo: Boolean of
>    true : str: string;
>    false: bar: IInterface;
>  end
>end
>
>compiler should be able to finalize the record.

Record.Foo := false;
Record.Str := 'Text';
Record.Finalize ??????
0
Loren
4/10/2012 7:46:58 PM
On Tue, 10 Apr 2012 10:43:38 -0700, Ain Valtin
<ask@when.you.really.need.it> wrote:

>Olivier Sannier wrote:
>
>> > Yes it can - it could/should use the case tag (foo in my example) to
>> > deside which variant part is valid and how to finalize the record.
>> 
>> Except that, IIRC, the same record can be used in different places
>> with a different "tag" meaning, while still holding the same set of
>> bytes.  Now, when it is time to release the record, how would you
>> know which finalize to call? I wouldn't, but I'd be happy to be
>> taught how to do it.
>
>I don't quite get what do you mean but I see no problem implementing
>it... it just requires initializing the record's tag to default value
>and when it is changed then execute housekeeping stuff - kind of like
>compiler adds AddRef / Release for interface types behind the scene.

The reality is the compiler lets you use all the fields, it's up to
you to make sense.  In reality these days it's virtually always used
to give multiple representations of the *SAME* data.

As such, there's one case that it should handle but refuses to:

record
     case boolean of
         false:
               Salutation : String;
               Name : String;
               Addr1 : String;
               Addr2 : String;
               City : String;
         true:
               Lines : Array [1..5] of String;
End;

This doesn't compile but in reality it's safe.
0
Loren
4/10/2012 7:46:59 PM
Loren Pechtel wrote:

> > ISTM that the compiler is just dumb when it comes to variant
> > records.  ie given
> > 
> > record
> >  case foo: Boolean of
> >    true : str: string;
> >    false: bar: IInterface;
> >  end
> > end
> > 
> > compiler should be able to finalize the record.
> 
> Record.Foo := false;
> Record.Str := 'Text';
> Record.Finalize ??????

That would (probably) raise exception at runtime as the compiler
generated code would try to finalize the interface field of the variant
record.
But this is just user's mistake/bug, I don't expect compiler to catch
it. The point is that compiler can manage managed types in variant
part, the fact that user can mess it up when broking rules is nothing
new and surprising...


ain
0
Ain
4/10/2012 8:11:30 PM
Loren Pechtel wrote:

> The reality is the compiler lets you use all the fields, it's up to
> you to make sense.

Exactly. User must follow the rules, ie if s/he assigns to the tag
field some value then s/he agrees to only use that part of the variant
record that the tag field "makes available". And reading the other
variant parts of the record is still safe, it is the "write access"
which must follow the rules.



>  In reality these days it's virtually always used
> to give multiple representations of the SAME data.

Nothing would change in that respect, you could still do it.


ain
0
Ain
4/10/2012 8:11:31 PM
Rudy Velthuis (TeamB) wrote:

> > Hard casts shouldn't show any form of intelligence 
> 
> But they do. As long as there are no other casts (like the casts in
> C++), they should.

But should it still be called a hard cast? It really is more like a
soft/compiler magic cast (a function call).

-- 
Pieter

"I have read your book and much like it."
 -- Moses Hadas (1900-1966)
0
Pieter
4/10/2012 11:32:18 PM
Pieter Zijlstra wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > Hard casts shouldn't show any form of intelligence 
> > 
> > But they do. As long as there are no other casts (like the casts in
> > C++), they should.
> 
> But should it still be called a hard cast? It really is more like a
> soft/compiler magic cast (a function call).

It is the form that is called hard cast: MyType(SomeOtherType);

C++ has static_cast<OneType>(OtherType),
dynamic_cast<OneType>(OtherType) and
reinterpret_cast<OneType>(OtherType). I like that. In Delphi, a hard
cast is usually a reinterpret_cast. But the fact these are keywords (in
C++) means they are a lot easier to find and much clearer about their
meaning.

-- 
"Correctness is clearly the prime quality. If a system does not
 do what it is supposed to do, then everything else about it
 matters little." -- Bertrand Meyer
0
Rudy
4/11/2012 6:37:46 AM
Ain Valtin wrote:

> Olivier Sannier wrote:
> 
> > > Yes it can - it could/should use the case tag (foo in my example)
> > > to deside which variant part is valid and how to finalize the
> > > record.
> > 
> > Except that, IIRC, the same record can be used in different places
> > with a different "tag" meaning, while still holding the same set of
> > bytes.  Now, when it is time to release the record, how would you
> > know which finalize to call? I wouldn't, but I'd be happy to be
> > taught how to do it.
> 
> I don't quite get what do you mean but I see no problem implementing
> it... it just requires initializing the record's tag to default value
> and when it is changed then execute housekeeping stuff - kind of like
> compiler adds AddRef / Release for interface types behind the scene.

That would be like old Pascal. In Delphi, variant records are mostly
used to convert types avoiding a hard cast, or to emulate C/C++ unions.
In both cases, the tag is useless or even in the way.

-- 
"We had gay burglars the other night. They broke in and rearranged
 the furniture." -- Robin Williams.
0
Rudy
4/11/2012 6:39:37 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > And it would make the tag required,
> > which is not the case right now, and which is not desired either.
> 
> It would make tag required only if you want to have managed types in
> variant part.

Yes, and how often would you want that? Also, that the tag value
controls the access to the variant parts would break a lot of existing
code.

-- 
"Sterling's Corollary to Clarke's Law: Any sufficiently advanced
 garbage is indistinguishable from magic."
0
Rudy
4/11/2012 6:41:42 AM
Rudy Velthuis (TeamB) wrote:

> Ain Valtin wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > And it would make the tag required,
> > > which is not the case right now, and which is not desired either.
> > 
> > It would make tag required only if you want to have managed types in
> > variant part.
> 
> Yes, and how often would you want that? Also, that the tag value
> controls the access to the variant parts would break a lot of existing
> code.

It would not break any existing code! Currently there is no code with
managed types in variant part, adding that feature would not change
anything for the existing code.
One would be allowed to use managed types in variant part only when the
tag field is used, but of course the tag wouldn't be required. So one
can continue to use records just as they have been working so far.
Also, compiler wouldn't need to protect read access to the variant part
even when tag/managed types are used, only when writing then runtime
exception could be raised in case writing to invalid part of the
variant record (valid part being indicated by the tag). But again, that
would be the case with managed types only, so no existing code is
broken as there is no such a code right now.


ain
0
Ain
4/11/2012 7:25:01 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Ain Valtin wrote:
> > 
> > > Rudy Velthuis (TeamB) wrote:
> > > 
> > > > And it would make the tag required,
> > > > which is not the case right now, and which is not desired
> > > > either.
> > > 
> > > It would make tag required only if you want to have managed types
> > > in variant part.
> > 
> > Yes, and how often would you want that? Also, that the tag value
> > controls the access to the variant parts would break a lot of
> > existing code.
> 
> It would not break any existing code! Currently there is no code with
> managed types in variant part

If the tag always controlled the access to the variant parts, it would
break lots of code.

But even if it only did that if one of the parts was "managed", it
would still break existing code. People, knowing that they can put
interfaces or strings in variant parts will do that and this will break
existing code that accesses the other parts without changing the tag
field accordingly.

So, IMO, the drawbacks would outweigh the benefits by far.


-- 
"Imagine if every Thursday your shoes exploded if you tied them
 the usual way. This happens to us all the time with computers,
 and nobody thinks of complaining." -- Jeff Raskin
0
Rudy
4/11/2012 7:54:05 AM
Ain Valtin wrote:

> Wayne Niddery wrote:
> 
> > "Ain Valtin" <ask@when.you.really.need.it> wrote in message 
> > news:459325@forums.embarcadero.com...
> > > > 
> > >> IOW, the compiler CAN'T take care of this. It can't know which of
> > the >> variant parts is valid.
> > > 
> > > Yes it can - it could/should use the case tag (foo in my example)
> > > to deside which variant part is valid and how to finalize the
> > > record.
> > 
> > 
> > Since the record can change at RUN time how can it be resolved at
> > COMPILE time? It cannot. At compile time there is no tag to case.
> 
> Compiler would emit code which finalizes the record based on the value
> of the case tag.

It would also have to emit code that controls the access to the variant
parts, and that would bloat the code and make it slower, since this
would have to be done at runtime.

-- 
Goebel's Theorem Of Software Schedules: Always multiply a 
software schedule by pi.  This is because you think you're going 
in a straight line but always end up going full circle.
0
Rudy
4/11/2012 7:54:38 AM
Rudy Velthuis (TeamB) wrote:

> > Compiler would emit code which finalizes the record based on the
> > value of the case tag.
> 
> It would also have to emit code that controls the access to the
> variant parts, and that would bloat the code and make it slower,
> since this would have to be done at runtime.

Only for the records with managed types in variant part, in places
where managed fields are accessed. Don't use the feature and there is
no "bloat". And in some cases it is possible to omit the sanity check
code altogether if the compiler is able to determine at compile time
that the right part of the record is accessed. Ie given

type
  TFooBar = record
    case foo: Boolean of
       true : (int: Integer)
       false: (str: string)
    end
  end

var bar: TFooBar;
begin
  bar.foo := True;
  bar.int := 42;

compiler could see that the tag field indicates the use of int field
and thus there is no need to emit "check is it OK to write to this
field" code for the assignment. This requires similar analysis as
compiler already performs to emit "value assigned to x is never used"
hint and "value of x might be undefined" warning.
So in some cases compiler can even emit compile time error when the
wrong part of the record is written to...


ain
0
Ain
4/11/2012 10:02:59 AM
Rudy Velthuis (TeamB) wrote:

> > It would not break any existing code! Currently there is no code
> > with managed types in variant part
> 
> If the tag always controlled the access to the variant parts

Never suggested that.


> But even if it only did that if one of the parts was "managed", it
> would still break existing code. People, knowing that they can put
> interfaces or strings in variant parts will do that and this will
> break existing code that accesses the other parts without changing
> the tag field accordingly.

No, it wouldn't break existing code. As soon as you change your code,
it is "new code", and of course you have to follow the rules when
making changes. Want to use managed types in variant part - take care
of the tag field!


ain
0
Ain
4/11/2012 10:03:00 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > It would not break any existing code! Currently there is no code
> > > with managed types in variant part
> > 
> > If the tag always controlled the access to the variant parts
> 
> Never suggested that.
> 
> 
> > But even if it only did that if one of the parts was "managed", it
> > would still break existing code. People, knowing that they can put
> > interfaces or strings in variant parts will do that and this will
> > break existing code that accesses the other parts without changing
> > the tag field accordingly.
> 
> No, it wouldn't break existing code. As soon as you change your code,
> it is "new code",

The code using the record type would be the same, and therefore be
existing code. Only the record type would be different now.

-- 
"Insanity is catching."
 -- Terry Pratchett (Making Money)
0
Rudy
4/11/2012 10:07:30 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > Compiler would emit code which finalizes the record based on the
> > > value of the case tag.
> > 
> > It would also have to emit code that controls the access to the
> > variant parts, and that would bloat the code and make it slower,
> > since this would have to be done at runtime.
> 
> Only for the records with managed types in variant part, in places
> where managed fields are accessed.

Even if there are fields that ae not managed. Sorry but not a good
idea, IMO. Variant records are a thing of the past anyway and usually
only used in compatibility scenarios.

-- 
Weinberg's Corollary: An expert is a person who avoids the small 
errors while sweeping on to the grand fallacy.
0
Rudy
4/11/2012 10:09:04 AM
Rudy Velthuis (TeamB) wrote:

> Ain Valtin wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > > Compiler would emit code which finalizes the record based on the
> > > > value of the case tag.
> > > 
> > > It would also have to emit code that controls the access to the
> > > variant parts, and that would bloat the code and make it slower,
> > > since this would have to be done at runtime.
> > 
> > Only for the records with managed types in variant part, in places
> > where managed fields are accessed.
> 
> Even if there are fields that ae not managed.

Right, I meant "only where variant part is accessed". And all there is
needed is an compiler emited if test before writing to the field, ie in
the case of the type given in previous post, if compiler can't
determine it at compile time, it would compile assignment to bar.int as

  if(not bar.foo)then raise Exception;
  bar.int := 42;


> Variant records are a thing of the past anyway and usually
> only used in compatibility scenarios.

Well, the discussion started because you claimed that there is some
obvious reasons why this (managed types in variant part) can't be done.
I say this can be done. Is the variant record thing of the past or not
is a different matter and irrelevant here.


ain
0
Ain
4/11/2012 11:02:17 AM
Rudy Velthuis (TeamB) wrote:

> The code using the record type would be the same, and therefore be
> existing code. Only the record type would be different now.

You chaged the type so it is expected that the code using that type
might need changes too.


ain
0
Ain
4/11/2012 11:02:18 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > The code using the record type would be the same, and therefore be
> > existing code. Only the record type would be different now.
> 
> You chaged the type so it is expected that the code using that type
> might need changes too.

No, Ain. Maybe you misunderstand what a code breaking change is about.
If I take my current code and compile it with a new compiler (the one that deals with variant
records the way you suggest) and the outcome (functionality of the .exe) is changed, than the
compiler has a code breaking change. It requires me to change my code to retain the functionality I
had before.

All Delphi versions (from D1) has handled the records with variant parts the same:
- tag variable is optional
- tag variable (if present) does not affect in any way how you access any of the variant parts
- tag variable (if present) has no effect on the data that is contained in any of the variant parts
etc.

If any of those are changed, a lot of code would break, just as Rudy says. Period.

If you really think there should be a new kind of record with the functionality you suggest here,
then you can suggest that in a qc entry and hope that you get somebody to vote for it. But
remember, that would be a new type.

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/11/2012 11:24:00 AM
Tom Brunberg wrote:

> No, Ain. Maybe you misunderstand what a code breaking change is about.

Nope, it's you not understanding the suggested change.


> If I take my current code and compile it with a new compiler (the one
> that deals with variant records the way you suggest) and the outcome
> (functionality of the .exe) is changed, than the compiler has a code
> breaking change.

Agreed. But this wouldn't be the case (the functionality of the exe
wouldn't change).


> It requires me to change my code to retain the
> functionality I had before.

No. You wouldn't need to change your code unless you change your record
type so that it has a managed type in variant part.


> All Delphi versions (from D1) has handled the records with variant
> parts the same:  - tag variable is optional
> - tag variable (if present) does not affect in any way how you access
> any of the variant parts - tag variable (if present) has no effect on
> the data that is contained in any of the variant parts etc.

And that would still be the case.
Remember, currently managed types in variant part aren't allowed, so
there is no existing code which have them! So nothing could break.

Would the new fature added, it wouldn't change the way records without
managed types in variant part do work. You would gain ability to have
managed type in variant part, but if you do so, you'd have to use the
tag field and follow the stricter write access rules for the variant
part.


> If any of those are changed, a lot of code would break, just as Rudy
> says. Period.

No, the code would only break when you change your record type to use
the new feature. When you add new fields to your record type, then it
is expected that the code working with that record type might need
reworking too. But no code would break "out of the blue".


ain
0
Ain
4/11/2012 12:35:30 PM
Ain Valtin wrote:

> Tom Brunberg wrote:
> 
> > No, Ain. Maybe you misunderstand what a code breaking change is about.
> 
> Nope, it's you not understanding the suggested change.

That may be.
 
> > If I take my current code and compile it with a new compiler (the one
> > that deals with variant records the way you suggest) and the outcome
> > (functionality of the .exe) is changed, than the compiler has a code
> > breaking change.
> 
> Agreed. But this wouldn't be the case (the functionality of the exe
> wouldn't change).

Ok, good.

> > It requires me to change my code to retain the
> > functionality I had before.
> 
> No. You wouldn't need to change your code unless you change your record
> type so that it has a managed type in variant part.
> 
> > All Delphi versions (from D1) has handled the records with variant
> > parts the same:  - tag variable is optional
> > - tag variable (if present) does not affect in any way how you access
> > any of the variant parts - tag variable (if present) has no effect on
> > the data that is contained in any of the variant parts etc.
> 
> And that would still be the case.
> Remember, currently managed types in variant part aren't allowed, so
> there is no existing code which have them! So nothing could break.

You are right! I missed that one.

> Would the new fature added, it wouldn't change the way records without
> managed types in variant part do work. You would gain ability to have
> managed type in variant part, but if you do so, you'd have to use the
> tag field and follow the stricter write access rules for the variant
> part.

Ok, so let's build upon your idea further. Consider a record with two variant parts both holding a
couple of strings:
{code}
  TMyRec = record
  case i:integer of
    0:(s1: string;
       s2: string);
    1:(s3: string;
       s4: string);
  end;
....
var
  MyRec: TMyRec;
{code}
Upon initialization i would have the value of 0.
If I have understood you correctly, write access would be allowed only to the variant indicated by
the tag field, so a first assignment of:
  MyRec.s1 := '...' would be ok
but
  MyRec.s4 := '...' would not be ok
unless I first set the tag field to 1:
  MyRec.i := 1
  MyRec.s4 := '...'

Let's say we have i=1 and a string in s4.
What should happen if I want to change the tag back to 0 in order to write to s1 or s2:
  MyRec.i := 0;
  MyRec.s1 := 'string1'
Would I have to clear s4 first?
- Hope not, I would anyway forget it
Would s4 be finalized automatically?
- Probably
Would s4 continue to exist?
- Probably not

So, why not automate the finalization of the other variants allways when something (managed) is
written to another variant, IOW no need to set the tag first, it would also be set automatically.
Thus the tag would just indicate which variant has valid (managed) data (was last written to).

Then, what if the variants have overlapping memory as they mostly do, or is packed?
{code}
  TMyRec = packed record
  case i:integer of
    0:(s1: string;
       s2: string);
    1:(i3: integer;
       i4: integer);
  end;
....
var
  MyRec: TMyRec;
{code}
Seems like a recepie for disaster since writing to i3 would overwrite the s1 pointer. Ok, we must
change the spec to always finalize the other variant when writing any kind of data to the other one.
And what if I write to i3 and then attempt to read s1. Maybe read access also should be forbidden
for the non tagged variant?

I'm sure there are also other issues to deal with.

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/11/2012 2:46:41 PM
Tom Brunberg wrote:

> Ok, so let's build upon your idea further. Consider a record with two
> variant parts both holding a couple of strings:
> {code}
>   TMyRec = record
>   case i:integer of
>     0:(s1: string;
>        s2: string);
>     1:(s3: string;
>        s4: string);
>   end;
> ...
> var
>   MyRec: TMyRec;
> {code}
> Upon initialization i would have the value of 0.
> If I have understood you correctly, write access would be allowed
> only to the variant indicated by the tag field, so a first assignment
> of:    MyRec.s1 := '...' would be ok
> but
>   MyRec.s4 := '...' would not be ok

Yes.


> unless I first set the tag field to 1:
>   MyRec.i := 1
>   MyRec.s4 := '...'

Yes.


> Let's say we have i=1 and a string in s4.
> What should happen if I want to change the tag back to 0 in order to
> write to s1 or s2:    MyRec.i := 0;
>   MyRec.s1 := 'string1'
> Would I have to clear s4 first?

No, compiler would generate code which finalizes the variant part for
i=1 when you change the tag field. Thats why the tag field would be
required if you want to have managed type in variant part.


> Would s4 be finalized automatically?

Yes.

> Would s4 continue to exist?

No, it would be set to empty string by compiler generated code when you
assign new value to the tag field.


> So, why not automate the finalization of the other variants allways
> when something (managed) is written to another variant, IOW no need
> to set the tag first, it would also be set automatically.  Thus the
> tag would just indicate which variant has valid (managed) data (was
> last written to).

This could be an option, but this would allow bugs where user writes to
the wrong variant part by mistake and thus causes the data loss without
noticing it. So I would prefer the option where user has to explicitly
set the tag to indicate which part of the variant s/he needs write
access to. And if s/he then writes to the wrong part either compile
time (in case it is possible to detect it at compile time) or run time
error is raised.


> And
> what if I write to i3 and then attempt to read s1. Maybe read access
> also should be forbidden for the non tagged variant?

I think it is OK to allow read access to any variant part. The data you
would get would probably be meaningless but thats not really a
problem...


ain
0
Ain
4/11/2012 3:26:44 PM
Ain Valtin wrote:

> Tom Brunberg wrote:
> > So, why not automate the finalization of the other variants allways
> > when something (managed) is written to another variant, IOW no need
> > to set the tag first, it would also be set automatically.  Thus the
> > tag would just indicate which variant has valid (managed) data (was
> > last written to).
> 
> This could be an option, but this would allow bugs where user writes to
> the wrong variant part by mistake and thus causes the data loss without
> noticing it.

But such a bugs are possible with present records too.

> So I would prefer the option where user has to explicitly
> set the tag to indicate which part of the variant s/he needs write
> access to. And if s/he then writes to the wrong part either compile
> time (in case it is possible to detect it at compile time) or run time
> error is raised.

Well, its impossible for the compiler to detect such an error, it just can't follow all paths the
program may take.
So it would be a runtime error.

> > And
> > what if I write to i3 and then attempt to read s1. Maybe read access
> > also should be forbidden for the non tagged variant?
> 
> I think it is OK to allow read access to any variant part. The data you
> would get would probably be meaningless but thats not really a
> problem...

You would be lucky if you would get away with just meaningless data. And you would be lucky if you
would get away with only an AV. Most probably you would experience hard to find bugs, data
corruption or program crashes.
s1 is a pointer to a string structure which has a refcount field that is changed when you acess the
string. Since changing the i3 variable would change s1 to point wherever, the read access would
change the memory at offset -8 from the value in i3.

I'm beginning to have full  understanding for whoever decided to not allow strings and other
managed types in variant parts of records.

Cheers
Tom

-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/11/2012 4:22:57 PM
Tom Brunberg wrote:

> > This could be an option, but this would allow bugs where user
> > writes to the wrong variant part by mistake and thus causes the
> > data loss without noticing it.
> 
> But such a bugs are possible with present records too.

I don't expect compiler vendor to be backward compatible with existing
bugs... :)


> > So I would prefer the option where user has to explicitly
> > set the tag to indicate which part of the variant s/he needs write
> > access to. And if s/he then writes to the wrong part either compile
> > time (in case it is possible to detect it at compile time) or run
> > time error is raised.
> 
> Well, its impossible for the compiler to detect such an error, it
> just can't follow all paths the program may take.
> So it would be a runtime error.

It could detect some cases at compile time (I posted an example in
other message in this thread), other cases could be detected only at
runtime indeed.


> > I think it is OK to allow read access to any variant part. The data
> > you would get would probably be meaningless but thats not really a
> > problem...
> 
> You would be lucky if you would get away with just meaningless data.
> And you would be lucky if you would get away with only an AV. Most
> probably you would experience hard to find bugs, data corruption or
> program crashes.  s1 is a pointer to a string structure which has a
> refcount field that is changed when you acess the string. Since
> changing the i3 variable would change s1 to point wherever, the read
> access would change the memory at offset -8 from the value in i3.

Not neccesarily, the compiler can take care of that case too and
generate code which doesn't change the internals of an managed field if
it is accessed in the invalid part (the one not selected by case tag)
of the variant record. But indeed simpler solution would be to not
allow read access to inactive part of such a record.


ain
0
Ain
4/11/2012 7:47:58 PM
Ain Valtin wrote:

> Tom Brunberg wrote:
> > You would be lucky if you would get away with just meaningless data.
> > And you would be lucky if you would get away with only an AV. Most
> > probably you would experience hard to find bugs, data corruption or
> > program crashes.  s1 is a pointer to a string structure which has a
> > refcount field that is changed when you acess the string. Since
> > changing the i3 variable would change s1 to point wherever, the read
> > access would change the memory at offset -8 from the value in i3.
> 
> Not neccesarily, the compiler can take care of that case too and
> generate code which doesn't change the internals of an managed field if
> it is accessed in the invalid part (the one not selected by case tag)
> of the variant record.

Ain, with "doesn't change the internals ...", do you mean 1) the string variable (pointer) in the
record or 2) the structure that the string variable is pointing at?

If 1) it means that s1 and i3 (and neither s2 and i4) in the earlier example could not share memory
and thus you could just as well write the record without variant parts.
If 2) you really need to think again!

> But indeed simpler solution would be to not
> allow read access to inactive part of such a record.

The simplest solution is to continue with the records as they are today, possibly adding methods to
allow or deny access in what ever way fancies you.


Cheers
Tom

-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/11/2012 9:46:38 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > The code using the record type would be the same, and therefore be
> > existing code. Only the record type would be different now.
> 
> You chaged the type so it is expected that the code using that type
> might need changes too.

I extended the type. That should not break old code.

-- 
"They laughed when I said I'd be a comedian. They aren't 
 laughing now."
0
Rudy
4/12/2012 6:33:31 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Ain Valtin wrote:
> > 
> > > Rudy Velthuis (TeamB) wrote:
> > > 
> > > > > Compiler would emit code which finalizes the record based on
> > > > > the value of the case tag.
> > > > 
> > > > It would also have to emit code that controls the access to the
> > > > variant parts, and that would bloat the code and make it slower,
> > > > since this would have to be done at runtime.
> > > 
> > > Only for the records with managed types in variant part, in places
> > > where managed fields are accessed.
> > 
> > Even if there are fields that ae not managed.
> 
> Right, I meant "only where variant part is accessed". And all there is
> needed is an compiler emited if test before writing to the field

Initialization as well as finalization would be complicated too. And if
you change the tag, the other field may not be properly initialized, or
it would be set to 0, nil, etc, which would change the value of the
record. Nah, not a good idea altogether. And quite unnecessary too.

-- 
"My health plan doesn't cover dental, so I enrolled my teeth as
 32 dependents, each needing a complete physical once a year."
 -- Robert Brault, www.robertbrault.com
0
Rudy
4/12/2012 6:36:19 AM
Tom Brunberg wrote:

> Ain, with "doesn't change the internals ...", do you mean 1) the
> string variable (pointer) in the record or 2) the structure that the
> string variable is pointing at?
> 
> If 1) it means that s1 and i3 (and neither s2 and i4) in the earlier
> example could not share memory and thus you could just as well write
> the record without variant parts.  If 2) you really need to think
> again!

I mean that it wouldn't treat the (currently invalid) managed field as
such but as a raw pointer, so you would get (copy of) the content of
that field, but no addref / release etc hosekeeping on the invalid
field is done. So if you assign to the string variable, first new
unique string with appropriate length is created and then content of
the field is copyed to the string. Granted, it would verly likely give
you invalid (unicode) string, but hey, thats what you asked for.
But since this doesn't seem like very useful feature it could be
implemented so that only the currently selected variant part is
accessible (for both read and write).

BTW you and Rudy seem to be somewhat obsessed by the "read the
currently inactive part of the record" part of the variant records.
While that is useful feature, it isn't the only reason for the variant
records. The idea for me is that you can clearly state the design of an
data structure - that only some fields are valid in given context. And
I see no reason why one shouldn't be able to use managed types too,
even if it comes with some restrictions (and those restrictions
wouldn't affect record types which doesn't use managed types in variant
part).


ain
0
Ain
4/12/2012 8:00:40 AM
Rudy Velthuis (TeamB) wrote:

> > Right, I meant "only where variant part is accessed". And all there
> > is needed is an compiler emited if test before writing to the field
> 
> Initialization as well as finalization would be complicated too.

It wouldn't be any more complicated that Initialization or finalization
of the "ordinary" managed type, just an test of the case tag added to
deside on which fields to do it.


> And
> if you change the tag, the other field may not be properly
> initialized, or it would be set to 0, nil, etc,

Huh?
Again, it is quite simple for compiler to emit code which takes
nessesary action when tag field is changed.


> Nah, not a good idea altogether. And quite
> unnecessary too.

Here we go again, Rudy telling the world what it needs and what it
doesn't need...


ain
0
Ain
4/12/2012 8:00:41 AM
Ain Valtin wrote:

> Yes it can - it could/should use the case tag (foo in my example) to
> deside which variant part is valid and how to finalize the record.

But there's nothing stopping your writing code like

{code}
rec.bar := IMyInterface;
rec.foo := True;
{code}

How could the compiler know anything about the valid type at any time,
especially run time when it (the compiler) is out of the picture?

This has always been a murky part of the Pascal definition. Please note
that the tag field is *not* set automatically, it's just another field
in the record and in fact it doesn't even have to *exist* in the
record! You could as well have written

{code}
record
  case Boolean of
    true : str: string;
    false: bar: IInterface;
  end
end
{code}

It is only *you* that *may* know what's in a variant record at any
time. Not the compiler at compile time, not the CPU at run time.
0
Anders
4/12/2012 8:03:36 AM
Rudy Velthuis (TeamB) wrote:

> In old Pascal, only the part that corresponded to a certain tag was
> accessible. So if the tag said the variant part was an interface, you
> would not be able to store a string in str and could only access bar.

Got a reference for that? 

AFAIR (I have been using Pascal since 1973-4-5 something) it was always
possible to access any variant, irrespective of the tag value,
especially when the tag wasn't even stored in the record...
0
Anders
4/12/2012 8:06:16 AM
Ain Valtin wrote:

> The idea for me is that you can clearly state the design of
> an data structure - that only some fields are valid in given context.

Why cram such functionality into a record? Use a class instead.
0
Anders
4/12/2012 8:14:53 AM
Anders Isaksson wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > In old Pascal, only the part that corresponded to a certain tag was
> > accessible. So if the tag said the variant part was an interface,
> > you would not be able to store a string in str and could only
> > access bar.
> 
> Got a reference for that? 
> 
> AFAIR (I have been using Pascal since 1973-4-5 something) it was
> always possible to access any variant, irrespective of the tag value,
> especially when the tag wasn't even stored in the record...

Not on this computer, but I'm sure there is one.

-- 
"Civil disobedience, thatís not our problem. Our problem is
 that people are obedient all over the world in the face of
 poverty and starvation and stupidity, and war, and cruelty. Our
 problem is that people are obedient while the jails are full of
 petty thieves, and all the while the grand thieves are running
 the country. That's our problem."
 -- Howard Zinn
0
Rudy
4/12/2012 8:50:25 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > Right, I meant "only where variant part is accessed". And all
> > > there is needed is an compiler emited if test before writing to
> > > the field
> > 
> > Initialization as well as finalization would be complicated too.
> 
> It wouldn't be any more complicated that Initialization or
> finalization of the "ordinary" managed type

Yes, it would, because it would have to know there is a tag and
evaluate its value to know which initialization or finalization to
perform (i.e. which variant part is the active part. At initialization,
this would also mean that the tag would have to be initialized:

  type
    Myrec = record
      case tag: Integer of
        const1: (X: Integer);
        const2: (I: IMyInterface);
        const3: (Z: Variant);
    end;

Now, if Myrec is a value type on a stack, which means that tag is
undefined yet, what should the initializer do? Init I or Z? Both
initializations are different. Or should tag be 0 by default, then
there is no initialiization at all (since X is "active").

But what if you want to access .I or .Z then? You must set tag to
const2 or const3 and then what happens? Should IMyInterface be
initialized now, resetting the value in the record to nil, even if the
integer was, say 12345, or what? Or should 12345 be considered a
non-nil interface or variant? And how does the compiler know when what
should be initialized and when not?

Sorry, but this is far more complicated than you think, and the dilemma
described above can't be solved, AFAICT. The current restriction makes
a lot of sense.

-- 
"A child of five could understand this. Fetch me a child of five."
 -- Groucho Marx
0
Rudy
4/12/2012 9:28:58 AM
Anders Isaksson wrote:

> Ain Valtin wrote:
> 
> > The idea for me is that you can clearly state the design of
> > an data structure - that only some fields are valid in given
> > context.
> 
> Why cram such functionality into a record? Use a class instead.

The feature was introduced when there wasn't OOP. I believe that was
the original intended use of the variant record, and because memory was
at premium at those time it was implemented in the "fields in variant
part occupy the same memory" way... but people started to use that
implementation detail as a feature, to "cast between types".

It takes much more work to achieve the same thing with classes, the
only way I see it to create base class with common fields and then two
descendants with "variant part". And then you have to cast to correct
descendant type to use the variant part while with record you just use
case statement to determine which field to access. Much more work
compared to variant record...

Oh, and last time I wanted that feature I wanted to use it with
VirtualTreeView, where I had string data for nodes at levels 0 and
integer data at level 1. Not a big deal to have unnessesary field
always in the record, but from the design point of view it vould have
been better to use variant record... VT, of course, uses record types,
not classes.


ain
0
Ain
4/12/2012 10:27:33 AM
Anders Isaksson wrote:

> Ain Valtin wrote:
> 
> > Yes it can - it could/should use the case tag (foo in my example) to
> > deside which variant part is valid and how to finalize the record.
> 
> But there's nothing stopping your writing code like
> 
> {code}
> rec.bar := IMyInterface;
> rec.foo := True;
> {code}
> 
> How could the compiler know anything about the valid type at any time,
> especially run time when it (the compiler) is out of the picture?

Compiler would emit code before assignment to the "rec.foo" which does
nessesary housekeeping... I already explainet that somwhere in this
thread.


> This has always been a murky part of the Pascal definition. Please
> note that the tag field is not set automatically, it's just another
> field in the record and in fact it doesn't even have to exist in the
> record!

As I wrote in another post, if you want to use managed types in variant
part then you have to use the tag field also, so that compiler can use
it to generate nessesary housekeeping code.


ain
0
Ain
4/12/2012 10:27:34 AM
Rudy Velthuis (TeamB) wrote:

> Ain Valtin wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > > Right, I meant "only where variant part is accessed". And all
> > > > there is needed is an compiler emited if test before writing to
> > > > the field
> > > 
> > > Initialization as well as finalization would be complicated too.
> > 
> > It wouldn't be any more complicated that Initialization or
> > finalization of the "ordinary" managed type
> 
> Yes, it would, because it would have to know there is a tag and
> evaluate its value to know which initialization or finalization to
> perform (i.e. which variant part is the active part. At
> initialization, this would also mean that the tag would have to be
> initialized:

Exactly, the tag and corresponding variant part of the record would be
initalized when the record is created, and then when the tag's value is
changed, old value is used to finalize the current part, then the new
part would be initialized according to the new tag value. Compiler can
easily generate nessesary code.


> But what if you want to access .I or .Z then? You must set tag to
> const2 or const3 and then what happens? Should IMyInterface be
> initialized now, resetting the value in the record to nil, even if the
> integer was, say 12345, or what? Or should 12345 be considered a
> non-nil interface or variant?

Yes, the value of the integer is "lost" and the interface field is
initialized to nil. Thats the rule when you want to have managed type
in the variant part. And no, it wouldn't break any existing code,
records without managed types in variant part could still be used to
"cast between types".


> And how does the compiler know when what
> should be initialized and when not?

Thats why the tag field is required with managed types, so that
compiler can use it to add nesseary housekeeping code. It has been
already discussed in this thread...


ain
0
Ain
4/12/2012 10:27:35 AM
Anders Isaksson wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > In old Pascal, only the part that corresponded to a certain tag was
> > accessible. So if the tag said the variant part was an interface, you
> > would not be able to store a string in str and could only access bar.
> 
> Got a reference for that? 
> 
> AFAIR (I have been using Pascal since 1973-4-5 something) it was always
> possible to access any variant, irrespective of the tag value,
> especially when the tag wasn't even stored in the record...

Hi Anders, your comment seemed familiar, so I looked up a discussion from around 21st february in
e.p.d.l.delphi.general where I answered your question regarding the tag variable being optional or
not.
Web link to the message:
https://forums.embarcadero.com/thread.jspa?messageID=437045&tstart=0#437045

IMO, I don't think the intention of Wirth at that time (1973) was to allow access *only* to the
variant part indicated by the tag field. He wrote:
> A record type may have several variants, in which case a certain field
> is designated as the tag field, whose value indicates which variant is
> assumed by the record variable at a given time.
The word *assumed* doesn't disallow access to other variants IMO.

You quoted his 1974 document in which the tag field clearly is optional:
> Then one can describe persons by data of the
> 
>   type person =
>        record <attributes or fields common to all persons> ;
>            case maritalstatus of
>            married: (<fields of married persons only>) ;
>            single: (<fields of single persons only>) ;
>        end
> 
> Usually, a component (field) of the record itself indicates its
> currently valid variant. For example, the above defined person
> record is likely to contain a common field
> 
> ms : maritalstetus
> 
> This frequent situation can be abbreviated by including the
> declaration of the discriminating component - the so-called tag
> field - in the case clause itself, i.e. by writing
> 
> case ms: maritalstatus of
IOW, the tag field *indicates* the valid variant.

Thus I don't see any *denial* of access to another variant than the one indicated by the tag field
(if present).

Anyway, the original Pascal specification doesn't have much relevance to the topic at hand.

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/12/2012 10:27:56 AM
Ain Valtin wrote:

> > But what if you want to access .I or .Z then? You must set tag to
> > const2 or const3 and then what happens? Should IMyInterface be
> > initialized now, resetting the value in the record to nil, even if
> > the integer was, say 12345, or what? Or should 12345 be considered a
> > non-nil interface or variant?
> 
> Yes, the value of the integer is "lost" and the interface field is
> initialized to nil.

Sorry, but what if the value found there is actually a valid interface,
or variant? How does the runtime know? You can hardly tell the runtime
to initialize the field each time it is accessed. Then you can just as
well omit it. <g>

Sorry, but your proposal doesn't make any sense to me. And the way you
describe it, it is useless.

-- 
"'Everything you say is boring and incomprehensible', she said, 
 'but that alone doesn't make it true.'" -- Franz Kafka
0
Rudy
4/12/2012 10:33:27 AM
Ain Valtin wrote:

> Anders Isaksson wrote:
> 
> > Ain Valtin wrote:
> > 
> > > Yes it can - it could/should use the case tag (foo in my example)
> > > to deside which variant part is valid and how to finalize the
> > > record.
> > 
> > But there's nothing stopping your writing code like
> > 
> > {code}
> > rec.bar := IMyInterface;
> > rec.foo := True;
> > {code}
> > 
> > How could the compiler know anything about the valid type at any
> > time, especially run time when it (the compiler) is out of the
> > picture?
> 
> Compiler would emit code before assignment to the "rec.foo" which does
> nessesary housekeeping...

WHAT housekeeping should it do? 

-- 
"I distrust those people who know so well what God wants them
 to do because I notice it always coincides with their own
 desires."
 -- Susan B. Anthony
0
Rudy
4/12/2012 10:34:22 AM
Ain Valtin wrote:

> Tom Brunberg wrote:
> 
> > Ain, with "doesn't change the internals ...", do you mean 1) the
> > string variable (pointer) in the record or 2) the structure that the
> > string variable is pointing at?
> > 
> > If 1) it means that s1 and i3 (and neither s2 and i4) in the earlier
> > example could not share memory and thus you could just as well write
> > the record without variant parts.  If 2) you really need to think
> > again!
> 
> I mean that it wouldn't treat the (currently invalid) managed field as
> such but as a raw pointer, so you would get (copy of) the content of
> that field, but no addref / release etc hosekeeping on the invalid
> field is done.

So, one more string handling routine, this time bypassing the refcounting.

> So if you assign to the string variable, first new
> unique string with appropriate length is created and then content of
> the field is copyed to the string. Granted, it would verly likely give
> you invalid (unicode) string, but hey, thats what you asked for.

It would most likely give me an AV. Mind you that writing to i3 changed the pointer s1.

> But since this doesn't seem like very useful feature it could be
> implemented so that only the currently selected variant part is
> accessible (for both read and write).

That's what I suggested, no?
Quoting myself:
> > Maybe read access
> > also should be forbidden for the non tagged variant?

> BTW you and Rudy seem to be somewhat obsessed by the "read the
> currently inactive part of the record" part of the variant records.

I can't speak for Rudy, but I am certainly not obsessed with anything in this matter. Just trying
to help you see the difficulties that would need to be solved. We all have good ideas. Sometimes
the patchwork required to realise the idea becomes so thick that it is time to return to square 1
and review what we are trying to achieve with the patchwork. Often it is also necessary to stop at
some point and conclude "this route creates more problems than it solves, better look for another
approach".

> While that is useful feature, it isn't the only reason for the variant
> records. The idea for me is that you can clearly state the design of an
> data structure - that only some fields are valid in given context. And
> I see no reason why one shouldn't be able to use managed types too,
> even if it comes with some restrictions (and those restrictions
> wouldn't affect record types which doesn't use managed types in variant
> part).

But why the obsession (thanks for the word, I like it!) about having the fields in variant parts?
Why not have them all in the main part of the record? Memory usage can not be a reason.
Or two separate records which you instantiate and dismiss as required?

Cheers
Tom


-- 
Tom Brunberg
firstname.surname@welho.com
0
Tom
4/12/2012 11:10:56 AM
Tom Brunberg wrote:

> > But since this doesn't seem like very useful feature it could be
> > implemented so that only the currently selected variant part is
> > accessible (for both read and write).
> 
> That's what I suggested, no?

Yes, and it looks like a reasonable compromise to have managed types in
variant part.


> But why the obsession (thanks for the word, I like it!) about having
> the fields in variant parts?  Why not have them all in the main part
> of the record? Memory usage can not be a reason.  Or two separate
> records which you instantiate and dismiss as required?

Better design - if you only need one or the other field at the time, it
is good to make it clear.
Do you use VirtualTreeView? Using multiple record types with it
(simultaniously, ie different data structures for different nodes)
would be mess!


ain
0
Ain
4/12/2012 11:44:26 AM
Rudy Velthuis (TeamB) wrote:

> Ain Valtin wrote:
> 
> > > But what if you want to access .I or .Z then? You must set tag to
> > > const2 or const3 and then what happens? Should IMyInterface be
> > > initialized now, resetting the value in the record to nil, even if
> > > the integer was, say 12345, or what? Or should 12345 be
> > > considered a non-nil interface or variant?
> > 
> > Yes, the value of the integer is "lost" and the interface field is
> > initialized to nil.
> 
> Sorry, but what if the value found there is actually a valid
> interface, or variant? How does the runtime know? You can hardly tell
> the runtime to initialize the field each time it is accessed. Then
> you can just as well omit it. <g>

It can't be valid interface because the tag retricted the value of the
variant part to he integer. Once you change the tag memory is
initializet to "nil interface field". Once more, the tag field would be
required to have managed types in variant part, so there is no need to
"initialize the field each time it is accessed", all the nessesary
information is available at runtime and some cases can be solved at
compile time as well.

I see you're just using your usual tactics to go around in circles and
annoy people until they give up...


ain
0
Ain
4/12/2012 11:44:27 AM
Ain Valtin wrote:

> Anders Isaksson wrote:
> 
> > Why cram such functionality into a record? Use a class instead.
> 
< [...]
> 
> It takes much more work to achieve the same thing with classes,

No, note the word *functionality*. You put a variant record in the
class, and access everything through properties. I.e. the variant
record has the storage, the class has the functionality.

Then you can check the validity of the tag field to your hearts desire,
generate any run time errors you want, and you don't have to change the
compiler.

But is anyone saving on memory these days? Why use a construct that
only will increase the chance for bugs? The only reasonable use of
variant records to day (as I see it) are:

- type conversion (getting at the bytes of a double, for example)
- map a physical record structure on file (as a help to parse binary
records)

and all usage of these should be short term (in program execution
space). Move the data to a safer structure as soon as possible in the
program.
0
Anders
4/12/2012 1:54:19 PM
Tom Brunberg wrote:

> Anders Isaksson wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > In old Pascal, only the part that corresponded to a certain tag
> > > was accessible. So if the tag said the variant part was an
> > > interface, you would not be able to store a string in str and
> > > could only access bar.
> > 
> > Got a reference for that? 
> > 
> > AFAIR (I have been using Pascal since 1973-4-5 something) it was
> > always possible to access any variant, irrespective of the tag
> > value, especially when the tag wasn't even stored in the record...
> 
> Hi Anders, your comment seemed familiar, so I looked up a discussion
> from around 21st february

:-) Yes, I remember that discussion. My main question to Rudy now was a
reference to a Pascal version that actually checked the tag field at
run time (can't see it ever doing it at compile time), and denied
access to the variant if the tag was something else. I don't belive
such an animal has ever existed, but I may of course be wrong...
0
Anders
4/12/2012 1:54:49 PM
"Tom Brunberg" wrote
> ...
> Sometimes the patchwork required to realize the idea 
> becomes so thick that it is time to return to square 1 
> ...

That is a good idea.  
But, may I suggest that you do it in a new thread.
--JohnH
0
John
4/12/2012 2:31:12 PM
Tom,

| We all have good ideas. Sometimes
| the patchwork required to realise the idea becomes so thick that it
| is time to return to square 1 and review what we are trying to
| achieve with the patchwork. Often it is also necessary to stop at
| some point and conclude "this route creates more problems than it
| solves, better look for another approach".

+1

I just "returned to square 1" on a project on Tuesday..  <g>  

It was refreshing how much easier it was to "do it right" this time
around.  ;-)


-- 

   Q

04/12/2012 09:27:19

XanaNews Version 1.19.1.278  [Q'sBrokenToolBar]
0
Quentin
4/12/2012 4:29:47 PM
Rudy Velthuis (TeamB) wrote:

> Pieter Zijlstra wrote:
> 
> > Rudy Velthuis (TeamB) wrote:
> > 
> > > > Hard casts shouldn't show any form of intelligence 
> > > 
> > > But they do. As long as there are no other casts (like the casts
> > > in C++), they should.
> > 
> > But should it still be called a hard cast? It really is more like a
> > soft/compiler magic cast (a function call).
> 
> It is the form that is called hard cast: MyType(SomeOtherType);

It might be called a hard cast but in real-life a lot of of these so
called hard casts aren't really hard casts in Delphi ;-)

> C++ has static_cast<OneType>(OtherType),
> dynamic_cast<OneType>(OtherType) and
> reinterpret_cast<OneType>(OtherType). I like that. In Delphi, a hard
> cast is usually a reinterpret_cast. But the fact these are keywords
> (in C++) means they are a lot easier to find and much clearer about
> their meaning.

Indeed, but on second thought we were just discussing semantics here
and I would probably hate it when it is changed to the C++ way ;-)

-- 
Pieter

"The pious pretense that evil does not exist only makes it
 vague, enormous and menacing."
 -- Aleister Crowley
0
Pieter
4/13/2012 1:01:14 AM
Hi,
Anders Isaksson wrote:
> 
> :-) Yes, I remember that discussion. My main question to Rudy now was a
> reference to a Pascal version that actually checked the tag field at
> run time (can't see it ever doing it at compile time), and denied
> access to the variant if the tag was something else. I don't belive
> such an animal has ever existed, but I may of course be wrong...

there once was a Pascal interpreter for the Apple IIe (with 128 kB) and
other Apple machines called Instant Pascal
(<http://apple2history.org/history/ah17/#02>). Though it did not check
the tag field of a variant record, it did check which field had been
written to and did not let you read from any other field. So the trick
we had always used in UCSD-Pascal to address a specific address,

  type
    PInteger = ^Integer;
    Address = record
      case Boolean of
        False: (ptr:  PInteger);
        True : (addr: Integer);
      end;

  var
    Addr: Address;
    val: Integer;
  begin
    Addr.addr := 1234;

    val       := Addr.ptr^;
    val       := val + 1;
    Addr.ptr^ := val;
  end;

did not work, because the reading of Addr.ptr was rejected at run-time.

(On the Apple IIe writing to a specific address was one (or the only)
way to produce sounds on the internal speaker or trigger some other
actions.)

Regards,
Jürgen

-- 
~
~
~
:wq

Edited by: Jürgen Krämer on Apr 13, 2012 10:58 AM
0
Utf
4/13/2012 8:58:47 AM
"Pieter Zijlstra" wrote
> ... 
> It might be called a hard cast but in real-life a lot of these so
> called hard casts aren't really hard casts in Delphi ;-)
> ...

Pieter, Rudy, et. al,
Maybe some better taxonomy would help.
Rgds, JohnH
0
John
4/13/2012 12:58:11 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Ain Valtin wrote:
> > 
> > > > But what if you want to access .I or .Z then? You must set tag
> > > > to const2 or const3 and then what happens? Should IMyInterface
> > > > be initialized now, resetting the value in the record to nil,
> > > > even if the integer was, say 12345, or what? Or should 12345 be
> > > > considered a non-nil interface or variant?
> > > 
> > > Yes, the value of the integer is "lost" and the interface field is
> > > initialized to nil.
> > 
> > Sorry, but what if the value found there is actually a valid
> > interface, or variant? How does the runtime know? You can hardly
> > tell the runtime to initialize the field each time it is accessed.
> > Then you can just as well omit it. <g>
> 
> It can't be valid interface because the tag retricted the value of the
> variant part to he integer. 

But not all the time. Say I set the tag to interface, store a valid
interface pointer into it, then set the tag to integer, read the value
and then set the tag back to interface. Now the interface would be
nilled out. Or, just to be sure, on each access, I set the tag first.
Should the interface be nilled out again? How does the tag know the
interface was not valid? Does the tag code do a _Release before setting
it to the integer value?

Sorry, but this is simply not a good idea. It is pretty useless, hard
to use, hard to implement and totally superflous.




-- 
"Once a new technology starts rolling, if you're not part of the
 steamroller, you're part of the road." -- Stewart Brand
0
Rudy
4/13/2012 1:14:51 PM
Rudy Velthuis (TeamB) wrote:

> > It can't be valid interface because the tag retricted the value of
> > the variant part to he integer. 
> 
> But not all the time.

Of course, it doesn't have to be. It is perfectly OK to switch the
currently active variant part.


> Say I set the tag to interface, store a valid
> interface pointer into it, then set the tag to integer, read the value
> and then set the tag back to interface. Now the interface would be
> nilled out.

Yes, that's what you asked for when you did set the tag to integer (to
finalize the variant part of the interface, ie to set it to nil).


> Or, just to be sure, on each access, I set the tag first.

Uh?


> Should the interface be nilled out again? How does the tag know the
> interface was not valid?

The tag knows is it a valid interface or not because record is
initialized to known state when it is created and from there on it is
simple "do the finalization of the old part and init of the new part"
whenever the value of the tag is altered.


OK, here's the summary of the feature:

Records without managed type in variant part continue to work the way
they have always worked, nothing changes in that case. Currently one
can't have managed type in variant part so there is no such code out
there and thus nothing can break when adding the feature.

When one uses managed type in variant part, using tag field becomes
mandatory. Only the currently "active" (selected by the tag field) part
is accessible (both read and write access).
Records are initialized to known state and when the value of the tag is
altered, compiler generated hosekeeping code takes care of finalizing
the managed types in currently active variant part, then initializes
managed fields in the newly activated part. When record is destroyed
then the currently active part is finalized.

So, your example

type
  TFooBar = record
    case foo: Boolean of
      False: (int: Integer);
      True : (bar: IInterface);
    end 
  end;

var R: TFooBar;
begin
  R.foo := True;
  R.bar := TInterfacedObject.Create;
  R.foo := False;
  prinf(R.int);
  R.foo := True;

What happens here:
 - the R.foo is initialised to False and because the integer (which is
currently active part) isn't managed type no init code is generated and
thus it's value is undefined;
 - "R.foo := True" the tag gets new value and the bar field is
initialized to nil (without calling _Release on the old value as it is
known to not be a valid interface);
 - assigning value to the bar field - usual stuff with managed type,
nothing special;
 - "R.foo := False" the bar field is finalized, ie set to nil;
 - "prinf(R.int)" as there wasn't assignment to the int field first
it's value is undefined, as an implementation detail it's likely value
is -1;
 - "R.foo := True" the int field doesn't need finalization so again,
only code for initializing the bar to nil is generated;


> It is pretty useless,

It is useful in situations where you have either one or other field and
you want to clearly indicate it. No being able to use managed type in
such a situation is unnessesary restriction.
I previously gave the example of using VirtualTreeView where one might
need string data on one level of nodes and integer data on other levels.


> hard to use

Uh? No harder than any other type.


> hard to implement

Nope, just some compiler generated code to keep track of the tag value
and do nessesary init/finit of the managed fields.


ain
0
Ain
4/13/2012 2:57:23 PM
John Herbster wrote:

> "Pieter Zijlstra" wrote
> > ... 
> > It might be called a hard cast but in real-life a lot of these so
> > called hard casts aren't really hard casts in Delphi ;-)
> > ...
> 
> Pieter, Rudy, et. al,
> Maybe some better taxonomy would help.
> Rgds, JohnH

Taxo... what??? ... <Googling> ... Oh I see, this was more or less
already answered by Rudy ...

> reinterpret_cast<OneType>(OtherType). I like that. In Delphi, a hard
> cast is usually a reinterpret_cast.

.... except for the real hard casts of course ;-)

-- 
Pieter

"What is the use of a house if you haven't got a tolerable
 planet to put it on?"
 -- Henry David Thoreau
0
Pieter
4/14/2012 2:03:00 AM
Pieter Zijlstra wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Pieter Zijlstra wrote:
> > 
> > > Rudy Velthuis (TeamB) wrote:
> > > 
> > > > > Hard casts shouldn't show any form of intelligence 
> > > > 
> > > > But they do. As long as there are no other casts (like the casts
> > > > in C++), they should.
> > > 
> > > But should it still be called a hard cast? It really is more like
> > > a soft/compiler magic cast (a function call).
> > 
> > It is the form that is called hard cast: MyType(SomeOtherType);
> 
> It might be called a hard cast but in real-life a lot of of these so
> called hard casts aren't really hard casts in Delphi ;-)
> 
> > C++ has static_cast<OneType>(OtherType),
> > dynamic_cast<OneType>(OtherType) and
> > reinterpret_cast<OneType>(OtherType). I like that. In Delphi, a hard
> > cast is usually a reinterpret_cast. But the fact these are keywords
> > (in C++) means they are a lot easier to find and much clearer about
> > their meaning.
> 
> Indeed, but on second thought we were just discussing semantics here
> and I would probably hate it when it is changed to the C++ way ;-)

C++ allows the old C-style casts too. But in C, these can do
conversions, e.g.

  int i = (int)myDouble;

will truncate myDouble, unlike in Delphi, where such a cast is simply
not allowed. Explicit casts would be a lot clearer than what we have
now, IMO. Note that a Delophi hard cast is equivalent to a C++
reinterpret_cast and C++ dynamic_cast is more or less equivalent to
"as".

-- 
Rudy Velthuis

"The most overlooked advantage of owning a computer is that if
 they foul up there's no law against whacking them around a bit." 
 -- Eric Porterfield
0
Rudy
4/14/2012 7:13:15 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > It can't be valid interface because the tag retricted the value of
> > > the variant part to he integer. 
> > 
> > But not all the time.
> 
> Of course, it doesn't have to be. It is perfectly OK to switch the
> currently active variant part.
> 
> 
> > Say I set the tag to interface, store a valid
> > interface pointer into it, then set the tag to integer, read the
> > value and then set the tag back to interface. Now the interface
> > would be nilled out.
> 
> Yes, that's what you asked for when you did set the tag to integer

No, that is not what I asked for. It would actually be pretty
unexpected behaviour.

As I said, I don't think it is a usable, useful or viable solution.
-- 
Rudy Velthuis

"Louis Pasteur's theory of germs is ridiculous fiction."
 -- Pierre Pachet, Professor of Physiology at Toulouse, 1872
0
Rudy
4/14/2012 7:15:15 AM
Rudy Velthuis (TeamB) wrote:

> > > Say I set the tag to interface, store a valid
> > > interface pointer into it, then set the tag to integer, read the
> > > value and then set the tag back to interface. Now the interface
> > > would be nilled out.
> > 
> > Yes, that's what you asked for when you did set the tag to integer
> 
> No, that is not what I asked for. It would actually be pretty
> unexpected behaviour.

Yes, thats what youre asking for when you change the value of the tag.
Changing the tag with managed types in variant part means "finalize the
old variant part and initialize the new variant part", thats part of
the specification of the feature.
Thus it would be expected behaviour.


> As I said, I don't think it is a usable, useful or viable solution.

Your opinion about usefulness of the feature is not important here. The
discussion was started because you claimed it can't be done. It can be
done.
If you continue to post this "I don't think this is useful" stuff I can
only conclude that you don't have any arguments left and thus try to
divert the discussion into "it's useful / no it isn't" match which you
of course would "win".
Is some feature useful or not is subjective opinion and neither of us
can claim to know it for sure, so please only technical arguments from
now on!


ain
0
Ain
4/14/2012 8:23:23 AM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > > Say I set the tag to interface, store a valid
> > > > interface pointer into it, then set the tag to integer, read the
> > > > value and then set the tag back to interface. Now the interface
> > > > would be nilled out.
> > > 
> > > Yes, that's what you asked for when you did set the tag to integer
> > 
> > No, that is not what I asked for. It would actually be pretty
> > unexpected behaviour.
> 
> Yes, thats what youre asking for when you change the value of the tag.

That is not what I asked for. It may be what I get if we implement it
your way, but it is certainly not what I asked for or what one might
expect.

But I doubt it will ever be done that way. And I am glad about that.

-- 
Rudy Velthuis

"The more I study religions the more I am convinced that man
 never worshipped anything but himself."
 -- Sir R. F. Burton
0
Rudy
4/15/2012 9:09:40 PM
Rudy Velthuis (TeamB) wrote:

> > Yes, thats what youre asking for when you change the value of the
> > tag.
> 
> That is not what I asked for. It may be what I get if we implement it
> your way, but it is certainly not what I asked for or what one might
> expect.

Oh yes, thats what you asked for because thats how the feature works.
You would know it works that way and thus you would expect it. If new
dental filling material appears, do you start stuffing it into your
customers mouth without learning first how it is supposed to be used? I
sure hope not! Same applies here - it would be a new feature, users are
expexted to learn how it works and thus know what to expect when they
use it.

BTW you haven't explained how you would expect it to work and why. I'm
pretty sure it could be implemented other way too, I just don't see any
real benefits, it would only complicate the implementation...


ain
0
Ain
4/15/2012 9:46:28 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > > Yes, thats what youre asking for when you change the value of the
> > > tag.
> > 
> > That is not what I asked for. It may be what I get if we implement
> > it your way, but it is certainly not what I asked for or what one
> > might expect.
> 
> Oh yes, thats what you asked for because thats how the feature works.

It is how you think the feature should work. I think that that makes it
rather useless. The current way, i.e. simply forbidding managed types
in variant parts is far more useful.

Variant records were old Pascal's way of having some kind of poor man's
polymorphism. There are many better way of achieving it. Currently,
variant ecords are only useful as emulations/conversions of C's unions
or to access parts of a type (using packed variant records). That makes
your suggestion rather obsolete too.
-- 
Rudy Velthuis

"Is your argument that the Creator of the Universe was working 
 under a deadline and His manager forced Him to rush inefficient
 designs into production?" -- John B. Breckenridge in bpot
0
Rudy
4/15/2012 9:57:47 PM
Rudy Velthuis (TeamB) wrote:

> It is how you think the feature should work. I think that that makes
> it rather useless. The current way, i.e. simply forbidding managed
> types in variant parts is far more useful.

Once again, I remind that the discussion started because you said
compiler can't take care of the managed types in variant part. I think
it has been demonstrated now that it can. Whether it is useful or not
is subjective, althought I don't quite get how (from the end user point
of view) limited options is more useful than having more options...
anyway, I don't see a point to continue so it's EOT for me.


ain
0
Ain
4/15/2012 10:35:45 PM
Ain Valtin wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > It is how you think the feature should work. I think that that makes
> > it rather useless. The current way, i.e. simply forbidding managed
> > types in variant parts is far more useful.
> 
> Once again, I remind that the discussion started because you said
> compiler can't take care of the managed types in variant part.

It can't, if the variant record ought to be useful. The way you propose
it is not useful.
-- 
Rudy Velthuis

"Debugging a Direct3D application can be challenging." 
 -- Microsoft's Direct3D Immediate Mode overview.
0
Rudy
4/15/2012 11:56:19 PM
Anders Isaksson wrote:

> Ain Valtin wrote:
> 
> > Anders Isaksson wrote:
> > 
> > > Why cram such functionality into a record? Use a class instead.
> > 
> < [...]
> > 
> > It takes much more work to achieve the same thing with classes,
> 
> No, note the word functionality. You put a variant record in the
> class, and access everything through properties. I.e. the variant
> record has the storage, the class has the functionality.
> 
> Then you can check the validity of the tag field to your hearts
> desire, generate any run time errors you want, and you don't have to
> change the compiler.

Then it is much easier to make the variant part private and expose the
fields as public properties of the record. Then you can check
validities too. And you can write implicit and explicit conversion
operators.

-- 
"C++ tries to guard against Murphy, not Machiavelli." 
 -- Damian Conway
0
Rudy
4/17/2012 6:39:27 AM
Rudy Velthuis (TeamB) wrote:

> Anders Isaksson wrote:
> 
> > No, note the word functionality. You put a variant record in the
> > class, and access everything through properties. I.e. the variant
> > record has the storage, the class has the functionality.
> > 
> > Then you can check the validity of the tag field to your hearts
> > desire, generate any run time errors you want, and you don't have to
> > change the compiler.
> 
> Then it is much easier to make the variant part private and expose the
> fields as public properties of the record. Then you can check
> validities too. And you can write implicit and explicit conversion
> operators.

It never occured to me that *records* could have the visibility
specifiers, too. They are not explicitely mentioned in the XE1 Help on
Records (Advanced), only by a vague link back to 'Classes & Objects', a
section the does *not* mention records...

But if that works, it's even better.
0
Anders
4/17/2012 9:37:21 AM
Anders Isaksson wrote:

> Rudy Velthuis (TeamB) wrote:
> 
> > Anders Isaksson wrote:
> > 
> > > No, note the word functionality. You put a variant record in the
> > > class, and access everything through properties. I.e. the variant
> > > record has the storage, the class has the functionality.
> > > 
> > > Then you can check the validity of the tag field to your hearts
> > > desire, generate any run time errors you want, and you don't have
> > > to change the compiler.
> > 
> > Then it is much easier to make the variant part private and expose
> > the fields as public properties of the record. Then you can check
> > validities too. And you can write implicit and explicit conversion
> > operators.
> 
> It never occured to me that records could have the visibility
> specifiers, too. They are not explicitely mentioned in the XE1 Help on
> Records (Advanced), only by a vague link back to 'Classes & Objects',
> a section the does not mention records...
> 
> But if that works, it's even better.

Take a look at my Decimal type. It has visibility specifiers,
operators, methods, properties and it is even a variant record. The
variant fields are private and declared at the *end* of the entire type
declaration.

http://rvelthuis.de/zips/decimals.zip

-- 
Rudy Velthuis

"I spent thirty-three years in the marines, most of my time
 being a high-class muscle man for big business, for Wall Street
 and the bankers. In short, I was a racketeer for capitalism."
 -- General Smedley Butler, Marine
0
Rudy
4/18/2012 11:07:05 PM
Reply:

Similar Artilces:

Migrate from Delphi 2007 for Win32 to Delphi XE
we use Delphi 2007 for Win32 to support legacy (32Bit) OWL-based pascal applications (yes i know it was a mistake not to switch to VCL 15 years ago). could our applications still be opened and compiled with Delphi XE? The existing projects are all plain Pascal-Code, coming back from the times of Turbo Pascal for Windows and later on Borland Pascal. Are there any improvements we could profit from (i.e IDE, Debugger)? Thanks Andrej > {quote:title=Andrej Dimic wrote:}{quote} > could our applications still be opened and compiled with Delphi XE? I'm not sure, but I guess ...

delphi Win32 using delphi .NET dll
Hi, I'm trying to use a delphi.NET dll in delphi.WIN32. I am currently using CodeGear Delphi 2007 with version2(base version) of .NET I can get the dll to import into the WIN32 application the only problem is when i include things such as: "using Classes,DateUtils, SysUtils" in the .NET dll the win32 application will instantly hang when any of the dll functions are called. Any help would be great thanks. Also I have tried this example and it also crashes for me? http://cc.embarcadero.com/Item/22688 -Braden I also found this.. "The problem is that, wehn you instal...

Delphi.NET loading Delphi.Win32 Driver
Hi, What I'm trying to do is marshal an array of cardinal (or integer) back into managed memory from a win32 dll. I know how to pass managed memory into a win32 dll {code} var aa : array of Integer; Buffer : IntPtr; begin SetLength(aa,2); aa[0] := 1; aa[1] := 80; if not Supports(ExtractFilePath(Application.ExeName)+'Win32_Library\SDK_Driver.Win32.io', TypeOf(IMyFunctions), MyFunctions) then Exit; //loads the driver into memory. MyFunctions contains the method names found in the SDK_Driver. Buffer := Marshal.AllocHGlobal(2 * {Marshal.SystemDefaultC...

Converting Delphi for Win32 to Delphi .Net(Prism)
Hi, I am currently migrating a project from Delphi for Win32 to Delphi.net. Part of my code currently goes into a directory and pulls out a random file from this directory and loads the contents of the file for me. This code doesn't seem to work in Delphi.Net. It uses PString and a number of functions in SysUtils that don't seem to be present in Delphi.net's SysUtils file. If anyone can help me please, it would be greatly appreciated! Many thanks, Jonathan Mackey Jonathan Mackey a écrit : > I am currently migrating a project from Delphi for Win32 to &...

Delphi and Delphi for .Net
It seems that Delphi for .Net is slower than Delphi Win32 native applicaiton. I would like to know is it true all .Net application is slower than Win32 native applicaiton or it is Delphi for .Net only. Your information is great appreciated, Inung On 2011-06-21 18:20:17 +0100, Inung Huang said: > It seems that Delphi for .Net is slower than Delphi Win32 native applicaiton. > I would like to know is it true all .Net application is slower than > Win32 native applicaiton or it is Delphi for .Net only. If you are only running the code in the application once then, yes, yo...

Win32 program: Delphi 7 vs Delphi XE5
How is a D7 Win32 program compared to a Delphi XE5 one in terms of stability and performance? Is Delphi XE5 good enough for a big ERP project with several DLL's and hundreds of units and forms? Thanks in advance Am 26.12.2013 15:02, schrieb lior ilan: > How is a D7 Win32 program compared to a Delphi XE5 one in terms of stability > and performance? > Is Delphi XE5 good enough for a big ERP project with several DLL's and > hundreds of units and forms? > Thanks in advance > Hello, XE5 has increased functionality. Stability seems to be ok for most ...

Win32 Delphi language features introduced since Delphi 7
Hi, Am I right in thinking that the language features introduced since Delphi 7 fall into the categories: a) language features dictated by .Net compatibility. e.g. Namespaces, Inlining, records with methods, operator overloading, pure interfaces, generics, extended RTTI and reflection; b) Unicode strings and supporting procedures? c) 64-bit support What other language features, if any, have been introduced since D7? Had most of the post-D7 languages features, except for generics, Unicode strings, and 64-bit support, been introduced in or before Delphi 2005? How bug-free were ...

SEPA components for Delphi with Source Code (Delphi 5
Hi all, in the european union change next year the Bankingformat to the SEPA Format. All peoples and companies must change the bankingssoftware and the costumer data form acountnummers in the new IBAN and BIC numbers. See: http://www.arma-it.de/shop/artikelueber.php?wgruppeid=211&wgruppe_offen=211 Functions: - generate SEPA XML'S - Calc IBAN - BIC Database (DE,AT and CH) Questions: vertrieb@arma-it.de PS: Bankinssoftware for Develpoers (Germany only) http://www.arma-it.de/shop/artikelueber.php?wgruppeid=212&wgruppe_offen=212 El 26/10/13 21:38, A...

Delphi 7 to Delphi XE
Have been using Delphi 7 for many moons ( have got later versions but never upgraded to ) My first problem is: Component Palette. in XE it is a small toolbar docked in top right in Delphi 7 it gives a large view of all the components. I am struggling to be able to cope/access my components.in Delphi XE. Can I make the component pallette tool bar the same size as Delphi 7, or is there a fast way to view/choose all available components in XE, that I have not spotted yet? Kind Regards, Robert. Hi, What I know is that in Delphi 2010 and XE you can choose between t...

Delphi for PHP or Delphi PRISM
Hi, I have the opportunity to develop a web-based library management system. Nothing fancy, just being able to do the usual CRUD stuff for books and provide a search facility. Borrowing is to be done via an email request to the library admin who then sends out the book(s). Since both Delphi for PHP and Delphi PRISM will enable me to develop the app, which one will allow me to deliver it in less time and also increase (even how small) my marketability as a web developer? Thanks. Phillip Flores Phillip Flores wrote: > Hi, > > I have the opportunity to develop a...

Delphi 4 to Delphi 2009
Hello, Thanks to all who answered my previous question. That was a great help. And atlast our client agreed to upgrade our delphi version from 4 to Delphi 2009. *Sigh*. But before that, I need to give the estimation and cost regarding the migration to delphi 2009. Can anyone tell me is there any tool to migrate from delphi 4 to delphi 2009 or just I need to compile our Delphi 4 application in Delphi 2009. I have read from the delphi 2009 feature matrix that Delphi 1 through Delphi 2007 import is possible in delphi 2009. But i am not that sure considering the size of our application. ...

Delphi XE / Delphi 2010
Hello! I noticed that Embarcadero® Delphi® 2010 Version is not on the list of products on Embarcadero page. Or is it still possible to buy it? Will RAD Studio XE compile programs written in Delphi 2010 without problems.? Thanks. Am 13.09.2010 09:04, schrieb Petra Nemec: > Will RAD Studio XE compile programs written in Delphi 2010 without problems.? As always you will probably have to recreate the projects as the import is still a bit -- special. Christian Hello! Does anybody know if it is still possible to get a Delphi2010 trial version (if yes where)? ...

Delphi 5 to Delphi 6 and up
Dear List, Trying to add 7Zip compression support to my delphi application. I am using the ported 7Zip sdk (see their website, they have a link). I am stumped on how to rewrite a single function: function ReverseDecode(var Models: array of SmallInt; ....): ..... where the input is mostly a fixed size array of SmallInt. This code perfectly compiles and functions in Delphi 6 and up, but in Delphi 5 I get the error: There is no overloaded version of 'ReverseDecode' that can be called with these arguments And obviously, the input (fixed) isn't the same as the param de...

Delphi 5 to Delphi XE4
Thinking about making the conversion. Of course we have numerous components such as: TurboPower AsyncPro, TurboPower Orpheus ICS2 Synactis All-In-The-Box. You guys have any advice as to the effort and time it may possibly take. It is a large application, several hundred thousand lines. And that's what happens when using third party components, a lot of extra work. I have been burned a few times. I now minimize the use to a few well known suppliers, like TMS. I have "banned" a lot of other components. Regards, Ole > > Thinking about making the conver...

Delphi 4 to Delphi 2007
Hello, I will have to port a D4 application (with source) to D2007. what kind of problem could I face ? I will have to go to customer site tommorow to analyse its source code to quote the work, what should I care of to hestimate the porting time ? Thanks John Terry wrote: > Hello, > I will have to port a D4 application (with source) to D2007. > what kind of problem could I face ? > I will have to go to customer site tommorow to analyse its source code > to quote the work, what should I care of to hestimate the porting time ? You can probably do it by just changi...

Web resources about - Delphi Rounding - embarcadero.delphi.win32

Rounding - Wikipedia, the free encyclopedia
This article is about numerical rounding. For lip-rounding in phonetics, see Labialisation . For other uses, see Rounding (disambiguation) . ...

Decimal Rounding on the App Store on iTunes
Get Decimal Rounding on the App Store. See screenshots and ratings, and read customer reviews.

Christmas in summer: Rounding up Gadgety Goodness in NYC
Check out the newest gadgets on display in the world of consumer electronics

Christmas in summer: Rounding up Gadgety Goodness in NYC
The temperatures were hovering near 80, but there definitely was a "Christmas in June" vibe at last night's Digital Experience in New York, sponsored ...

'New Hitler' Gaddafi rounding up opponents
The son of a retired Libyan academic fears the worst for his father and three brothers after they are kidnapped by Moamar Gaddafi's forces in ...

Bell, Telus Face Lawsuit Over Rounding Up Calls To Next Full Minute
TORONTO An Ontario court has certified class action lawsuits against Telus and Bell over the practice of rounding up calls to the next full minute. Lawyers ...

Rounding Out Advertising Week With Your Burning Questions
Ad Age Publisher Allison Arden led an Advertising Week panel with four marketers at Nasdaq MarketSite today, using crowd-curated marketing questions ...

Rounding Up the Apple Rumors Ahead of WWDC
Apple will kick off its annual Worldwide Developers Conference with a Monday keynote address from CEO Tim Cook, and there’s no shortage of prognostications ...

AnandTech - AMD Radeon HD 7870 GHz Edition & Radeon HD 7850 Review: Rounding Out Southern Islands
In 2009-2010, AMD launched the entire 4 chip Evergreen series in 6 months. By previous standards this was a quick pace for a new design, especially ...

Nobody Is Rounding Up Jews In Ukraine
Donetsk Chief rabbi: leaflet distributed by separatists asking Jews to register, calls it a "provocation" #Ukraine http://t.co/h6xXjTERaH&quot ...

Resources last updated: 1/19/2016 7:27:25 AM