I posted the following code on rosettacode.org for the task of converting Arabic and Roman numerals.
import std.regex, std.array, std.algorithm;
immutable {
int[] weights = [1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1];
string[] symbols = ["M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX",
"V", "IV", "I"];
}
string toRoman(int n) {
auto app = appender!string;
foreach (i, w; weights) {
while (n >= w) {
app.put(symbols[i]);
n -= w;
}
if (n == 0) break;
}
return app.data;
}
int toArabic(string s) {
int arabic;
foreach (m; match(s, "CM|CD|XC|XL|IX|IV|[MDCLXVI]")) {
arabic += weights[symbols.indexOf(m.hit)];
}
return arabic;
}
It used to work just fine, but now I get a compiler error.
Error: template std.algorithm.indexOf(alias pred = "a == b",R1,R2) if (is(typeof(startsWith!(pred)(haystack,needl e)))) does not match any function template declaration
According to the documentation indexOf is deprecated, and countUntil should be used in stead, but it gives me the same error.
Long story but I'll try to keep it short:
std.algorithm.indexOf
expects an input range, which is a structural type that must define front
, popFront()
and empty
. For arrays, these methods are defined in std.array and work via uniform function call syntax, which allows fun(someArray)
to work the same as someArray.fun()
.
immutable string[]
is not an input range, since popFront
removes the first element of the array, which cannot be done for an immutable type. The fact that this used to work was a bug.
I've updated the Rosetta Code entry to change symbols
to an immutable(string)[]
. Here, the elements of symbols
are immutable, but the array may be sliced and reassigned. For example:
void main() {
immutable string[] s1 = ["a", "b", "c"];
immutable(string)[] s2 = ["d", "e", "f"];
s2 = s2[1..$]; // This is what std.array.popFront does under the hood.
assert(s2 == ["e", "f"]); // Passes.
s2[1] = "g"; // Error: Can't modify immutable data.
s1 = s1[1..$]; // Error: Can't modify immutable data.
s1[1] = "g"; // Error: Can't modify immutable data.
}
immutable string[]
is implicitly convertible to immutable(string)[]
but implicit function template instantiation (often denoted IFTI; this is what's used to instantiate the indexOf
template) is not smart enough try this.
I believe this is a bug in std.algorithm
. If you remove the immutable
qualifier, the code works as is. I think indexOf
/countUntil
should work on immutable
arrays, but at the moment it does not.
You can make them manifest constants (precede each declaration with enum
) and it appears to work. Amusingly, this may also be a bug.
Apologies for the breakage; I introduced it. I concur with dsimcha's description and proposed fix.
We are considering a simple change to the language to account for this simple case. That would automatically peel off one level of qualifiers when passing a value of a qualified type into a function. By that (for now hypothetical) rule, qualifier(T[]) would become (when passed to a function) qualifier(T)[] and qualifier(T*) would become qualifier(T)*. This would allow your example to work. The disadvantage is that a function would not be able to distinguish the top-level qualifier but I believe that that does not harm any concrete use.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With