Autore Topic: Nuovo componente gb.adt con la rev. 5052  (Letto 840 volte)

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.316
  • Ne mors quidem nos iunget
    • Mostra profilo
Nuovo componente gb.adt con la rev. 5052
« il: 18 Agosto 2012, 16:05:04 »
Ambasciata della Comunità italiana di Gambas sulla mailing list internazionale

Comunicazione n. 10 dal vostro Ambasciatore      ;D

Questa Ambasciata porta a conoscenza un comunicato diffuso da tale Tobias Boege circa l'implementazione di un nuovo componente "gb.adt" avvenuta con la revisione 5052:

« Hi,
as of rev5052 you will notice a new gb.adt component as a playground for
abstract datatypes implementations.
I had most of the algorithms already lying around from another project.
Everything is, however, written from scratch and the code depends on nothing
but the C library.

Only hurdle was to incorporate the algorithms into the Gambas memory
management: You can imagine, that it is tricky to implement circular
double-linked lists of objects without creating circular references on the
list nodes.

The implementation of linked lists features two new classes:
- List, which represents a single list node. Technically speaking this list
  node is a fully capable linked list itself because it is linked to itself.
- ListRoot which is just a List object marked special so that special
  properties can be applied to it.

About List:
The first I want to state is that List nodes can be either used standalone
and created to _carry_ an object or they can be embedded into a new class
and _be carried_ by the object. You must tell the List constructor what kind
of mode your List node shall perform in. This is important because an
embedded List node which references its container creates unresolvable
circular references - which we don't want - otherwise a non-embedded list
nodes which does not reference its linked object may see the latter vanish
away because of its reference count becoming zero - not good either.

List nodes have a Next-element, Prev-element and Data-element pointer. As
said above, they are linked lists itself because initially their Next and
Prev pointers point to themselves.
Note carefully that the List.Add*() functions add _entire lists_. This is
normally not a problem because most people will add one node (which is
linked to itself into an empty list) but it is also possible to:

' List1 -> List2
List1.AddAfter(List2)

' GlobalList -> List1 -> List2
GlobalList.AddAfter(List1)

As far as a List node is in a non-empty list (i.e. a list which is not only
made up of itself), it gets a reference count. By the nature of circular
linked lists, this creates circular references. Consequently, if you create
a list, you must tidy it up by means of List.Clear() or differently,
depending on your application.

As imaginable with circular double-linked lists, you can do everything from
any node in the list: Add new lists/nodes, traverse the list, clear the
list, enumerate all objects in a list, unlink single nodes, extract lists
from others, etc..

About ListRoot:
Don't fear the ListRoot because it is the means I intended to solve the
memory obstacle of circular references. Actually ListRoot may be a
misleading name (help me native speakers!). ListRoot semantics differ from
normal List nodes in the following details:

- ListRoots don't carry data
- In a 'For Each data In List' they are skipped (s.a.)
- When linked in a list they get _no_ reference count.
- They cannot be linked to a list but the list must be linked to them. This
  helps prevent multiple ListRoots in a List infrastructure.

You got the two main reasons for which the List and ListRoot classes are
native now: I play tricks with reference counts (with embedded Lists and
ListRoots).
If you like to adhere to just two constraints you can have your lists be
tidied up for you automatically:
1. Link a ListRoot to your list (the For-Each detail above tries to hide the
   presence of ListRoot from your normal work)
2. Always keep the ListRoot in a variable as long as you want the list to be
   existent. When the ListRoot leaves scope, is thus freed, it calls
   List.Clear() in its _free() special method so that all List nodes are
   freed properly. It is possible for a linked ListRoot to get a zero
   reference count because it just doesn't get a ref when in a list - in
   contrast to normal List nodes, as stated above.

You will see how it works in the attached test project.

Bruce, I hope you will never have to write linked lists from scratch
anymore ;-) Tell me if the current implementation is useful if you find
time.

Next are the classes Deque, Stack, Queue and PrioQueue (priority queue)
which are quite self-explanatory and nothing special. Except, maybe, that
they are built on top of the List interface so you can decide if you need to
maintain highly dynamic sort of Deque (use my implementation) or a
fixed-size one (use Variant[] then).

Last so far is the Circular class. It provides a fixed-size circular/ring
buffer with one reader and one writer.

I invite you to try these classes out. Report problems and suggestions. I
haven't read this Knuth so alternate ideas and interfaces are likely to be
around and are welcome!

Benoît, there is a datastructure CLIST_INTF declared in gb.adt/src/c_list.h.
I have not yet worried about GB.GetInterface() or something so please excuse
me taking an unduly independent line. I saw that there already is a
rudimentary linked list in main/share/gb_list_temp.h. I personally use
linked lists quite often and thought it could be part of the interpreter API
just as Memory and Gambas arrays are. What do you think about that?

Regards,
Tobi
»
« Ultima modifica: 13 Giugno 2013, 16:03:19 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Nuovo componente gb.adt con la rev. 5052
« Risposta #1 il: 18 Agosto 2012, 19:38:22 »
Se ho ben capito, trattasi di oggetto multidimensionale, molto simile ad un oggetto presente in Java...

