View Issue Details

IDProjectCategoryView StatusLast Update
0038149FPCRTLpublic2020-12-01 22:01
Reporterrich_orr@yahoo.com Assigned ToSven Barth  
PrioritynormalSeverityminorReproducibilityalways
Status resolvedResolutionno change required 
PlatformDarwin for x86_64OSMacOS 
Product Version3.2.0 
Summary0038149: Warning on TObjectList create
DescriptionThis warning is generated when creating a TObjectList with a class type. There is no tie-back in the error to the source code that is causing the issue making me think that it is an issue inside of RTL-Generics itself. I have reproduced it in both my code and the generics authors own example code.d

genericstest.pas(20,14) Warning: (3057) An inherited method is hidden by "ToString:AnsiString;"
generics.collections.pas(1182,19) Warning: (5093) function result variable of a managed type does not seem to be initialized
Steps To ReproduceCompile attached source file for repro.
TagsNo tags attached.
Fixed in Revision
FPCOldBugId
FPCTarget-
Attached Files

Activities

rich_orr@yahoo.com

2020-11-29 19:59

reporter  

genericstest.pas (6,215 bytes)   
// Generic types for NewPascal.org and FPC!
// Original version by keeper89.blogspot.com, 2011
// FPC version by Maciej Izak (hnb), 2014

program TObjectListProject;

{$MODE DELPHI}

uses
  SysUtils, Generics.Collections, Generics.Defaults, DateUtils;

type
  TPlayer = class
  public
    Name, Team: string;
    BirthDay: TDateTime;
    NTeamGoals: Byte; // Number of goals for the national team
    constructor Create(const Name: string; BirthDay: TDateTime;
      const Team: string; NTeamGoals: Byte = 0);
    function ToString: string;
  end;

  // Class containing handlers add / remove list items
  TListEventsHandler = class
  public
    class procedure OnListChanged(Sender: TObject; constref Item: TPlayer;
      Action: TCollectionNotification);
  end;


constructor TPlayer.Create(const Name: string; BirthDay: TDateTime;
  const Team: string; NTeamGoals: Byte);
begin
  Self.Name := Name;
  Self.BirthDay := BirthDay;
  Self.Team := Team;
  Self.NTeamGoals := NTeamGoals;
end;

function TPlayer.ToString: string;
begin
  Result := Format('%s - Age: %d Team: %s Goals: %d',
                   [Name,
                    DateUtils.YearsBetween(Date, BirthDay),
                    Team, NTeamGoals])
end;

// Function sort descending goals for the national team
function ComparePlayersByGoalsDecs(constref Player1, Player2: TPlayer): Integer;
begin
  Result := TCompare.UInt8(Player2.NTeamGoals, Player1.NTeamGoals);
end;

class procedure TListEventsHandler.OnListChanged(Sender: TObject; constref Item: TPlayer;
  Action: TCollectionNotification);
var
  Mes: string;
begin
  // Unlike TDictionary we added Action = cnExtracted
  case Action of
    cnAdded:
      Mes := 'added to the list!';
    cnRemoved:
      Mes := 'removed from the list!';
    cnExtracted:
      Mes := 'extracted from the list!';
  end;
  Writeln(Format('Football player %s %s ', [Item.ToString, Mes]));
end;

var
  // Declare TObjectList as storage for TPlayer
  PlayersList: TObjectList<TPlayer>;
  Player: TPlayer;
  FoundIndex: PtrInt;
