www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Linked list, printing looks destructive.

reply Alain De Vod <devosalain ymail.com> writes:
Following program is a single linked list.
We expect as output 1 2 3 1 2 3
But the output is only 1 2 3
I think this has something to do with popFront
How to fix it using "class List" ?

```
import std.stdio: write,writeln;
import std.range: empty,popFront,front;

struct Node {
	int element;
	Node * next;
}

class List {
	Node * root=null;
	this(int[] AR){foreach(i ; AR)pushfront(i);}
	bool empty() const {return !root;}
	void popFront() {root=root.next;}
	float front() const {return root.element;}
	void pushfront(int element) {
		Node * newnode=new Node();
		newnode.element=element;
		newnode.next=root;
		root=newnode;
	}
}//List

void main(){
	List l=new List([3,2,1]);
	foreach(element; l) writeln(element);
	foreach(element; l) writeln(element);
}

```
Apr 24 2022
next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 4/24/22 18:40, Alain De Vod wrote:

 I think this has something to do with popFront
This type violates a fundamental rule: Containers and ranges are separate concepts. Your List is a container, not a range. I changed your code by moving the range functions to a Range struct that is created by opSlice(): class List { Node * root=null; this(int[] AR){foreach(i ; AR)pushfront(i);} auto opSlice() { return Range(root); } static struct Range { Node * root_; bool empty() const {return !root_;} void popFront() {root_=root_.next;} float front() const {return root_.element;} } void pushfront(int element) { Node * newnode=new Node(); newnode.element=element; newnode.next=root; root=newnode; } }//List The foreach loop implicitly calls opSlice() and it all works.[1] When you want a range, you can call opSlice indirectly by using [] after the object: import std.algorithm; writeln(l[].map!(e => e * 2)); Ali [1] As reported recently by Steven Schveighoffer, this information is missing in my book: https://bitbucket.org/acehreli/ddili/issues/33/add-additional-foreach-mechanism-to-range
Apr 24 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 25 April 2022 at 02:19:46 UTC, Ali Çehreli wrote:
 This type violates a fundamental rule: Containers and ranges 
 are separate concepts. Your List is a container, not a range. I 
 changed your code by moving the range functions to a Range [...]
Dear Ali, I implemented a linkedlist over classical logic (*_leaf and const *_root). Now seeing the ranges approach I tried it but without success. The following implementation can work with foreach() though; as long as you call goRoot() :) ```d class List(dType) { struct Node { dType item; Node* next; } bool FIFO; private Node * _leaf; this(bool FIFO = true, dType item = dType.init) { this.FIFO = FIFO; if(FIFO) _leaf= new Node(item, null); _root = cast(const)_leaf; } /* auto opSlice() { return Range(_leaf); } static struct Range {//*/ const Node * _root; auto empty() { return !_leaf; } auto popFront() { return _leaf = _leaf.next; } dType front(Node * node = null) { dType result; if(node) { result = (*node).item; } else result = (*_leaf).item; return result; } //} alias Next = popFront; alias pop = front; alias push = InsertBack; void InsertBack(dType item) { _leaf = new Node(item, _leaf); } void InsertFront(dType item) { (*_leaf).next = new Node(item, null); Next; } auto goRoot() { return _leaf = cast(Node*)_root.next; } } import std.stdio; enum FIFO { False, True } enum end = 20; void main() { int firstNumber = 10; auto FIFO_Stack = new List!int; with(FIFO_Stack) { do { InsertFront(firstNumber); } while(++firstNumber <= end); goRoot(); do pop.writef!" %s"; while(Next); writeln; } FIFO_Stack.goRoot(); foreach(stack; FIFO_Stack) { stack.writeln; } } /* OUTPUT: 10 11 12 13 14 15 16 17 18 19 20 10 11 12 13 14 15 16 17 18 19 20 */ ``` SDB 79
Apr 24 2022
parent reply Alain De Vos <devosalain ymail.com> writes:
On Monday, 25 April 2022 at 05:17:28 UTC, Salih Dincer wrote:
 On Monday, 25 April 2022 at 02:19:46 UTC, Ali Çehreli wrote:
 This type violates a fundamental rule: Containers and ranges 
 are separate concepts. Your List is a container, not a range. 
 I changed your code by moving the range functions to a Range 
 [...]
