Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2016-12

List of integers? Any class available in RTL or FCL to help?

27 messages · 9 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Graeme Geldenhuys

Hi,

The code I'm working on often needs a list of integers (actually uint16, int16 etc, but Integer should do). I would normally use an array, but I have no idea how many items I'll need beforehand. Obviously I could take 15 minutes and implement my own TIntList class or something, but that got me thinking... Surely the RTL or FCL must have such simple container types already? If so, has anybody got suggestions? I could use TList and abuse the fact that it stores Pointers, which in affect is good enough to store Integer data, but is there a container that doesn't use such abuse?

I could use Generics, but I really don't like generics much - they just don't look pascal-like, but maybe I should simply get over that and just start using them.

I would still like to hear of the RTL or FCL has other container I could use.

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp
Graeme Geldenhuys
to Graeme Geldenhuys
Graeme Geldenhuys wrote
I would still like to hear of the RTL or FCL has other container I could use.

I forgot to mention, I also need the following additional functionality for such a container. Sorting and Ignore Duplicates.

Regards,
Graeme

Florian Klämpfl
to Graeme Geldenhuys
Graeme Geldenhuys wrote 7 lines
On 2016-12-04 09:43, Graeme Geldenhuys wrote: > I would still like to hear of the RTL or FCL has other container I could > use. I forgot to mention, I also need the following additional functionality for such a container. Sorting and Ignore Duplicates.

You mean you want allow duplicates? Then you should have a look at TFPGList, even if you do not like generics. TFPGList is our approach to extend FPC carefully with generics. As it is written in objfpc mode, you are forced not to clutter your code with specializations but you do once a TInt8List = specialize TFPGList<Int8> etc. and continue to use TInt8List. Further, TFPGList is a wrapper/anchestor around TFPSList, so each specialization does not explode into another full TList like implementation: a lot of code is shared by all specializations of TFPGList.

Martin Schreiber
to Graeme Geldenhuys: The code I'm working on often needs a list of integers (actually uint16, int16 etc, but…
Graeme Geldenhuys wrote
The code I'm working on often needs a list of integers (actually uint16, int16 etc, but Integer should do). I would normally use an array, but I have no idea how many items I'll need beforehand.

As an alternative to the FPC lists MSEgui provides the TDatalist hierarchy in lib/common/kernel/msedatalist.pas. For simple cases there is also lib/common/kernel/msearrayutils.pas with functions for dynamic arrays with an optional "count" parameter.

Martin

Graeme Geldenhuys
to Florian Klämpfl: You mean you want allow duplicates? Then you should have a look at TFPGList, even if you…

Hi Florain,

Thanks for the quick response.

Florian Klämpfl wrote
You mean you want allow duplicates?

I want the list to silently ignore duplicates.

eg:
  numberList.Duplicates := dupIgnore;
  numberList.Sorted := true;
  numberList.add(1);
  numberList.add(2);
  numberList.add(3);
  numberList.add(1);

The list will only contain 3 items in the end and the list is always sorted.

Then you should have a look at TFPGList, even if you do not like generics. TFPGList is our approach to extend FPC carefully with generics.

At the moment I'm using FPC 2.6.4 for the work I'm doing. I can't yet move to FPC 3.0.0.

My worry about Generics is the following statement in the fgl.pp unit:

"
{ be aware, this unit is a prototype and subject to be changed heavily } "

So that tells me this is not to be used in production software as it is more like an experiment than anything else.

As it is written in objfpc mode, you are forced not to clutter your code with specializations but you do once a TInt8List = specialize TFPGList<Int8> etc. and continue to use TInt8List.

This is good also only use objfpc mode in my code. I'm not totally discarding the use of Generics, I'm just worried about that prototype statement I mentioned. That made me thing that I might be better off implementing my own TList<T> because I don't know the future of the fgl.pp unit. But then if I go to all the trouble of implementing my own TList<T> then I can just as well use TIntegerList = class(TList) or something (but I do realise this last point will most likely be more coding).

