Jump to page: 1 2 3
Thread overview
linked lists and iterators
Jul 20, 2002
Sean L. Palmer
Jul 21, 2002
Patrick Down
Jul 21, 2002
Patrick Down
Jul 21, 2002
Pavel Minayev
Jul 21, 2002
Sean L. Palmer
Jul 23, 2002
Sandor Hojtsy
Jul 23, 2002
Pavel Minayev
Jul 30, 2002
Sandor Hojtsy
Jul 31, 2002
Sean L. Palmer
Jul 31, 2002
Burton Radons
Aug 01, 2002
Sean L. Palmer
Aug 06, 2002
Sandor Hojtsy
Aug 06, 2002
Burton Radons
Aug 11, 2002
Walter
Aug 11, 2002
Sean L. Palmer
Aug 15, 2002
Walter
Aug 11, 2002
Pavel Minayev
Aug 15, 2002
Walter
Aug 15, 2002
Pavel Minayev
Aug 15, 2002
Walter
Aug 15, 2002
Patrick Down
Aug 21, 2002
Sandor Hojtsy
Aug 21, 2002
Pavel Minayev
Aug 21, 2002
Russell Lewis
Aug 21, 2002
Pavel Minayev
Aug 21, 2002
Martin M. Pedersen
Jul 21, 2002
Burton Radons
July 20, 2002
I think we should take another look at the possibility of adding linked lists directly to the language and formalizing the concept of iterator as a basic language feature.  Can this be done?  If so, how?

A linked list is, as you know, a string of pointers

struct T
{
    T* next;
    T* prev;
    int data;
}

{
    T* head = new T;  // I really want constructors for structs!!!!!
    head->data = 0;
    head->next = 0;
    head->prev = 0;

    T* ins = new T;
    ins->data = 1;
    ins->next = 0;
    ins->prev = head;
    head->next = ins;

    T* iter = head;
    while(iter)
    {
        printf("Node %d\n", iter->data);
        iter = iter->next;
    }
}


As you can see, it's extremely boilerplate code.  Lists are so well known that a compiler could use the ultimate best algorithm for manipulating them. And they could be syntactically wrapped so they look more like container/iterator.

It would be easy with generics.  In fact, how you implement list may be a big clue as to how to go about implementing generics.  Maybe something along the lines of:

struct T
{
    int data;
    T(int d) { data = d; }
}

dlist(T) mylist;
mylist.addtail(T(0));
mylist.addtail(T(1));
dlist(T).iterator iter = mylist.head;
while (iter)
{
    printf("Node %d\n",iter->data);
    ++iter;
}

Sean


July 21, 2002
"Sean L. Palmer" <seanpalmer@earthlink.net> wrote in news:ahckjc$6mt$1@digitaldaemon.com:

> I think we should take another look at the possibility of adding linked lists directly to the language and formalizing the concept of iterator as a basic language feature.  Can this be done?  If so, how?

I would like to see the concept of iterators added to the language.

I see two types of operations on on basic arrays and the other a more generalized form.

int[] arr;

for(int i in arr) // i gets successive values from arr
{
  //...
}

class Iter // or struct
{
  bit getNext(out aType i) { }
}

obj = new Iter;

for(aType i in obj) // i gets values from successive calls to getNext
{
  //...
}

The linked list works well this way

struct ListIter
{
  ListNode cur;

  bit getNext(out aType data)
  {
    if(cur.Next)
    {
      data = cur.data;
      return true;
    }
    return false;
  }
}

ListIter iter;
iter.cur = list.head; // I too wish of struct constructors

for(aType i in iter)
{
  //...
}
July 21, 2002
Forgot the cur = cur.Next;  :)

Patrick Down <pat@codemoon.com> wrote in news:Xns9251C45EE91F3patcodemooncom@63.105.9.61:

> struct ListIter
> {
>   ListNode cur;
> 
>   bit getNext(out aType data)
>   {
>     if(cur.Next)
>     {
>       data = cur.data;
        cur = cur.Next;
>       return true;
>     }
>     return false;
>   }
> }
July 21, 2002
On Sat, 20 Jul 2002 14:35:27 -0700 "Sean L. Palmer" <seanpalmer@earthlink.net> wrote:

> It would be easy with generics.  In fact, how you implement list may be a big clue as to how to go about implementing generics.  Maybe something along the lines of:
> 
> struct T
> {
>     int data;
>     T(int d) { data = d; }
> }
> 
> dlist(T) mylist;
> mylist.addtail(T(0));
> mylist.addtail(T(1));
> dlist(T).iterator iter = mylist.head;
> while (iter)
> {
>     printf("Node %d\n",iter->data);
>     ++iter;
> }

Might I propose another syntax?

	int[*] mylist;		// linked list of ints
	mylist ~= 0;		// add to back
	mylist = 1 ~ mylist	// add to front (compiler should optimize this)
	int[*].iterator i;	// or could it be just mylist.iterator?
	for (i = mylist.head; i; i++)
		printf("Node %d\n", *i);

Also, int[*] could be one-directional linked list, while int[**] would be two-directional.

Or is it better to use int[->] and int[<->] for this purpose?
July 21, 2002
Sean L. Palmer wrote:

> I think we should take another look at the possibility of adding linked
> lists directly to the language and formalizing the concept of iterator as a
> basic language feature.  Can this be done?  If so, how?
> 
> A linked list is, as you know, a string of pointers
> 
> struct T
> {
>     T* next;
>     T* prev;
>     int data;
> }
> 
> {
>     T* head = new T;  // I really want constructors for structs!!!!!
>     head->data = 0;
>     head->next = 0;
>     head->prev = 0;
> 
>     T* ins = new T;
>     ins->data = 1;
>     ins->next = 0;
>     ins->prev = head;
>     head->next = ins;
> 
>     T* iter = head;
>     while(iter)
>     {
>         printf("Node %d\n", iter->data);
>         iter = iter->next;
>     }
> }
> 
> 
> As you can see, it's extremely boilerplate code.  Lists are so well known
> that a compiler could use the ultimate best algorithm for manipulating them.
> And they could be syntactically wrapped so they look more like
> container/iterator.


The best generic algorithm with lists tends to be the same as the worst generic algorithm.  There's not a hell of a lot you can optimise.  But they are a useful generic type.


> It would be easy with generics.  In fact, how you implement list may be a
> big clue as to how to go about implementing generics.  Maybe something along
> the lines of:
> 
> struct T
> {
>     int data;
>     T(int d) { data = d; }
> }
> 
> dlist(T) mylist;
> mylist.addtail(T(0));
> mylist.addtail(T(1));
> dlist(T).iterator iter = mylist.head;
> while (iter)
> {
>     printf("Node %d\n",iter->data);
>     ++iter;
> }

-1 linked lists as a language feature, +1 iterators, -1 making it look anything at all like STL's.  I prefer Patrick's method, but using next, and without any special syntax.  A new extension to while, perhaps, to take for-style ';' separators for local variables.  I'm not opposed to for .. in, but getting over the Bright Barrier will require something more general, methinks.

Implementation hm.  I always need first/last, so I want a header, and prefer using List and Node for each:

    struct Node (TypeInfo $type)
    {
        List ($type) *list;
        Node ($type) *next;
        Node ($type) *prev;
        $type value;

        void remove ()
        {
            synchronize (list)
            {
                if (next) next.prev = prev;
                else list.last = prev;
                if (prev) prev.next = next;
                else list.first = next;
                next = prev = null;
            }
        }
    }

    class List (TypeInfo $type)
    {
        Node ($type) *first;
        Node ($type) *last;

        Node ($type) *alloc ()
        {
            return new Node ($type); /* Should use block allocation */
        }

        Node ($type) *append ($type value)
        {
            synchronize (this)
            {
                Node ($type) *node = alloc ();

                node.next = null;
                node.prev = last;
                if (last) last.next = node;
                else first = node;
                last = node;

                return node;
            }
        }

        ListIter ($type) iter ()
        {
            return ListIter ($type) (this);
        }
    }

    struct ListIter (TypeInfo $type)
    {
        List ($type) list;
        Node ($type) *node;

        this (List ($type) list)
        {
            this.list = list;
            node = this.first;
        }

        bit next (out $type value)
        {
            synchronize (list)
            {
                if (!node) return false;
                value = node.value;
                node = node.next;
                return true;
            }
        }

        bit next (out $type *value)
        {
            synchronize (list)
            {
                if (!node) return false;
                value = &node.value;
                node = node.next;
                return true;
            }
        }

        bit next (out Node ($type) *value)
        {
            synchronize (list)
            {
                if (!node) return false;
                value = node;
                node = node.next;
                return true;
            }
        }
    }

