www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why stops this code

reply mitgedanken <sara.dolores.tasche gmail.com> writes:
At ``unittest // ???`` you see what's my problem I don't 
understand.

What I already done:
- Removed ``nothrow``
- Using ``try-catch``

```d
module mitgedanken.parser;

import std.typecons : Tuple;
import std.container : Array;
import std.conv : to;
import std.traits : isSomeString;
import std.string;


struct Symbol
{
     string str;

      property ulong length() const  safe pure nothrow => 
this.str.length;
      property bool empty() const  safe pure nothrow => 
(this.str.length == 0);

     static Symbol asEmpty()  safe pure nothrow
         => Symbol("");

     string toString() const  safe pure nothrow
         => this.str;

     ulong opDollar()
         => this.length;

     T opCast(T : string)() const
         => this.str;

     auto opAssign(T)(T value) if (isSomeString!T)
     {
         this.str = value;
         return this;
     }

     auto opBinary(string op : "~")(string rhs)
     {
         Symbol symbol = Symbol(this.str ~ rhs);
         return symbol;
     }

     auto opOpAssign(string op = "~=", T)(T value) if 
(isSomeString!T)
     {
         this.str ~= value;
         return this;
     }
}

alias NodeRef = NullableNodeRef;
alias RootRef = NodeRef;

alias TreeRef = Tree*;

enum Kind : string
{
     _Undefined_ = "undefined",
     Terminal    = "terminal",
     Leaf        = "leaf",
     Root        = "root",
}

struct NullableNodeRef
{
     private Node* _node;
     alias node = _node;

      property bool  isNull() const pure  safe nothrow => 
(this._node is null);
      property Node* get()          pure  safe nothrow => 
this._node;

      property string getString(const string stringIfNull) const
         => this.isNull ? stringIfNull : this._node.repr();

     this (Node node) nothrow
     {
         this._node = &node;
     }

     this (Node* nodeRef) nothrow
     {
         this._node = nodeRef;
     }

     auto opDispatch(string member)() const
         => mixin("this._node." ~ member);

     auto opDispatch(string member)()
         => mixin("this._node." ~ member);

     bool opEqual(Object other)
         => *this._node == other;

     T opCast(T : Node*)() const
         => this._node;

     static nodeRef(ref Node node)
         => NodeRef(node);
}

NullableNodeRef nullableRef(Node node) nothrow
     => NullableNodeRef(node);

NullableNodeRef nullableRef(Node* node) nothrow
     => NullableNodeRef(node);

interface Representable
{
     string repr();
}

class Node : Representable
{
private:
     int     _precedence;
     TreeRef _tree;
     Kind    _kind;

     Symbol  _symbol;
     NodeRef _root;
     NodeRef _left;
     NodeRef _right;

public:
      property TreeRef tree()        safe pure nothrow => 
this._tree;
      property Symbol  symbol()      safe pure nothrow => 
this._symbol;
      property int     precedence()  safe pure nothrow => 
this._precedence;
      property NodeRef root()        safe pure nothrow => 
this._root;
      property NodeRef left()        safe pure nothrow => 
this._left;
      property NodeRef right()       safe pure nothrow => 
this._right;
      property Kind    kind()        safe pure nothrow => 
this._kind;

      property bool terminates() const  safe pure nothrow => 
!this.isLeaf();

     alias parent = root;

      property void root(NodeRef nodeRef)  safe
     {
         if (!this._root.isNull)
             throw new Error("Root node already exists");

         this._root = nodeRef;
     }

      property void left(NodeRef nodeRef)  safe
     {
         if (!this._left.isNull)
             throw new Error("Left node already exists");

         this._left = nodeRef;
     }

      property void right(NodeRef nodeRef)  safe
     {
         if (!this._right.isNull)
             throw new Error("Right node already exists");

         this._right = nodeRef;
     }

     this(
         TreeRef tree,
         Symbol  symbol,
         int     precedence,
         NodeRef root,
         NodeRef left  = NodeRef.init,
         NodeRef right = NodeRef.init
     )
     {
         this._tree       = tree;
         this._symbol     = symbol;
         this._precedence = precedence;
         this._root       = root;
         this._left       = left;
         this._right      = right;

         _setKind();
     }

     this(TreeRef tree, Symbol symbol, int precedence, NodeRef 
root)
     {
         this._tree       = tree;
         this._symbol     = symbol;
         this._precedence = precedence;
         this._root       = root;

         _setKind();
     }

     this(TreeRef tree, Symbol symbol, int precedence)
     {
         this._tree       = tree;
         this._symbol     = symbol;
         this._precedence = precedence;

         _setKind();
     }

     bool isLeaf() const pure  safe nothrow => this.hasLeft() || 
this.hasRight();
     bool isRoot() const pure  safe nothrow => this._root.isNull 
&& this.isLeaf();

     bool hasParent() const pure  safe nothrow => 
!this._root.isNull;
     bool hasLeft()   const pure  safe nothrow => 
!this._left.isNull;
     bool hasRight()  const pure  safe nothrow => 
!this._right.isNull;

     alias hasRoot = hasParent;

     string repr() const
     {
         string str = "";

         str ~= "\"" ~ this._symbol.str ~ "\"";
         str ~= "(";
         str ~= "prec="    ~ to!string(this._precedence);
         str ~= ", kind="  ~ this._kind;
         str ~= ", root="  ~ this._root.getString("<no root>");
         str ~= ", left="  ~ this._left.getString("<no left 
leaf>");
         str ~= ", right=" ~ this._right.getString("<no right 
leaf>");
         str ~= ")";

         return str;
     }

     private void _setKind()  safe pure nothrow
     {
         if (this.root.isNull)
             this._kind = Kind.Root;
         else if (!this._left.isNull || !this._right.isNull)
             this._kind = Kind.Leaf;
         else
             this._kind = Kind.Terminal;
     }

     //override string toString() const  safe pure nothrow
     //    => this.repr();

     T opCast(T : string)() const
         => this._symbol.str;

     T opCast(T : NodeRef)() const
         => nullableRef(this);

     auto opBinary(string op : "~")(string rhs)
     {
         Node node = new Node(
             this._tree,
             this._symbol ~ rhs,
             this._precedence,
             this._root,
             this._left,
             this._right
         );

         return node;
     }

     auto opBinary(string op : "~")(Node rhs)
     {
         Node node = new Node(
             this._tree,
             this._symbol ~ rhs.symbol.str,
             this._precedence,
             this._root,
             this._left,
             this._right
         );

         return node;
     }

     auto opBinary(string op : "~")(NodeRef rhs)
     {
         Node node = new Node(
             this._tree,
             this._symbol ~ rhs.symbol.str,
             this._precedence,
             this._root,
             this._left,
             this._right
         );

         return NodeRef(node);
     }

     auto opBinary(string op : "~")(NodeRef rhs)
     {
         Node node = new Node(
             this._tree,
             this._symbol ~ rhs.symbol.str,
             this._precedence,
             this._root,
             this._left,
             this._right
         );

         return NodeRef(node);
     }

     override bool opEquals(Object other) const
     {
         if (is(other == Node))
             return false;

         const Node n = cast(Node) other;
         return (n.repr() == this.repr());
     }

     bool opEquals(typeof(null) other) const
         => this._kind != Kind._Undefined_;
}

alias Root = Node;

final class Tree : Representable
{
     private NodeRef _root;
     private ulong   _count;
     private NodeRef _current;

      property NodeRef root()   safe pure nothrow => this._root;
      property ulong   count()  safe pure nothrow => this._count;

      property void root(NodeRef nodeRef)
     {
         this._root = nodeRef;
     }

     void incrementCount(uint byAmountOf = 1)
     {
         this._count += byAmountOf;
     }

     this(Node* root)
     {
         this._root  = NodeRef(root);
         this._count = 0;
     }

     this()
     {
         this._root  = NodeRef.init;
         this._count = 0;
     }

     bool hasRoot() => !this._root.isNull;

     string repr()
     {
         import std.stdio;

         string tree = "";
         Node* curr = this._root.get;

         if (curr.isRoot)
             return "";

         while (!curr.terminates)
         {
             tree ~= curr.repr();

             if (curr.hasLeft())
                 curr = curr.left.get;
             else if (curr.hasRight())
                 curr = curr.right.get;
         }

         if (tree == "" || tree == "\n")
             return "";

         return tree.strip("\n");
     }

     alias toString = repr;
}

unittest // ???
{
     import std.stdio;

     Tree tree = new Tree();
     TreeRef treeRef = &tree;

     Node op  = new Node(treeRef, Symbol("+"), 0);
     // That's fine, the root is displayed
     Node one = new Node(treeRef, Symbol("1"), 0, nullableRef(op));
     Node two = new Node(treeRef, Symbol("2"), 0, nullableRef(op));

     //(1) Execution ends
     op.left  = nullableRef(&one);
     op.right = nullableRef(&two);

     //(2) Execution ends after this, if it is at (1) position
     writeln(two.repr());

     writeln(one.repr());
     writeln(op.repr());

     if (!treeRef.hasRoot())
         treeRef.root = nullableRef(&op);

     //writeln(*treeRef);
     writeln(tree.root.get.hasRight());
}

int main(string[] _)
{
     return 0;
}
```
Apr 25
next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
All classes in D are pointers.