Dear Ali, I implemented a linkedlist over classical logic (*_leaf and const *_root). Now seeing the ranges approach I tried it but without success. The following implementation can work with foreach() though; as long as you call goRoot() :) ```d class List(dType) { struct Node { dType item; Node* next; } bool FIFO; private Node * _leaf; this(bool FIFO = true, dType item = dType.init) { this.FIFO = FIFO; if(FIFO) _leaf= new Node(item, null); _root = cast(const)_leaf; } /* auto opSlice() { return Range(_leaf); } static struct Range {//*/ const Node * _root; auto empty() { return !_leaf; } auto popFront() { return _leaf = _leaf.next; } dType front(Node * node = null) { dType result; if(node) { result = (*node).item; } else result = (*_leaf).item; return result; } //} alias Next = popFront; alias pop = front; alias push = InsertBack; void InsertBack(dType item) { _leaf = new Node(item, _leaf); } void InsertFront(dType item) { (*_leaf).next = new Node(item, null); Next; } auto goRoot() { return _leaf = cast(Node*)_root.next; } } import std.stdio; enum FIFO { False, True } enum end = 20; void main() { int firstNumber = 10; auto FIFO_Stack = new List!int; with(FIFO_Stack) { do { InsertFront(firstNumber); } while(++firstNumber <= end); goRoot(); do pop.writef!" %s"; while(Next); writeln; } FIFO_Stack.goRoot(); foreach(stack; FIFO_Stack) { stack.writeln; } } /* OUTPUT: 10 11 12 13 14 15 16 17 18 19 20 10 11 12 13 14 15 16 17 18 19 20 */ ``` SDB 79
I implemented an alternative goroot it's called re_init and next program works. Still I don't understand what is really going on. Some state is lost using a class and you have restore it. And the state is not lost using a struct. ``` cat test.d import std.stdio: write,writeln; import std.range: empty,popFront,front; struct Node { int element; Node * next; } class List { Node * root=null; Node * walker=null; this(int[] AR){foreach(i ; AR)pushfront(i);} bool empty() const {return !walker;} void popFront() {walker=walker.next;} float front() const {return walker.element;} void pushfront(int element) { Node * newnode=new Node(); newnode.element=element; newnode.next=root; root=newnode; re_init(); } void re_init(){walker=root;} }//List void main(){ List l=new List([3,2,1]); l.writeln(); l.re_init(); l.writeln(); } ```
Apr 25 2022
parent reply Alain De Vos <devosalain ymail.com> writes:
This program works ok, (but List is no Range)

```
class Node {
	int data;
	Node next;
}

class List {
	Node node=null;
	this(int[] AR){foreach(i ; AR)pushfront(i);}
	bool empty() const {return !node;}
	void popFront() {node=node.next;}
	float front() const {return node.data;}
	void pushfront(int data) {
		Node newnode=new Node();
		newnode.data=data;
		newnode.next=node;
		node=newnode;
	}
		
}//List

void main(){
	List l=new List([3,2,1]);
	Node backupnode=l.node;
	l.writeln();
	l.node=backupnode;//Restore state destroyed by writeln
	l.writeln();
}
```
Apr 25 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Monday, 25 April 2022 at 09:38:05 UTC, Alain De Vos wrote:
 This program works ok, (but List is no Range)
It is also possible with the copy constructor of a struct. I don't know how to do with class... ```d struct Node { int element; Node * next; } struct List { Node * root, walker; this(int[] AR) { foreach(i; AR) { pushfront(i); } } bool empty() const { return !walker; } void popFront() { walker = walker.next; } float front() const { return walker.element; } void pushfront(int element) { Node * newnode = new Node(); newnode.element = element; newnode.next = root; root = newnode; } // shallow copy this(ref return scope List that) { this.walker = that.root; } }//List import std.stdio; void main() { List list = List([3,2,1]); //Node backupnode=l.node; foreach(l; list) l.writeln(); //l.node=backupnode;//Restore state destroyed by writeln foreach(l; list) l.writeln(); } ``` SDB 79
Apr 25 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 4/25/22 03:48, Salih Dincer wrote:

 It is also possible with the copy constructor of a struct. I don't know
 how to do with class...
Classes don't have language provided construction because nobody needs it and in fact they have to protect themselves when a language provides it. (See, e.g. C++'s slicing problem: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rc-copy-virtual ) [1] In case you want to copy a class object, you must provide a function yourself, which may be called anything you want or 'dup' to match with a name used by D. Ali Off-topic rant: It frustrates me when C++ programmers shun D because it is "a language with reference types" as told to me by a well-known C++ speaker. I guess they should attempt to read C++'s core guidelines to understand how a polymorphic class makes it an accident to pass its objects by value.
Apr 25 2022
prev sibling parent reply cc <cc nevernet.com> writes:
On Monday, 25 April 2022 at 01:40:01 UTC, Alain De Vod wrote:
 Following program is a single linked list.
 We expect as output 1 2 3 1 2 3
 But the output is only 1 2 3
 ```
If you don't need List to be treated as a true range, but just want to iterate, a simple way to do this is with opApply: https://tour.dlang.org/tour/en/gems/opdispatch-opapply ```d import std.stdio: write,writeln; import std.range: empty,popFront,front; struct Node { int element; Node * next; } class List { Node * root=null; this(int[] AR){foreach(i ; AR)pushfront(i);} bool empty() const {return !root;} /*void popFront() {root=root.next;} float front() const {return root.element;}*/ void pushfront(int element) { Node * newnode=new Node(); newnode.element=element; newnode.next=root; root=newnode; } int opApply(int delegate(typeof(Node.element)) dg) { Node* current = root; while (current) { if (dg(current.element)) return 1; // stop iteration if the foreach body asks to break current = current.next; } return 0; } }//List void main(){ List l=new List([3,2,1]); foreach(element; l) writeln(element); foreach(element; l) writeln(element); } // 1 2 3 1 2 3 ```
Apr 25 2022
parent Alain De Vos <devosalain ymail.com> writes:
Indeed code below works,
```
import std.stdio: write,writeln;

class Node {
	int data;
	Node next;
}

class List {
	Node node=null;
	this(int[] AR){foreach(i ; AR)pushfront(i);}
	void pushfront(int data) {
		Node newnode=new Node();
		newnode.data=data;
		newnode.next=node;
		node=newnode;
	}//pushfront
	int opApply(int delegate(typeof(Node.data)) dg) {
		Node current = node;
		while (current) {
			if (dg(current.data)) return 1;
			current = current.next;
		}
		return 0;
	}//opApply
}//List

void main(){
	List l=new List([3,2,1]);
	foreach(element; l) writeln(element);
	foreach(element; l) writeln(element);
}//main
```
Apr 25 2022