ps:
Is it recommended to always define a specialised type? I guess it makes the code more clear when read by a human. Or is it perfectly acceptable doing:

  var
    lst: specialize TFPGList<Int8>;
  begin
    ...
  end;
Further, TFPGList is a wrapper/anchestor around TFPSList, so each specialization does not explode into another full TList like implementation: a lot of code is shared by all specializations of TFPGList.

I was just looking over the fgl.pp unit and noticed that exact point. So that is at least another good design.

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp
Yann Mérignac
to Graeme Geldenhuys

You can try my GContnrs unit (
http://yann.merignac.free.fr/unit-gcontnrs.html). It has tree sets that, as i understand them, can fulfill your needs.

2016-12-04 11:25 GMT+01:00 Graeme Geldenhuys
:

Show quoted text 85 lines
Hi Florain, Thanks for the quick response. On 2016-12-04 10:06, Florian Klämpfl wrote: > You mean you want allow duplicates? I want the list to silently ignore duplicates. eg: numberList.Duplicates := dupIgnore; numberList.Sorted := true; numberList.add(1); numberList.add(2); numberList.add(3); numberList.add(1); The list will only contain 3 items in the end and the list is always sorted. > Then you should have a look at TFPGList, even if you do not like > generics. TFPGList is our approach to extend FPC carefully with generics. At the moment I'm using FPC 2.6.4 for the work I'm doing. I can't yet move to FPC 3.0.0. My worry about Generics is the following statement in the fgl.pp unit: " { be aware, this unit is a prototype and subject to be changed heavily } " So that tells me this is not to be used in production software as it is more like an experiment than anything else. > As it is written in objfpc > mode, you are forced not to clutter your code with specializations but you do once a TInt8List = > specialize TFPGList<Int8> etc. and continue to use TInt8List. This is good also only use objfpc mode in my code. I'm not totally discarding the use of Generics, I'm just worried about that prototype statement I mentioned. That made me thing that I might be better off implementing my own TList<T> because I don't know the future of the fgl.pp unit. But then if I go to all the trouble of implementing my own TList<T> then I can just as well use TIntegerList = class(TList) or something (but I do realise this last point will most likely be more coding). ps: Is it recommended to always define a specialised type? I guess it makes the code more clear when read by a human. Or is it perfectly acceptable doing: var lst: specialize TFPGList<Int8>; begin ... end; > Further, TFPGList is a > wrapper/anchestor around TFPSList, so each specialization does not explode into another full TList > like implementation: a lot of code is shared by all specializations of TFPGList. I was just looking over the fgl.pp unit and noticed that exact point. So that is at least another good design. Regards, Graeme -- fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Graeme Geldenhuys
to Yann Mérignac
Yann Mérignac wrote
You can try my GContnrs unit ( http://yann.merignac.free.fr/unit-gcontnrs.html). It has tree sets that, as i understand them, can fulfill your needs.

Thank you for the offer. I'll definitely take a look at your code, but I don't think I can include 3rd party code in what I'm working on. I'm busy enhancing fpPDF code (which is part of Free Pascal's FCL).

Regards,
Graeme

fpGUI Toolkit - a cross-platform GUI toolkit using Free Pascal http://fpgui.sourceforge.net/ My public PGP key: http://tinyurl.com/graeme-pgp
Sven Barth
to Graeme Geldenhuys: Thanks for the quick response. I want the list to silently ignore duplicates. eg:…

Am 04.12.2016 11:25 schrieb "Graeme Geldenhuys" <

: > Then you should have a look at TFPGList, even if you do not like > generics. TFPGList is our approach to extend FPC carefully with

generics.

At the moment I'm using FPC 2.6.4 for the work I'm doing. I can't yet move to FPC 3.0.0.

Unit fgl is a part of FPC since around 2.2 or so and only for records you'd need 2.6.4 as an = operator overload is required (and no, a global one wouldn't be sufficient with generics). Thus regarding the compiler version it would be perfectly safe to use it.

Show quoted text 8 lines
My worry about Generics is the following statement in the fgl.pp unit: " { be aware, this unit is a prototype and subject to be changed heavily } " So that tells me this is not to be used in production software as it is more like an experiment than anything else.

I think we can throw out that statement. As said the unit is already part of FPC for a long time and up until some time in the 2.6 series I think the only generic containers provided by the RTL (then fcl-stl was added). 3.1 also contains the Delphi compatible and more versatile Generics.Collections unit.
So even if in the future the latter would become the main one, the fgl unit will at least stay as we don't like to break code without good reason and it's also more lightweight (though it has its restrictions like the need for an = operator when specializing TFPGList).

Show quoted text 10 lines
ps: Is it recommended to always define a specialised type? I guess it makes the code more clear when read by a human. Or is it perfectly acceptable doing: var lst: specialize TFPGList<Int8>; begin ... end;

This will only really work in 3.1.1 as I solved some problems there. Other than that, yes, it's completely fine. Delphi code mainly uses that approach though you can of course explicitly declare your types like in mode ObjFPC as well. The only exception to this are generic functions and methods, those always must be specialized inline.

I'd suggest you to at least play around with generics a bit as they're definitely here to stay and with them now working better than in 2.6 not to mention 2.4 they definitely make quite some coding easier.

Regards,
Sven

Lars
to Yann Mérignac: You can try my GContnrs unit ( http://yann.merignac.free.fr/unit-gcontnrs.html). It has…

This topic title brings back nostalgia as I needed an integer list before, and found some, either in the contributed units section of fpc, or in some old turbopascal units by a company.. TurboPower with Julian Bucknall, or something similar. As I looked through the code, I wondered if fpc and delphi really needed something more like a general purpose associative array or similar.. as it seemed people were reinventing it all the time over and over.

I believe I found some code on sourceforge, maybe it was that company that used to sell code for turbopascal called TurboPower, which I think Julian Bucknall worked for and they made casino software that ran on dos and powered casino machines.. But I could be recalling incorrect.

There is even old classic 1980's stuff like this:
http://www.drdobbs.com/cpp/container-object-types-in-turbo-pascal/184408235 An article in 1989 by Anders himself.... But that may be unrelated.

With data structures like this it does seem people are reinventing it, especially when people use a TStringList to store integers (I have done this before, a shame indeed, bad programming practice)... Or complex generics which just seems like over engineering, but at least it works. Using plain old arrays, requires reinventing the wheel because you end up writing duplicate functions for each array type (array of string) instead of a general purpose algorithm for many types..

I guess that is why some people prefer dynamic typed languages because you can write general algorithms for many types without reinventing the wheel. But with static languages it is still possible, as GoLang has a associative array, maps, etc without resorting to complex generics.

Sometimes I got so tired of inventing a intlist that I just ended up using a TStringList to store integers, which... was bad. but worked.

Sven Barth
"Lars" wrote 12 lines
With data structures like this it does seem people are reinventing it, especially when people use a TStringList to store integers (I have done this before, a shame indeed, bad programming practice)... Or complex generics which just seems like over engineering, but at least it works. Using plain old arrays, requires reinventing the wheel because you end up writing duplicate functions for each array type (array of string) instead of a general purpose algorithm for many types.. I guess that is why some people prefer dynamic typed languages because you can write general algorithms for many types without reinventing the wheel. But with static languages it is still possible, as GoLang has a associative array, maps, etc without resorting to complex generics.

I really don't get why some people think of generics as complex -.-

Regards,
Sven

Sven Barth
to denisgolovan
"denisgolovan" wrote 10 lines
05.12.2016, 13:35, "Sven Barth" : > > I really don't get why some people think of generics as complex -.- Exactly for the cited reason. See below. > Using plain old arrays, requires reinventing the wheel because you end

up

> writing duplicate functions for each array type (array of string)

instead

> of a general purpose algorithm for many types.. It's not possible to get uniform interfaces that would play nice with

algorithms.

Try writing a _single_ function for sorting static arrays, dynamic

arrays,open arrays, generic containers(T*List * all value types).

The standard recipe is re-implement everything from scratch over and over

again.

Even now, when we have generic functions - I am forced to specialize them

by hand! Even C# got it right...

Another issue is that some special functions are considered "special" -

you cannot overload them (SetLength, Copy, ...).

Yet another thing is that arrays are nice value-pretending types

(refcouting), but most generics are classes!

record based generics value types back to the language.

Basically it's all about combinatorics when combining functions. Either compiler does it for you, or you are forced to do it manually

instead.

To sum up, generics in current implementation add too little while

exploding combinatorial variety of algorithms.

Again: I don't see why anyone thinks of generics as complex. Your mail did not answer that in any way.

Regards,
Sven

Lars
to denisgolovan
denisgolovan wrote 5 lines
And generics are complex because they lead to more accidental complexity for reasons given earlier.

The Golang approach is to use interfaces, similar to freepascal's VARARGS but a bit different.. and more powerful. Interfaces, an overloaded term, not to be confused with COM/Corba interfaces...

i.e. a function that can take multiple types of "stuff".. without ever using generics or templates.

Someone on this list (maybe even me) mentioned that writing functions for arrays requires writing code multiple times that does basically the same thing but for different types...

You might be interested in this article:
http://wiki.c2.com/?IncludeFileParametricPolymorphism

I was able to make FPC compile code that took in multiple types to a function, without using generics, but just using fps's include file system. I believe golang's interfaces solve the issue more elegantly than using include file tricks, as the include file trick was just a prototype to prove it was possible..

A general purpose function that handles multiple types of arrays without rewriting the code for each array type looks like this:

    procedure AddItemToArray(
      const item: {$I T.inc}; var arr: {$I TArr.inc}); overload;
    var len: integer;
    begin
      // below is the same for EVERY type! Reuse, Reuse!
      len:= length(arr);
      setlength(arr, len+1);
      arr[len]:= item;
    end;

Where $I T.inc defines the type being used.

Maybe I reinvented generics. Advantage of this, is no OOP (object orientation) required and it therefore works on any procedural code or OOP code, not just OOP code alone. One reason I dislike generics in modern languages is that it almost always requires object orientation to be used and you cannot program "generally" using procedural style coding. My include file parametric polymorphism allows procedural code to be written (such as dealing with simple arrays) generally.

Golang does it via interfaces..

Dynamic typed languages like php and python can do it because of dynamic typing allowing any type to be passed in "generally" without the compiler checking.. which IMO is a bug, not a feature.

VARARGS sort of allow one to program generally, by allowing a multi type to be passed in, then you check it at run time... That's similar to golang's interfaces but golang interface more powerful than a vararg.

By vararg I mean:
  CallSomeCode([arbitrary, amount, of, parameters, of, any, type]);

Where the square brackets allow you to pass in sort of an "array of any type"

It is interesting that golang has been able to create an interface that can be sent in to a function/procedure, "generally", without resorting to any generics or c++ tempting tricks.. But the disadvantage is you have to check some things at run time, similar to RTTI or vararg checks...

if vararg.type = integer then..

if vararg.type = string then..

Whereas template systems tend to do these checks at compile time to save the run time checks...

My include file parametric polymorphism trick, does all the checks at compile time with no run time overhead. But it's an include file trick, not a language feature built in. I may have invented a general purpose generic way of writing code procedurally, which I find fascinating.. but I'm tooting my own horn.

Lars
to Sven Barth: up instead algorithms. arrays,open arrays, generic containers(T*List * all value types).…
Sven Barth wrote
Again: I don't see why anyone thinks of generics as complex. Your mail did not answer that in any way.

Well for one, at least in Delphi, it forces you to throw stuff into a class that have no need. Like a simple array...

This:

http://stackoverflow.com/questions/23447612/how-to-handle-a-plain-dynamic-array-using-generics

Is much more complex than my IncludeFileParametricPolymorphism invention that allows you to program arrays generally, without throwing stuff into a class just because classes are the only thing the compiler knows about generically. Why? Why should everything be forced into a class when it need not be. Even PHP, as much as I hate it, allows you to program generally, on simple functions/procedures without forcing something into a class.

But I don't know enough about fps generics to know if stuff needs to be forced into a class, as I have to start using generics and testing it out to really know. From what I've seen though, I'm certainly not and have never been a fan of less than and greater than signs.... They tick me off enough in HTML enough. But that's not really a real point, that's just a pet peeve to deal with...

Sven Barth
to Lars: The Golang approach is to use interfaces, similar to freepascal's VARARGS but a bit…
"Lars" wrote 14 lines
A general purpose function that handles multiple types of arrays without rewriting the code for each array type looks like this: procedure AddItemToArray( const item: {$I T.inc}; var arr: {$I TArr.inc}); overload; var len: integer; begin // below is the same for EVERY type! Reuse, Reuse! len:= length(arr); setlength(arr, len+1); arr[len]:= item; end; Where $I T.inc defines the type being used.

Same code with 3.1.1's generics in non-Delphi mode:

=== code begin ===

generic procedure AddItemToArray<T>(
      const item: T; var arr: specialize TArray<T>); overload;
    var len: integer;
    begin
      // below is the same for EVERY type! Reuse, Reuse!
      len:= length(arr);
      setlength(arr, len+1);
      arr[len]:= item;
    end;
// used like this:
specialize AddItemToArray<Longint>(42, myarr);

=== code end ===

Show quoted text 7 lines
Maybe I reinvented generics. Advantage of this, is no OOP (object orientation) required and it therefore works on any procedural code or OOP code, not just OOP code alone. One reason I dislike generics in modern languages is that it almost always requires object orientation to be used and you cannot program "generally" using procedural style coding. My include file parametric polymorphism allows procedural code to be written (such as dealing with simple arrays) generally.

FPC supports global generic routines (even in Delphi mode despite Delphi itself not supporting it).

Regards,
Sven

Sven Barth
to Lars: Well for one, at least in Delphi, it forces you to throw stuff into a class that have no…
"Lars" wrote 6 lines
But I don't know enough about fps generics to know if stuff needs to be forced into a class, as I have to start using generics and testing it out to really know. From what I've seen though, I'm certainly not and have never been a fan of less than and greater than signs.... They tick me off enough in HTML enough. But that's not really a real point, that's just a pet peeve to deal with...

I'm not a fan of the syntax for generics either, cause it's a PITA to parse certain corner cases (e.g. inline specializations in if-conditions). But what's done is done...

Regards,
Sven

Graeme Geldenhuys
to Sven Barth
Sven Barth wrote
> > enough in HTML enough. But that's not really a real point, that's just a > > pet peeve to deal with... I'm not a fan of the syntax for generics either, cause it's a PITA to

Out of curiosity, if there was a blank slate -- no Delphi-compatibility to worry about -- what syntax would you have chosen?

Regards,
Graeme

Lars
to Lars: Well for one, at least in Delphi, it forces you to throw stuff into a class that have no…
I previously wrote
But I don't know enough about fps generics to know if stuff needs to be forced into a class, as I have to start using generics and testing it out to really know.

Sorry, FPS --> FPC. My MacOs laptop that I'm on, testing it out, keeps automatically spell checking stuff... and made fps become fps

So if in my last emails you wondered what I mean by "fps generics" or "fps" which unfortunately came up several times... It's "FPC" that I meant..

Have to figure out how to turn off macOS spell check...

Me a Mac newbie, and, you can tell that.

Sven Barth

Am 14.12.2016 12:59 schrieb "Graeme Geldenhuys" <

: On 2016-12-14 10:14, Sven Barth wrote: >> > enough in HTML enough. But that's not really a real point, that's

just a

Show quoted text 5 lines
>> > pet peeve to deal with... > I'm not a fan of the syntax for generics either, cause it's a PITA to Out of curiosity, if there was a blank slate -- no Delphi-compatibility to worry about -- what syntax would you have chosen?

The thing is it's not even Delphi-compatibility as we had the syntax before Delphi implemented its own (that's why we have "generic" and "specialize" keywords). And that was before my time anyway...
That said... I'd probably use something along the following: specialize TFPGMap with (String, TObject).

Regards,
Sven

Lars
to Lars: The Golang approach is to use interfaces, similar to freepascal's VARARGS but a bit…
I previously wrote
similar to freepascal's VARARGS

Correction: I really meant ARRAY of CONST, but varargs is kind of related.

i.e.:
http://www.freepascal.org/docs-html/3.0.0/ref/refsu70.html#x181-20300014.4.6

is a simple way of generically programming, where you check what is being passed in at run time instead of at compile time..

but you can't do things more powerful like send structures (records) or more complex things like arrays, generically, whereas golang interfaces allow such.

Apologies for "varargs", that's just what came to mind.. I really meant "array of const". Even "array of const" is a strange name for this tool.

I think I once thought, can I make an "array of array of const" to try to expand on the power of array of const. Which seems like a silly idea, but academically interesting. Also, Varients are related to general programming (generic). But no one likes variants, as it is like dynamic typing.. Not sure if you can create an array of variant and program generally that way. Doesn't really matter as people hate variants and tend to avoid them.

Sven Barth
to Lars: Correction: I really meant ARRAY of CONST, but varargs is kind of related. i.e.:…
"Lars" wrote 7 lines
I think I once thought, can I make an "array of array of const" to try to expand on the power of array of const. Which seems like a silly idea, but academically interesting. Also, Varients are related to general programming (generic). But no one likes variants, as it is like dynamic typing.. Not sure if you can create an array of variant and program generally that way. Doesn't really matter as people hate variants and tend to avoid them.

Ehm... You are aware that "array of const" is nothing else than a "array of lightweight variant" (namely TVarRec)? So with "array of const" you *are* already working with dynamic typing, with only TVarRec being more restricted than Variant.

Regards,
Sven

Marco van de Voort
to Sven Barth: Am 14.12.2016 12:59 schrieb "Graeme Geldenhuys" < just a The thing is it's not even…

In our previous episode, Sven Barth said:

Show quoted text 6 lines
> Out of curiosity, if there was a blank slate -- no Delphi-compatibility > to worry about -- what syntax would you have chosen? The thing is it's not even Delphi-compatibility as we had the syntax before Delphi implemented its own (that's why we have "generic" and "specialize" keywords).

- FPC 2.2.0 release September 2007
- Delphi 2007 with afaik most of the current generics syntax in the .NET part : March 2007

We might have not aware of that at the time (who really used Delphi.NET?), but we were definitely not the first.

Jonas Maebe
to Marco van de Voort
Marco van de Voort wrote 11 lines
In our previous episode, Sven Barth said: > The thing is it's not even Delphi-compatibility as we had the syntax before > Delphi implemented its own (that's why we have "generic" and "specialize" > keywords). - FPC 2.2.0 release September 2007 - Delphi 2007 with afaik most of the current generics syntax in the .NET part : March 2007 We might have not aware of that at the time (who really used Delphi.NET?), but we were definitely not the first.

We didn't release it first, but Sven is right that we already had our own syntax long before Delphi with generics was released. The first commit for FPC generics support was on 21 December 2005 (r2020).

Jonas

Graeme Geldenhuys
to Jonas Maebe
Jonas Maebe wrote
The first commit for FPC generics support was on 21 December 2005 (r2020).

Dito :)
I was just about to say the same. You can't look at the FPC release date, you need to look at the generics commit date - those two dates could be far part - and in this case they were.

Regards,
Graeme