begin
  WriteLn('Working with TObjectList - football manager');
  WriteLn;

  PlayersList := TObjectList<TPlayer>.Create;

  // ---------------------------------------------------
  // 1) Adding items

  PlayersList.Add(
    TPlayer.Create('Zinedine Zidane', EncodeDate(1972, 06, 23), 'France', 31));
  PlayersList.Add(
    TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44));
  PlayersList.Add(
    TPlayer.Create('Ronaldo', EncodeDate(1976, 09, 22), 'Brazil', 62));
   // Adding the specified position
  PlayersList.Insert(0,
    TPlayer.Create('Luis Figo', EncodeDate(1972, 11, 4), 'Portugal', 33));
  // Add a few players through InsertRange (AddRange works similarly)
  PlayersList.InsertRange(0,
    [TPlayer.Create('David Beckham', EncodeDate(1975, 05, 2), 'England', 17),
     TPlayer.Create('Alessandro Del Piero', EncodeDate(1974, 11, 9), 'Italy ', 27),
     TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44)]);
  Player := TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44);
  PlayersList.Add(Player);


  // ---------------------------------------------------
  // 2) Access and check the items

  // Is there a player in the list - Contains
  if PlayersList.Contains(Player) then
    Writeln('Raul is in the list!');
  // Player index and count of items in the list
  Writeln(Format('Raul is %d-th on the list of %d players.',
                 [PlayersList.IndexOf(Player) + 1, PlayersList.Count]));
  // Index access
  Writeln(Format('1st in the list: %s', [PlayersList[0].ToString]));
  // The first player
  Writeln(Format('1st in the list: %s', [PlayersList.First.ToString]));
  // The last player
  Writeln(Format('Last in the list: %s', [PlayersList.Last.ToString]));
  // "Reverse" elements
  PlayersList.Reverse;
  Writeln('List items have been "reversed"');
  Writeln;


  // ---------------------------------------------------
  // 3) Moving and removing items

  // Changing places players in the list
  PlayersList.Exchange(0, 1);
  // Move back 1 player
  PlayersList.Move(1, 0);

  // Removes the element at index
  PlayersList.Delete(5);
  // Or a number of elements starting at index
  PlayersList.DeleteRange(5, 2);
  // Remove the item from the list, if the item
  // exists returns its index in the list
  Writeln(Format('Removed %d-st player', [PlayersList.Remove(Player) + 1]));

  // Extract and return the item, if there is no Player in the list then
  // Extract will return = nil, (anyway Raul is already removed via Remove)
  Player := PlayersList.Extract(Player);
  if Assigned(Player) then
    Writeln(Format('Extracted: %s', [Player.ToString]));

  // Clear the list completely
  PlayersList.Clear;
  Writeln;

  // ---------------------------------------------------
  // 4) Event OnNotify, sorting and searching

  PlayersList.OnNotify := TListEventsHandler.OnListChanged;

  PlayersList.Add(
    TPlayer.Create('Zinedine Zidane', EncodeDate(1972, 06, 23), 'France', 31));
  PlayersList.Add(
    TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44));
  PlayersList.Add(
    TPlayer.Create('Ronaldo', EncodeDate(1976, 09, 22), 'Brazil', 62));
  PlayersList.AddRange(
    [TPlayer.Create('David Beckham', EncodeDate(1975, 05, 2), 'England', 17),
     TPlayer.Create('Alessandro Del Piero', EncodeDate(1974, 11, 9), 'Italy ', 27),
     TPlayer.Create('Raul', EncodeDate(1977, 06, 27), 'Spain', 44)]);

  PlayersList.Remove(PlayersList.Last);
  Player := PlayersList.Extract(PlayersList[0]);

  PlayersList.Sort(TComparer<TPlayer>.Construct(ComparePlayersByGoalsDecs));
  Writeln;
  Writeln('Sorted list of players:');
  for Player in PlayersList do
    Writeln(Player.ToString);
  Writeln;

  // Find Ronaldo!
  // TArray BinarySearch requires sorted list
  // IndexOf does not require sorted list
  // but BinarySearch is usually faster
  Player := PlayersList[0];
  if PlayersList.BinarySearch(Player, FoundIndex,
    TComparer<TPlayer>.Construct(ComparePlayersByGoalsDecs)) then
    Writeln(Format('Ronaldo is in the sorted list at position %d', [FoundIndex + 1]));

  Writeln;

  // With the destruction of the list remove all elements
  // OnNotify show it
  FreeAndNil(PlayersList);

  Readln;
end.
genericstest.pas (6,215 bytes)   

rich_orr@yahoo.com

2020-11-29 20:01

reporter   ~0127261

Also will repro on Windows compilations.

Bi0T1N

2020-11-29 21:33

reporter   ~0127263

Last edited: 2020-11-29 21:34

View 2 revisions

Compiling with FPC 3.3.1-r47626 on Win64 gives:


test_bug.pas(20,14) Warning: An inherited method is hidden by "ToString:AnsiString(0);"
generics.collections.pas(1186,20) Note: Call to subroutine "function TEnumerable<TObjectListProject.TPlayer>.GetEnumerator:TEnumerator$1<TOBJECTLISTPROJECT.TPlayer>;" marked as inline is not inlined
generics.collections.pas(144,52) Note: Private type "TCustomPointersEnumerator$2<TOBJECTLISTPROJECT.TPlayer,TOBJECTLISTPROJECT.TCustomList$1$crcE0B4E8C7.PT>.T" never used


The warning about the hidden method is correct as all classes inherit from TObject which already provides a ToString (https://www.freepascal.org/docs-html/rtl/system/tobject.tostring.html) function and thus the program should use override;. To verify that you can use Result := inherited ToString; which will print TPlayer.

Thaddy de Koning

2020-12-01 11:45

reporter   ~0127293

Yes simply add override to ToString solves the issue.

Sven Barth

2020-12-01 22:01

manager   ~0127309

> genericstest.pas(20,14) Warning: (3057) An inherited method is hidden by "ToString:AnsiString;"

This is a mistake in your example as the others already said.

> generics.collections.pas(1182,19) Warning: (5093) function result variable of a managed type does not seem to be initialized

This one is already fixed in trunk and 3.2.1 as well.

Issue History

Date Modified Username Field Change
2020-11-29 19:59 rich_orr@yahoo.com New Issue
2020-11-29 19:59 rich_orr@yahoo.com File Added: genericstest.pas
2020-11-29 20:01 rich_orr@yahoo.com Note Added: 0127261
2020-11-29 21:33 Bi0T1N Note Added: 0127263
2020-11-29 21:34 Bi0T1N Note Edited: 0127263 View Revisions
2020-12-01 11:45 Thaddy de Koning Note Added: 0127293
2020-12-01 22:01 Sven Barth Assigned To => Sven Barth
2020-12-01 22:01 Sven Barth Status new => resolved
2020-12-01 22:01 Sven Barth Resolution open => no change required
2020-12-01 22:01 Sven Barth FPCTarget => -
2020-12-01 22:01 Sven Barth Note Added: 0127309