-1

I have the following unit I have used for some Delphi versions. But now I am testing XE8 and I get an error in

function THolydayList.TEnglishNameCollection.ToArray: TArray<string>;
begin
  Result := ToArrayImpl(fList.Count);
end;

I think is has to do with the fact that System.Generics.Collections is rewritten in XE8. But pressed for time I haven't had the opportunity to look into that. My question is: has anybody looked into this and can guide me in a direction as of what to look for.

An example of my use of this unit could be the following where I update a table with dates related to an employer for a given year

procedure TsCalendarYearHolyday(aEmployer: string; aYear: integer);
var
  STDDato: TStdDato;
  HolyDay : THolyDay;
  Query: TUniQuery;
begin
  Query := frmUniConn.CreateQuery;
  STDDato := TStdDato.Create;
  STDDato.Year := aYear;
  STDDato.Country := Denmark;
  STDDato.MarkSunday := False;
  STDDato.Language := hdNative;
  STDDato.MakeHoliDays(0);
  try
    Query.SQL.Clear;
    Query.SQL.Add('UPDATE ' + TableTsCalendarYear);
    Query.SQL.Add('   SET flddayspecial = :flddayspecial');
    Query.SQL.Add('      ,flddaydesc = :flddaydesc');
    Query.SQL.Add('      ,flddaynormal = :flddaynormal');
    Query.SQL.Add(' WHERE (flddate = :flddate)');
    Query.SQL.Add('   AND (fldemployer = :fldemployer)');
    for HolyDay in STDDato.Liste do
      begin
        try
          Query.ParamByName('flddayspecial').AsBoolean := True;
          Query.ParamByName('flddaydesc').AsString := Holyday.NativeName;
          Query.ParamByName('flddaynormal').AsFloat := 0;
          Query.ParamByName('flddate').AsDate := HolyDay.Date;
          Query.ParamByName('fldemployer').AsString := aEmployer;
          Query.Execute;
        except
          on E: exception do
            Logfile.Error('U_TsCalendars.TsCalendarYearHolyday: ' + E.Message);
        end;
      end;
  finally
    FreeAndNil(STDDato);
    Query.Free;
  end;
end;

I added a link since this is the whole unit

Danilo Casa
  • 506
  • 1
  • 9
  • 18
OZ8HP
  • 1,443
  • 4
  • 31
  • 61

1 Answers1

3

It's a little frustrating that you say "I get an error" without stating what that error is. Run time error? Compile time error? Please be precise about errors. In my experience, when people don't say what the error is it is often because they didn't read the error message closely and attempt to understand it. That is usually a mistake. So my biggest piece of advice to you is to pay closer attention to such details and hopefully that will help you solve such problems for yourself in the future.


However, since it is clear enough that the call to ToArrayImpl will fail to compile because ToArrayImpl is a private member, we can work it out.

Clearly you cannot call ToArrayImpl because it is private. And the only way we can work out what you need is to read the code in your off site link. Again, not ideal. This code will compile and behave as you intend.

function THolydayList.TEnglishNameCollection.ToArray: TArray<string>;
var
  i: Integer;
begin
  SetLength(Result, fList.Count);
  for i := 0 to fList.Count-1 do
    Result[i] := fList[i].EnglishName;
end;

Whether or not this is the best solution to your problem, I am not prepared to say.


Now, one might wonder how your code ever worked. This was due to compiler bugs in older versions. The ToArrayImpl method has always been private. Older versions of the compiler failed to correctly enforce that visibility and allowed your class to call ToArrayImpl when it was not meant to.

This code:

uses
  Generics.Collections;

type
  TMyEnumerable<TObject> = class(TEnumerable<TObject>)
    procedure Foo;
  end;

procedure TMyEnumerable<TObject>.Foo;
begin
  ToArrayImpl(0);
end;

compiles in XE7 but not XE8. Clearly the older compilers were broken.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The off site link was selected in order to include as much of the code as possible so I didn't forget some code needed to see the problem. – OZ8HP Aug 06 '15 at 05:23
  • 1
    Yes, there was a bug in generics that allowed access to private members from the ancestor class which got fixed in XE8 (I can't find any QC or QP entry for it right now). – Stefan Glienke Aug 06 '15 at 07:24
  • 2
    @OZ8HP Note that I cut it down to around 10 lines. That's an important skill to learn, in my view. Isolating the problem is the first part of problem solving. – David Heffernan Aug 06 '15 at 08:28
  • @Stefan: this was a generics problem only? Because IIRC, private worked properly before. – Rudy Velthuis Aug 07 '15 at 21:23
  • @Rudy Yes this is purely a generics issue. Stefan blogged about it a while back. I remember encountering the issue some while ago. – David Heffernan Aug 07 '15 at 21:24
  • Ok, then I understand now. Thanks. – Rudy Velthuis Aug 07 '15 at 21:26