Thread overview | |||||||
---|---|---|---|---|---|---|---|
|
May 22, 2017 How to get rid of const / immutable poisoning (and I didn't even want to use them...) | ||||
---|---|---|---|---|
| ||||
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 Re: How to get rid of const / immutable poisoning (and I didn't even want to use them...) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Enjoys Math | 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 Re: How to get rid of const / immutable poisoning (and I didn't even want to use them...) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Enjoys Math | 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 Re: How to get rid of const / immutable poisoning (and I didn't even want to use them...) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Enjoys Math | 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 23, 2017 Re: How to get rid of const / immutable poisoning (and I didn't even want to use them...) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Enjoys Math | https://dpaste.dzfl.pl/74d67cfca3e8 |
Copyright © 1999-2021 by the D Language Foundation