Removing all those extra pointers, got it to run, up until it needs to 
print.

Printing will result in an infinite loop due to your test data.
Apr 25
prev sibling parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Saturday, 25 April 2026 at 18:59:41 UTC, mitgedanken wrote:
 At ``unittest // ???`` you see what's my problem I don't 
 understand.
https://rpa.st/HS26E
Apr 25
next sibling parent mitgedanken <sara.dolores.tasche gmail.com> writes:
Thanks to all.
Apr 27
prev sibling parent reply 0xEAB <desisma heidel.beer> writes:
On 4/25/26 23:49, Dejan Lekic wrote:
 https://rpa.st/HS26E
Please find attached my comment.
May 03
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Sunday, 3 May 2026 at 14:57:51 UTC, 0xEAB wrote:
 On 4/25/26 23:49, Dejan Lekic wrote:
 https://rpa.st/HS26E
Please find attached my comment.
It gives me a **404** now.
May 21
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Thursday, 21 May 2026 at 18:16:00 UTC, mitgedanken wrote:
 On Sunday, 3 May 2026 at 14:57:51 UTC, 0xEAB wrote:
 On 4/25/26 23:49, Dejan Lekic wrote:
 https://rpa.st/HS26E
Please find attached my comment.
It gives me a **404** now.
Apologies, I was too quick paste the code there and forgot to change the expiry setting... Here is the improved code that should work: ```d module mitgedanken.parser; import std.typecons: Tuple; import std.container: Array; import std.conv: to; import std.traits: isSomeString; import std.string; struct Symbol { string str; property ulong length() const safe pure nothrow => this.str.length; property bool empty() const safe pure nothrow => (this.str.length == 0); static Symbol asEmpty() safe pure nothrow => Symbol(""); string toString() const safe pure nothrow => this.str; ulong opDollar() => this.length; T opCast(T : string)() const => this.str; auto opAssign(T)(T value) if (isSomeString!T) { this.str = value; return this; } auto opBinary(string op : "~")(string rhs) { Symbol symbol = Symbol(this.str ~ rhs); return symbol; } auto opOpAssign(string op = "~=", T)(T value) if (isSomeString!T) { this.str ~= value; return this; } } alias NodeRef = NullableNodeRef; alias RootRef = NodeRef; alias TreeRef = Tree*; enum Kind : string { _Undefined_ = "undefined", Terminal = "terminal", Leaf = "leaf", Root = "root", } struct NullableNodeRef { private Node* _node; alias node = _node; property bool isNull() const pure safe nothrow => (this._node is null); property inout(Node)* get() inout pure safe nothrow => this._node; property string getString(const string stringIfNull) const { if (this.isNull) return stringIfNull; return this._node.symbol.str; } // Only keep the safe version that takes a pointer directly this(Node* nodeRef) pure nothrow safe { this._node = nodeRef; } // Safe opDispatch that checks for null auto opDispatch(string member)() const { assert(!isNull, "Attempted to access member '" ~ member ~ "' on null NodeRef"); return mixin("this._node." ~ member); } bool opEquals(const NullableNodeRef other) const pure safe nothrow => this._node is other._node; bool opEquals(typeof(null)) const pure safe nothrow => this._node is null; size_t toHash() const pure safe nothrow { return cast(size_t)cast(void*)this._node; } T opCast(T : Node*)() const pure safe nothrow => this._node; static NodeRef nodeRef(Node* node) pure safe nothrow => NodeRef(node); } NullableNodeRef nullableRef(Node* node) pure nothrow safe => NullableNodeRef(node); interface Representable { string repr() const; } class Node : Representable { private: int _precedence; TreeRef _tree; Kind _kind; Symbol _symbol; NodeRef _root; NodeRef _left; NodeRef _right; public: property TreeRef tree() safe pure nothrow => this._tree; property Symbol symbol() const safe pure nothrow => this._symbol; property int precedence() const safe pure nothrow => this._precedence; property NodeRef root() safe pure nothrow => this._root; property NodeRef left() safe pure nothrow => this._left; property NodeRef right() safe pure nothrow => this._right; property Kind kind() const safe pure nothrow => this._kind; // A node terminates traversal if it's a leaf (no children) property bool terminates() const safe pure nothrow => this.isLeaf(); alias parent = root; property void root(NodeRef nodeRef) safe { if (!this._root.isNull) throw new Error("Root node already exists"); this._root = nodeRef; } property void left(NodeRef nodeRef) safe { if (!this._left.isNull) throw new Error("Left node already exists"); this._left = nodeRef; } property void right(NodeRef nodeRef) safe { if (!this._right.isNull) throw new Error("Right node already exists"); this._right = nodeRef; } this( TreeRef tree, Symbol symbol, int precedence, NodeRef root, NodeRef left = NodeRef.init, NodeRef right = NodeRef.init ) { this._tree = tree; this._symbol = symbol; this._precedence = precedence; this._root = root; this._left = left; this._right = right; _setKind(); } this(TreeRef tree, Symbol symbol, int precedence, NodeRef root) { this._tree = tree; this._symbol = symbol; this._precedence = precedence; this._root = root; _setKind(); } this(TreeRef tree, Symbol symbol, int precedence) { this._tree = tree; this._symbol = symbol; this._precedence = precedence; this._root = NodeRef.init; this._left = NodeRef.init; this._right = NodeRef.init; _setKind(); } // Fixed: A leaf node has NO children bool isLeaf() const pure safe nothrow => !this.hasLeft() && !this.hasRight(); // Fixed: A root node has no parent and has children (is not a leaf) bool isRoot() const pure safe nothrow => this._root.isNull && !this.isLeaf(); bool hasParent() const pure safe nothrow => !this._root.isNull; bool hasLeft() const pure safe nothrow => !this._left.isNull; bool hasRight() const pure safe nothrow => !this._right.isNull; alias hasRoot = hasParent; string repr() const { string str = ""; str ~= "\"" ~ this._symbol.str ~ "\""; str ~= "("; str ~= "prec=" ~ to!string(this._precedence); str ~= ", kind=" ~ this._kind; str ~= ", root=" ~ this._root.getString("<no root>"); str ~= ", left=" ~ this._left.getString("<no left leaf>"); str ~= ", right=" ~ this._right.getString("<no right leaf>"); str ~= ")"; return str; } private void _setKind() safe pure nothrow { if (this._root.isNull && (this._left.isNull && this._right.isNull)) this._kind = Kind.Root; else if (this._root.isNull) this._kind = Kind.Root; else if (!this._left.isNull || !this._right.isNull) this._kind = Kind.Leaf; else this._kind = Kind.Terminal; } T opCast(T : string)() const => this._symbol.str; auto opBinary(string op : "~")(string rhs) { Node node = new Node( this._tree, this._symbol ~ rhs, this._precedence, this._root, this._left, this._right ); return node; } auto opBinary(string op : "~")(Node rhs) { Node node = new Node( this._tree, this._symbol ~ rhs.symbol.str, this._precedence, this._root, this._left, this._right ); return node; } auto opBinary(string op : "~")(NodeRef rhs) { Node node = new Node( this._tree, this._symbol ~ rhs.symbol.str, this._precedence, this._root, this._left, this._right ); return NodeRef(&node); } override bool opEquals(Object other) const { // Fixed: Use runtime cast check instead of compile-time is() const Node n = cast(Node)other; if (n is null) return false; return (n.repr() == this.repr()); } // Fixed: Added toHash to match opEquals override override size_t toHash() const safe nothrow { size_t hash = 0; foreach (c; this._symbol.str) { hash = hash * 31 + c; } hash = hash * 31 + this._precedence; return hash; } } alias Root = Node; final class Tree : Representable { private NodeRef _root; private ulong _count; private NodeRef _current; property NodeRef root() safe pure nothrow => this._root; property ulong count() safe pure nothrow => this._count; property void root(NodeRef nodeRef) { this._root = nodeRef; } void incrementCount(uint byAmountOf = 1) { this._count += byAmountOf; } this(Node* root) { this._root = NodeRef(root); this._count = 0; } this() { this._root = NodeRef.init; this._count = 0; } bool hasRoot() const => !this._root.isNull; string repr() const { string tree = ""; if (this._root.isNull) return ""; Node* curr = cast(Node*)this._root.get; if (curr is null) return ""; // Traverse down the tree while (curr !is null && !curr.terminates) { tree ~= curr.repr(); tree ~= "\n"; if (curr.hasLeft()) curr = curr.left.get; else if (curr.hasRight()) curr = curr.right.get; else break; } // Include the terminal node if (curr !is null) tree ~= curr.repr(); if (tree == "" || tree == "\n") return ""; return tree.strip(); } alias toString = repr; } // Test basic tree construction and node relationships unittest { import std.stdio; Tree tree = new Tree(); TreeRef treeRef = &tree; // Create operator node (will be root) Node op = new Node(treeRef, Symbol("+"), 0); // Create operand nodes with op as their parent Node one = new Node(treeRef, Symbol("1"), 0, nullableRef(&op)); Node two = new Node(treeRef, Symbol("2"), 0, nullableRef(&op)); // Link children to operator op.left = nullableRef(&one); op.right = nullableRef(&two); // Set tree root if (!treeRef.hasRoot()) treeRef.root = nullableRef(&op); // Verify node relationships assert(one.isLeaf(), "one should be a leaf (no children)"); assert(two.isLeaf(), "two should be a leaf (no children)"); assert(!op.isLeaf(), "op should not be a leaf (has children)"); assert(one.hasParent(), "one should have a parent"); assert(two.hasParent(), "two should have a parent"); assert(!op.hasParent(), "op should not have a parent"); assert(one.terminates(), "leaf nodes should terminate"); assert(two.terminates(), "leaf nodes should terminate"); assert(!op.terminates(), "root with children should not terminate"); assert(op.hasLeft(), "op should have left child"); assert(op.hasRight(), "op should have right child"); assert(tree.hasRoot(), "tree should have root"); writeln("Basic tree test passed!"); writeln("op: ", op.repr()); writeln("one: ", one.repr()); writeln("two: ", two.repr()); } // Test Symbol operations unittest { Symbol s = Symbol("hello"); assert(s.length == 5); assert(!s.empty); assert(s.toString() == "hello"); Symbol s2 = s ~ " world"; assert(s2.str == "hello world"); Symbol empty = Symbol.asEmpty(); assert(empty.empty); assert(empty.length == 0); } // Test NullableNodeRef unittest { Tree tree = new Tree(); TreeRef treeRef = &tree; Node n = new Node(treeRef, Symbol("test"), 0); NodeRef ref1 = nullableRef(&n); assert(!ref1.isNull); assert(ref1.get is &n); NodeRef ref2 = NodeRef.init; assert(ref2.isNull); assert(ref2 == null); // Test equality NodeRef ref3 = nullableRef(&n); assert(ref1 == ref3); assert(ref1 != ref2); } // Test Node equality unittest { Tree tree = new Tree(); TreeRef treeRef = &tree; Node n1 = new Node(treeRef, Symbol("x"), 0); Node n2 = new Node(treeRef, Symbol("x"), 0); Node n3 = new Node(treeRef, Symbol("y"), 0); assert(n1 == n2, "Nodes with same repr should be equal"); assert(n1 != n3, "Nodes with different symbols should not be equal"); } // Test Tree repr unittest { Tree tree = new Tree(); TreeRef treeRef = &tree; // Empty tree assert(tree.repr() == ""); // Single node tree Node single = new Node(treeRef, Symbol("single"), 0); tree.root = nullableRef(&single); string r = tree.repr(); assert(r.length > 0, "Single node tree should have repr"); } // Test node concatenation unittest { Tree tree = new Tree(); TreeRef treeRef = &tree; Node n1 = new Node(treeRef, Symbol("hello"), 0); Node n2 = n1 ~ " world"; assert(n2.symbol.str == "hello world"); } int main(string[] _) { return 0; } ``` What is different: 1. **`isLeaf()` logic was inverted** — Original had `hasLeft() || hasRight()` (a node with children is a "leaf" — wrong). Fixed to `!hasLeft() && !hasRight()` (a leaf has *no* children). 2. **`isRoot()` logic was wrong** — Original had `root.isNull && isLeaf()` (a root must be a leaf — contradictory). Fixed to `root.isNull && !isLeaf()` (a root has no parent *and* has children). 3. **`terminates()` logic was inverted** — Original had `!isLeaf()`. With the corrected `isLeaf()`, this would mean non-leaf nodes terminate, which is also wrong. Fixed to `isLeaf()` — leaf nodes terminate traversal. 4. **`NullableNodeRef.opDispatch` null safety** — Original had no null check, so accessing a member on a null ref would crash. Fixed version asserts `!isNull` before dispatching. 5. **`NullableNodeRef.opEquals` was wrong** — Original used `opEqual(Object)` (not the right D pattern) and compared via `*this._node == other`. Fixed to proper `opEquals(NullableNodeRef)` and `opEquals(typeof(null))` overloads with pointer identity comparison, plus `toHash()`. 6. **`Node.opEquals` used `is(other == Node)` incorrectly** — `is()` in D is a compile-time type check, not a runtime one. It always evaluated the same way. Fixed to `cast(Node)other is null` for a proper runtime null check. Also added `toHash()` override to keep `opEquals`/`toHash` contract consistent. 7. **`NullableNodeRef` stored a value, not a pointer** — The original constructor `this(Node node)` took a stack-local class reference by value (`&node` on a class gives `Node**`-style confusion, but for a class it's actually a reference already). The `this(Node* nodeRef)` overload was correct. The value constructor was removed, keeping only the pointer version. `get()` return type also changed to `inout(Node)*`. 8. **`Tree.repr()` null safety** — Original called `this._root.get` without checking for null, and used `curr.isRoot` to return early (but `isRoot` was broken). Fixed version checks `this._root.isNull` and `curr is null` before proceeding. 9. **`getString` changed** — Original called `this._node.repr()` (the node's full debug representation). Fixed to `this._node.symbol.str` (just the symbol string), which is more appropriate for display in `Node.repr()`. 10. **Removed `opEquals(typeof(null))` on `Node`** — The original had `this._kind != Kind._Undefined_` as a null comparison, which didn't make semantic sense. Removed entirely. 11. **Removed duplicate `opBinary` overload** — The original had two identical `opBinary!"~"(NodeRef)` overloads. One was removed.
May 22
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Friday, 22 May 2026 at 09:45:54 UTC, Dejan Lekic wrote:
 On Thursday, 21 May 2026 at 18:16:00 UTC, mitgedanken wrote:
 On Sunday, 3 May 2026 at 14:57:51 UTC, 0xEAB wrote:
 On 4/25/26 23:49, Dejan Lekic wrote:
 https://rpa.st/HS26E