A parte la sua indubbia utilità, a causa del nome mi toccherà cambiare quelli che ho creato nei miei programmi, con nome moooolto simile...  :D :hard:

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.316
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Nuovo componente gb.adt con la rev. 5052
« Risposta #2 il: 18 Agosto 2012, 21:00:01 »
trattasi di oggetto multidimensionale, molto simile ad un oggetto presente in Java...

Puoi dare qualche dettaglio in più al riguardo ?




.... nei miei programmi,

Ole-le, ola-la, facceli vede', facceli tocca' !
 :dj:
« Ultima modifica: 18 Agosto 2012, 21:23:15 da vuott »
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.316
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Nuovo componente gb.adt con la rev. 5052
« Risposta #3 il: 20 Agosto 2012, 00:58:06 »
Minisini così risponde:
« Hi Tobi,

If Deque, Stack... classes can be useful, I'm not sure about your List
and ListRoot classes.

I think you tried to mimic in Gambas the way linked list are implemented
in C: consequently, the Gambas interface is over-complicated.

First, you must know that linked list are far less useful nowadays. As
they trash the CPU cache, using an array is way faster, the speed gain
usually compensating the need for reallocation. Bet let's ignore that point.

I think a List class should have the following interface:
- Create a new List. (_new)
- Put one Variant at the beginning. (Add / Append)
- Put one Variant at the end. (Prepend)
- Enumerate the contents. (_next)
- Have an internal cursor, on which we could do a MoveNext() and
MovePrevious(). (MoveNext, MovePrevious, MoveFirst, MoveLast).
- Have a current item, and be allow to retrieve it. (Current)
- A Count property. (Count)
- An array method to retrieve the i-th element (slowly of course).
(_get), and eventually to modify it (_put)
- Take the current element from the list (i.e. removing it from the list
and returning it). (Take)
- Find a value inside the list. (Find or FindFirst, maybe FindLast too)
- Find a value from the current one, forward or backward. (FindNext,
FindPrevious).

Internally, the List can be managed with a double-linked list of nodes,
each node having a GB_VARIANT_VALUE inside.

But, for performance reasons, it can later be implemented as a
double-linked list of arrays of Variant. Faster, but harder to implement.

As for "embedding" the list inside an object, i.e. doing what we usually
do in C, I think I understood what you want to do, but I don't think it
is really useful in Gambas.

The only advantage I see is being able to find the next (or previous)
object of the list as soon as you have a reference on the object. Which
is not possible with the previous List class.

To do that, maybe I would create another class (something like
'StaticList'). But anyway it will not be easy to have a practical interface!

As for having a list interface in the interpreter API: why not. But it
would be done if this is really useful, as implementation of linked list
is done in a few lines of codes, and usually need to be adapted for
performance reasons. Anyway see '/trunk/main/share/gb_list.h'
and '/trunk/main/share/gb_list_temp.h', which is my own implementation
of embedded linked lists in C.

So tell me what you think.

Regards,

--
Benoît Minisini
»
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »

Offline md9327

  • Moderatore
  • Senatore Gambero
  • *****
  • Post: 2.840
    • Mostra profilo
Re: Nuovo componente gb.adt con la rev. 5052
« Risposta #4 il: 22 Agosto 2012, 01:48:00 »
trattasi di oggetto multidimensionale, molto simile ad un oggetto presente in Java...

Puoi dare qualche dettaglio in più al riguardo ?




.... nei miei programmi,

Ole-le, ola-la, facceli vede', facceli tocca' !
 :dj:
L'oggetto di cui parlo è Vector in Java.
La classe Vector è una classe astratta, da cui si possono derivare classi specializzate di tipo array dinamici di oggetti. Ogni elemento può contenere qualsiasi cosa, in particolare viene uso appunto per contenere determinate classi.

Quello che però sarebbe di utilità enorme, è la possibilità di associare un qualcosa (es. tramite Tag) ad ogni elemento componente ListBox, ComboBox, ColumnView, ecc., ovvero la possibilità di agganciare direttamente ad ognuno degli elementi dell'array contenuto in questo tipo di componenti, un determinato oggetto.
Questo è già fattibile con oggetti grafici base, quali TextBox o altro, ma non negli oggetti con liste.
In altri linguaggi, come ad esempio Java, questo è possibile, e offre enormi potenzialità, dando la possiblità al programmatore di espandere di molto la propria fantasia, senza fare salti pindarici per risolvere problemi di contro banali.

Per fare un esempio, tu pensa alle posibilità offerte da una struttura del genere, applicata ad una GridView, dove ogni modifica viene applicata automaticamente (o quasi) all'oggetto stesso relativo alla riga modificata, mettendo la GridView stessa alla semplice posizione di oggetto puramente grafico, solo per il passaggio di informazioni dall'utente al motore applicativo.
Questo amplierebbe di moltissimo l'uso delle classi, come del resto ho fatto e faccio con altri linguaggi.

Offline vuott

  • Moderatore globale
  • Senatore Gambero
  • *****
  • Post: 11.316
  • Ne mors quidem nos iunget
    • Mostra profilo
Re: Nuovo componente gb.adt con la rev. 5052
« Risposta #5 il: 22 Agosto 2012, 01:51:08 »
Grazie per la precisazione.

   :ciao:
« Chiunque, non ricorrendo lo stato di necessità, nel proprio progetto Gambas fa uso delle istruzioni Shell o Exec, è punito con la sanzione pecuniaria da euro 20,00 a euro 60,00. »