Plus many other methods.

July 21, 2002
This sounds fine to me!  ;)  Makes it look almost just like existing dynamic array syntax.

I like int[->] and int[<->] actually.

Is there some kind of search for dynamic array yet?  What about erase entry?

Sean

"Pavel Minayev" <evilone@omen.ru> wrote in message
news:CFN374584471657523@news.digitalmars.com...
On Sat, 20 Jul 2002 14:35:27 -0700 "Sean L. Palmer"
<seanpalmer@earthlink.net>
wrote:

> It would be easy with generics.  In fact, how you implement list may be a big clue as to how to go about implementing generics.  Maybe something
along
> the lines of:
>
> struct T
> {
>     int data;
>     T(int d) { data = d; }
> }
>
> dlist(T) mylist;
> mylist.addtail(T(0));
> mylist.addtail(T(1));
> dlist(T).iterator iter = mylist.head;
> while (iter)
> {
>     printf("Node %d\n",iter->data);
>     ++iter;
> }

Might I propose another syntax?

int[*] mylist; // linked list of ints
mylist ~= 0; // add to back
mylist = 1 ~ mylist // add to front (compiler should optimize this)
int[*].iterator i; // or could it be just mylist.iterator?
for (i = mylist.head; i; i++)
printf("Node %d\n", *i);

Also, int[*] could be one-directional linked list, while int[**] would be two-directional.

Or is it better to use int[->] and int[<->] for this purpose?


July 23, 2002
"Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:ahemp8$25c6$1@digitaldaemon.com...
> I like int[->] and int[<->] actually.

Me too.

> Is there some kind of search for dynamic array yet?  What about erase
entry?

Ha! You do it all "by hand". Reminds me of BASIC times.

Sandor


July 23, 2002
On Tue, 23 Jul 2002 09:35:51 +0200 "Sandor Hojtsy" <hojtsy@index.hu> wrote:

> 
> "Sean L. Palmer" <seanpalmer@earthlink.net> wrote in message news:ahemp8$25c6$1@digitaldaemon.com...
>> I like int[->] and int[<->] actually.
> 
> Me too.
> 
>> Is there some kind of search for dynamic array yet?  What about erase
> entry?
> 
> Ha! You do it all "by hand". Reminds me of BASIC times.

Well, erasing entry is easy:

	// delete Nth element
	array = array[0 .. N] ~ array[N+1 .. array.length];

Still, some syntactic sugar would be great.
July 30, 2002
"Pavel Minayev" <evilone@omen.ru> wrote in message news:CFN374606396220486@news.digitalmars.com...
>>Well, erasing entry is easy:
>>// delete Nth element
>>array = array[0 .. N] ~ array[N+1 .. array.length];
>>Still, some syntactic sugar would be great.

Why do I have the feeling that the underlying implementation for that expression will be slower than it could be for an explicit erase method?

Sandor


July 31, 2002
"Sandor Hojtsy" <hojtsy@index.hu> wrote in message news:ai5klg$273n$1@digitaldaemon.com...
>
> "Pavel Minayev" <evilone@omen.ru> wrote in message news:CFN374606396220486@news.digitalmars.com...
> >>Well, erasing entry is easy:
> >>// delete Nth element
> >>array = array[0 .. N] ~ array[N+1 .. array.length];
> >>Still, some syntactic sugar would be great.
>
> Why do I have the feeling that the underlying implementation for that expression will be slower than it could be for an explicit erase method?

I think you're right... especially in debug builds.

Sean


« First   ‹ Prev
1 2 3