Please find attached my comment.
It gives me a **404** now.
Apologies, I was too quick paste the code there and forgot to change the expiry setting... Here is the improved code that should work: [...]
**Thank you!** Do you have some optimisation tips?
May 23
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
[program killed by signal 11 (segmentation violation) / 
run.dlang.io](https://run.dlang.io/?compiler=dmd&args=-unittest%20-main&source=void%20main()%0A%7B%0A%20%20%20%20import%20std.concurrency;%0A%20%20%20%20import%20std.stdio:%20write,%20writeln,%20writef,%20writefln;%0A%20%20%20%20%23line%201%0Aauto%20tid%20%3D%20spawn(%7B%0A%20%20%20%20%20%20%20%20int%20i;%0A%20%20%20%20%20%20%20%20while%20(i%20%3C%209)%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20receiveOnly!int;%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20ownerTid.send(i%20*%202);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20auto%20r%20%3D%20new%20Generator!int(%7B%0A%20%20%20%20%20%20%20%20foreach%20(i;%201%20..%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20yield(i);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20foreach%20(e;%20r)%0A%20%20%20%20%20%20%20%20tid.send(e);%0A%20%20%20%20%0A%20%20%20%20writeln(receiveOnly!int);%20%2F%2F%2018%0A%20%20%20%20%0A%20%20%20%20%0A%7D)
May 24
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Sunday, 24 May 2026 at 13:13:59 UTC, mitgedanken wrote:
 [program killed by signal 11 (segmentation violation) / 
 run.dlang.io](https://run.dlang.io/?compiler=dmd&args=-unittest%20-main&source=void%20main()%0A%7B%0A%20%20%20%20import%20std.concurrency;%0A%20%20%20%20import%20std.stdio:%20write,%20writeln,%20writef,%20writefln;%0A%20%20%20%20%23line%201%0Aauto%20tid%20%3D%20spawn(%7B%0A%20%20%20%20%20%20%20%20int%20i;%0A%20%20%20%20%20%20%20%20while%20(i%20%3C%209)%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20receiveOnly!int;%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20ownerTid.send(i%20*%202);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20auto%20r%20%3D%20new%20Generator!int(%7B%0A%20%20%20%20%20%20%20%20foreach%20(i;%201%20..%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20yield(i);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20foreach%20(e;%20r)%0A%20%20%20%20%20%20%20%20tid.send(e);%0A%20%20%20%20%0A%20%20%20%20writeln(receiveOnly!int);%20%2F%2F%2018%0A%20%20%20%20%0A%20%20%20%20%0A%7D)
Something with the `TreeCrawler`(?).
May 24
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Sunday, 24 May 2026 at 13:18:28 UTC, mitgedanken wrote:
 On Sunday, 24 May 2026 at 13:13:59 UTC, mitgedanken wrote:
 [program killed by signal 11 (segmentation violation) / 
 run.dlang.io](https://run.dlang.io/?compiler=dmd&args=-unittest%20-main&source=void%20main()%0A%7B%0A%20%20%20%20import%20std.concurrency;%0A%20%20%20%20import%20std.stdio:%20write,%20writeln,%20writef,%20writefln;%0A%20%20%20%20%23line%201%0Aauto%20tid%20%3D%20spawn(%7B%0A%20%20%20%20%20%20%20%20int%20i;%0A%20%20%20%20%20%20%20%20while%20(i%20%3C%209)%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20receiveOnly!int;%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20ownerTid.send(i%20*%202);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20auto%20r%20%3D%20new%20Generator!int(%7B%0A%20%20%20%20%20%20%20%20foreach%20(i;%201%20..%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20yield(i);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20foreach%20(e;%20r)%0A%20%20%20%20%20%20%20%20tid.send(e);%0A%20%20%20%20%0A%20%20%20%20writeln(receiveOnly!int);%20%2F%2F%2018%0A%20%20%20%20%0A%20%20%20%20%0A%7D)
Something with the `TreeCrawler`(?).
At line 304. What's wrong?
May 24
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Sunday, 24 May 2026 at 13:23:04 UTC, mitgedanken wrote:
 On Sunday, 24 May 2026 at 13:18:28 UTC, mitgedanken wrote:
 On Sunday, 24 May 2026 at 13:13:59 UTC, mitgedanken wrote:
 [program killed by signal 11 (segmentation violation) / 
 run.dlang.io](https://run.dlang.io/?compiler=dmd&args=-unittest%20-main&source=void%20main()%0A%7B%0A%20%20%20%20import%20std.concurrency;%0A%20%20%20%20import%20std.stdio:%20write,%20writeln,%20writef,%20writefln;%0A%20%20%20%20%23line%201%0Aauto%20tid%20%3D%20spawn(%7B%0A%20%20%20%20%20%20%20%20int%20i;%0A%20%20%20%20%20%20%20%20while%20(i%20%3C%209)%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20receiveOnly!int;%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20ownerTid.send(i%20*%202);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20auto%20r%20%3D%20new%20Generator!int(%7B%0A%20%20%20%20%20%20%20%20foreach%20(i;%201%20..%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20yield(i);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20foreach%20(e;%20r)%0A%20%20%20%20%20%20%20%20tid.send(e);%0A%20%20%20%20%0A%20%20%20%20writeln(receiveOnly!int);%20%2F%2F%2018%0A%20%20%20%20%0A%20%20%20%20%0A%7D)
Something with the `TreeCrawler`(?).
At line 304. What's wrong?
I rewrote it: [ github](https://github.com/eureka-euphoria/parser)
May 24
parent reply mitgedanken <sara.dolores.tasche gmail.com> writes:
On Sunday, 24 May 2026 at 19:00:16 UTC, mitgedanken wrote:
 On Sunday, 24 May 2026 at 13:23:04 UTC, mitgedanken wrote:
 [program killed by signal 11 (segmentation violation) / 
 run.dlang.io](https://run.dlang.io/?compiler=dmd&args=-unittest%20-main&source=void%20main()%0A%7B%0A%20%20%20%20import%20std.concurrency;%0A%20%20%20%20import%20std.stdio:%20write,%20writeln,%20writef,%20writefln;%0A%20%20%20%20%23line%201%0Aauto%20tid%20%3D%20spawn(%7B%0A%20%20%20%20%20%20%20%20int%20i;%0A%20%20%20%20%20%20%20%20while%20(i%20%3C%209)%0A%20%20%20%20%20%20%20%20%20%20%20%20i%20%3D%20receiveOnly!int;%0A%20%20%20%20%0A%20%20%20%20%20%20%20%20ownerTid.send(i%20*%202);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20auto%20r%20%3D%20new%20Generator!int(%7B%0A%20%20%20%20%20%20%20%20foreach%20(i;%201%20..%2010)%0A%20%20%20%20%20%20%20%20%20%20%20%20yield(i);%0A%20%20%20%20%7D);%0A%20%20%20%20%0A%20%20%20%20foreach%20(e;%20r)%0A%20%20%20%20%20%20%20%20tid.send(e);%0A%20%20%20%20%0A%20%20%20%20writeln(receiveOnly!int);%20%2F%2F%2018%0A%20%20%20%20%0A%20%20%20%20%0A%7D)
Wrong link 8) Anyway, check out the GitHub link.
May 24
parent reply Dejan Lekic <dejan.lekic gmail.com> writes:
On Sunday, 24 May 2026 at 21:50:28 UTC, mitgedanken wrote:
 Wrong link 8)
 Anyway, check out the GitHub link.
There are many issues with the code here are the most serious ones: Stack Locals, Not GC Objects This is the **fundamental design flaw** in the entire module. In D, `class` is a reference type. `Node n = new Node(...)` puts `n` (a reference) on the stack and the object on the GC heap. `&n` gives you a `Node*` — a pointer to the **stack-local reference**, not to the GC object. ```d Tree tree = new Tree(); TreePtr treeRef = &tree; // pointer to stack-local `tree` Node op = new Node(treeRef, Symbol("+"), 0); Node one = new Node(treeRef, Symbol("1"), 0, nullableNode(&op)); // ^^ // address of stack-local `op` ``` When `op` goes out of scope, `one._root._node` is a **dangling pointer**. The unittests happen to work because everything is in the same scope, but as library code this is **undefined behavior**. **The fix:** `Node` is already a reference type. `Node` references are already nullable (`Node n = null`). The entire `NullableNode` struct is unnecessary — you could just use `Node` directly: ```d // Instead of NullableNode wrapping Node*: Node _root; // already nullable, already a reference to the GC object ``` --- Dangling Pointer ```d auto opBinary(string op : "~")(NullableNode rhs) { Node node = new Node( this._tree, this._symbol ~ rhs.symbol.str, this._precedence, this._root, this._left, this._right ); return NullableNode(&node); // ← node is LOCAL, &node dangles after return } ``` `node` is a local variable. `&node` points to the stack frame. After the function returns, the `NullableNode` holds a dangling pointer — immediate use-after-free. --- Not Object Identity ```d size_t toHash() const pure nothrow safe { return cast(size_t)cast(void*)this._node; } ``` This hashes the address of the *reference variable on the stack*, not the identity of the GC heap object. Two `NullableNode`s referencing the same `Node` object through different local variables will have different hashes: ```d Node n1 = new Node(...); Node n2 = n1; // same object auto a = nullableNode(&n1); auto b = nullableNode(&n2); assert(a == b); // FALSE — different stack addresses! ``` `opEquals` also compares with `is` (pointer equality), so this same bug means two references to the same object through different variables are considered **not equal**. --- ```d override bool opEquals(Object other) const { return (n.repr() == this.repr()); // repr() includes children, parent } override size_t toHash() const nothrow safe { // only hashes symbol + precedence } ``` If you mutate a `Node`'s children after inserting it into an associative array, `toHash` stays the same but `opEquals` changes, violating the AA invariant. The hash and equality must agree on what constitutes identity. --- Node as `Branch` ```d if (!this.hasParent && this.hasLeft && this.hasRight) this._kind = Kind.Root; // requires BOTH children else if (this.hasLeft || this.hasRight) this._kind = Kind.Branch; // any children + parent → branch ``` A node with no parent and only one child gets classified as `Branch`, not `Root`. This is probably wrong — a node at the top of a tree with a single child should be a `Root`. --- ```d while (curr !is null && !curr.isLeaf) { if (curr.hasLeft()) curr = curr.left.node; // always prefers left else if (curr.hasRight()) curr = curr.right.node; } ``` This traverses only the leftmost path, ignoring entire right subtrees. A proper tree representation needs to visit all nodes (pre-order, in-order, post-order, or level-order). --- ```d int opApply(scope int delegate(ref NodePtr) dg) { if (auto node = this._state._current) { if (node.hasLeft) { /* visit left child */ } if (node.hasRight) { /* visit right child */ } } return 0; } ``` This only visits the immediate children of the current node — it doesn't recursively traverse the tree. As a "crawler" it's misleading. It also mutates `_state._current` during iteration, making the crawler stateful in a confusing way.
Jun 07
parent reply Andy Valencia <dont spam.me> writes:
On Sunday, 7 June 2026 at 12:40:49 UTC, Dejan Lekic wrote:
 On Sunday, 24 May 2026 at 21:50:28 UTC, mitgedanken wrote:
 Anyway, check out the GitHub link.
There are many issues with the code here are the most serious ones: ...
This is a very nice commentary based on his reading of your code. As an old C guy, I have deep and long experience with pointers. In D, I almost never use them because of that knowledge! I try very hard to use class objects, ref, and out parameters instead. I'm pretty I've yet to do pointer arithmetic. My code doesn't run as fast as it could--but I don't care. Life is too short to be chasing SEGV's and memory corruption. Arrays, indices, and slices for me. Andy
Jun 07
parent "H. S. Teoh" <hsteoh qfbox.info> writes:
On Sun, Jun 07, 2026 at 02:32:45PM +0000, Andy Valencia via Digitalmars-d-learn
wrote:
[...]
 As an old C guy, I have deep and long experience with pointers.  In D,
 I almost never use them because of that knowledge!  I try very hard to
 use class objects, ref, and out parameters instead.  I'm pretty I've
 yet to do pointer arithmetic.
I'm also a C guy, I debug and write C code for a living. I also have deep and long experience with pointers, pointer bugs, and memory corruption issues. I've actually done some pointer arithmetic in D, but it's pretty rare. Most of the time you don't have to care about raw pointers in D. Just use slices and classes, otherwise pass by (const) ref if you have a *really* big struct. (But D lends itself to better code design, so you rarely end up with the code smell that your struct is too big to pass by value. Most of the time you pass by ref only because you actually need to mutate the caller's copy of the value.)
 My code doesn't run as fast as it could--but I don't care.
Premature optimization is an inherent part of C culture, unfortunately. The language just forces you to think in terms that unconsciously drives you want to optimize the last cycles out of your code, even when it's completely irrelevant. It took me several embarrassing experiences of thinking I knew best how to optimize something, only for the profiler to show me that I'm TOTALLY off, to cure me of this syndrome. Nowadays I still keep an eye on performance, but for the most part, I don't bother optimizing unless it's deep inside an inner loop that's actually hot. Most of the time the difference doesn't really matter THAT much. It's only when you're dealing with things like a hard deadline (e.g. 60fps, you only have 16.7ms to do all of your processing per iteration), or a compute-intensive task where performance can mean the difference between getting the answer 2 hours later vs. 2 weeks later, then I'll profile and look into optimizing my inner loops. Even then, from my experience, most D code does not require you to go to raw pointer level to maximize performance. I've seen up to 2x to 3x performance boost just by simple 1-2 line tweaks: eliminating unnecessary allocations like reusing a buffer provided by the caller instead of allocating inside a function, locating Schlemiel's hiding places in the code and replacing them with non-quadratic algorithms, etc.. In fact, I've yet to encounter a case in D where using raw pointers was necessary for performance reasons. I did wrote raw pointer code a few times, just for comparison's sake, but have yet to find a case where it provided a significant advantage.
 Life is too short to be chasing SEGV's and memory corruption.  Arrays,
 indices, and slices for me.
[...] Yeah!! After 3 decades of dealing with constant pointer bugs, off-by-1 errors, buffer overflows, dangling pointers, double-frees, enough is enough. I still do it for my day job, because, well, it's C. But outside of that? No thank you, give me GC any day. The haters will hate, but GC is a true godsend. Not only it eliminates an entire class of memory bugs (with no effort!), it also frees my brain from constant obsession about memory management issues and actually make progress in my problem domain. My APIs become cleaner, free of hairy frilly memory management paraphrenalia that sprout everywhere in C APIs, and my code becomes much cleaner and easier to follow. Less bugs, faster development times. I met D many years ago and am still in love. ;-) T -- Only boring people get bored. -- JM
Jun 07