www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to get rid of const / immutable poisoning (and I didn't even want

reply Enjoys Math <enjoysmath gmail.com> writes:
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
next sibling parent reply Enjoys Math <enjoysmath gmail.com> writes:
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
parent ag0aep6g <anonymous example.com> writes:
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
prev sibling parent reply Enjoys Math <enjoysmath gmail.com> writes:
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
parent Kagamin <spam here.lot> writes:
https://dpaste.dzfl.pl/74d67cfca3e8
May 23 2017