digitalmars.D.learn - How to get rid of const / immutable poisoning (and I didn't even want
- Enjoys Math (7/7) May 22 2017 I had to employ const / immutable to some things to get passed
- Enjoys Math (112/120) May 22 2017 Crap. I hit tab then enter.
- ag0aep6g (42/129) May 22 2017 Marking a whole struct as `immutable` is usually a mistake. It applies
- Enjoys Math (9/16) May 22 2017 Solved it by reverting back to original code (no const /
- Kagamin (1/1) May 23 2017 https://dpaste.dzfl.pl/74d67cfca3e8
I had to employ const / immutable to some things to get passed some compiler errors. Then the poisoning continues. How do I get this code to run? String's will hold a T[] which actually will not be modified by the String methods ("immutable strings of T"). I did not want to use any immutable / const anywhere at first, but by passing in [1,2,3]
May 22 2017
On Monday, 22 May 2017 at 20:12:56 UTC, Enjoys Math wrote:I had to employ const / immutable to some things to get passed some compiler errors. Then the poisoning continues. How do I get this code to run? String's will hold a T[] which actually will not be modified by the String methods ("immutable strings of T"). I did not want to use any immutable / const anywhere at first, but by passing in [1,2,3]Crap. I hit tab then enter. By passing in a constant array which is totally legit for testing reasons, the compiler shits. Here's the code: ------------ module smallest_grammar; import std.conv; import std.algorithm; struct Symbol(T) { public: this(T sym, bool isVar) { this.sym = sym; this.is_var = isVar; } property T symbol() { return sym; } property bool isVar() { return is_var; } private: T sym; bool is_var = false; } immutable struct String(T) { public: this(immutable T[] s) { this.s = s; } alias s this; string toString() const { return to!string(s); } string flattened() const { string t = ""; foreach (c; s) t ~= to!string(c); return t; } size_t toHash() const system pure nothrow { return hashOf(flattened()); } bool opEquals(ref const String t) const system pure nothrow { if (t.length != this.length) return false; for(size_t k=0; k < t.length; k++) if (t.s[k] != this.s[k]) return false; return true; } // A compressible is a substring that occurs (non-overlappingly)=2 and has a length >= 3// or one that occurs >= 3 and has a length of 2 String[] compressibles() const { auto count = compressibleCount(); String[] substrings; foreach (s, n; count) substrings ~= s; return substrings; } size_t[String] compressibleCount() const { auto count = substringCount(2, size_t(s.length / 2)); foreach (str, n; count) if (str.length == 2 && n < 3 || str.length >= 3 && n < 2) count.remove(str); return count; } String[] substrings(int minLen=0, int maxLen=-1) const { auto count = substringCount(); String[] substrings; foreach (s, n; count) substrings ~= s; return substrings; } size_t[String] substringCount(int minLen=0, int maxLen=-1) const { if (maxLen == -1) maxLen = s.length; assert (maxLen <= s.length && minLen >=0 && minLen <= maxLen); size_t[String] count; if (minLen == 0) count[empty] = s.length + 1; for (size_t i=0; i < s.length - minLen; i++) { size_t max_len = min(s.length - i, maxLen); for (size_t l=1; l < max_len; l++) { auto substr = String(this.s[i..i+l]); if (!(substr in count)) count[substr] = 0; else count[substr] ++; } } return count; } public: immutable(T)[] empty = []; private T[] s; } struct Grammar(T) { public: this(string name) { this.name = name; } private: string name; String!(T)[][T] rules; } unittest { import std.stdio; // String auto s = String!string(["1", "2", "34"]); writeln(s); writeln(s.flattened()); // Compressibles s = String!string(["a", "b", "a", "b", "a", "b", "a"]); writeln(s.substrings()); // Grammar auto g = Grammar!string(); writeln("~ End Smallest Grammar unittests ~"); }
May 22 2017
On 05/22/2017 10:13 PM, Enjoys Math wrote:immutable struct String(T) {Marking a whole struct as `immutable` is usually a mistake. It applies to all methods, making them unusable on mutable and const instances.public: this(immutable T[] s) {This means you can create `String`s only with immutable arrays. Again, not what you want usually. You can use `inout` to make a constructor that accepts mutable, const, and immutable arrays when constructing mutable, const, and immutable instances, respectively: ---- this(inout T[] s) inout { ... } ---- If `inout` doesn't work for some reason, you will have to define distinct constructors: ---- this(T[] s) { ... } this(const T[] s) const { ... } this(immutable T[] s) immutable { ... } ----this.s = s; } alias s this; string toString() const { return to!string(s); } string flattened() const { string t = ""; foreach (c; s) t ~= to!string(c); return t; } size_t toHash() const system pure nothrow { return hashOf(flattened()); } bool opEquals(ref const String t) const system pure nothrow { if (t.length != this.length) return false; for(size_t k=0; k < t.length; k++)Off topic: foreach (k; 0 .. t.length)if (t.s[k] != this.s[k]) return false;Seeing how `k` is used, could also make it: ---- foreach (k, e; t) if (e != this.s[k]) return false; ----return true; } // A compressible is a substring that occurs (non-overlappingly) >=2 and has a length >= 3 // or one that occurs >= 3 and has a length of 2 String[] compressibles() const { auto count = compressibleCount(); String[] substrings; foreach (s, n; count) substrings ~= s; return substrings; } size_t[String] compressibleCount() const { auto count = substringCount(2, size_t(s.length / 2));Off topic: substringCount's second parameter is an int, not a size_t. Converting from size_t to int like this works with -m32, but if large values are possible, you've got a bug. With -m64 it simply doesn't work. You can use `to!int` which throws on failure.foreach (str, n; count) if (str.length == 2 && n < 3 || str.length >= 3 && n < 2) count.remove(str); return count; } String[] substrings(int minLen=0, int maxLen=-1) const { auto count = substringCount(); String[] substrings; foreach (s, n; count) substrings ~= s; return substrings; } size_t[String] substringCount(int minLen=0, int maxLen=-1) const { if (maxLen == -1) maxLen = s.length;Same bug-prone conversion from size_t to int as above.assert (maxLen <= s.length && minLen >=0 && minLen <= maxLen); size_t[String] count; if (minLen == 0) count[empty] = s.length + 1;`empty` is not a String, it's a T[]. Works when you change `empty` to `static empty = String([]);`.for (size_t i=0; i < s.length - minLen; i++) { size_t max_len = min(s.length - i, maxLen); for (size_t l=1; l < max_len; l++) { auto substr = String(this.s[i..i+l]);We're in a const method, so `this.s[i..i+l]` is const as well. If you want to return a result with mutable keys, you have to `.dup` that slice of s. Alternatively, drop `const` from the method, or return a result with const keys. Though returning `const` has similar repercussions as returning immutable keys (next paragraphs). Arguably, keys of associative arrays should be immutable. When the keys change and the associative isn't re-hashed, it's going to behave erratically. Making the keys immutable would mean you have to `.idup` the slices. You'd also have `.dup` in `compressibles` and `substring` if they're supposed to return mutable `String`s.if (!(substr in count)) count[substr] = 0; else count[substr] ++; } } return count; } public: immutable(T)[] empty = []; private T[] s; }
May 22 2017
On Monday, 22 May 2017 at 20:12:56 UTC, Enjoys Math wrote:I had to employ const / immutable to some things to get passed some compiler errors. Then the poisoning continues. How do I get this code to run? String's will hold a T[] which actually will not be modified by the String methods ("immutable strings of T"). I did not want to use any immutable / const anywhere at first, but by passing in [1,2,3]Solved it by reverting back to original code (no const / immutable) on struct and creating two constructors: this(T[] s) { this.s = s; } this(const(T)[] s) { this.s = cast(T[]) s; }
May 22 2017