digitalmars.D.learn - Issue with char and string overlap
- JS (88/88) Jul 19 2013 I'm trying to create a split function that can handle both char
- JS (4/92) Jul 19 2013 BTW, I'd like to have a default value for d. That or efficiently
- monarch_dodra (21/24) Jul 19 2013 To answer your previous question about shadowing, you are
- monarch_dodra (15/103) Jul 19 2013 Simply provide a default parameter for *one* of the functions. EG:
- anonymous (5/53) Jul 19 2013 i and oldj should probably be size_t. The same for other ints
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (8/11) Jul 19 2013 Even better:
- H. S. Teoh (8/27) Jul 19 2013 ^^
I'm trying to create a split function that can handle both char and string delims. I initially created two separate functions but this doesn't work for default parameters since the compiler doesn't know which one to choose(but in this case both would work fine and it would be nice to inform the compiler of that). I then tried to template and conditionally code the two but it still doesn't work: both functions work separately but when i uncomment the string version I get an error about the string version shadowing. import std.stdio, std.cstream; string[] split(T)(string s, T d) if (is(T == char) || is(T == string)) { int i = 0, oldj = 0; bool ok = true; string[] r; foreach(j, c; s) { static if (is(T == char)) { if (c == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j]; i++; oldj = j+1; ok = false; } else if (!ok) ok = true; } else if (is(T == string)) { /* for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (i == r.length) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } */ } } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } string[] splitS(string s, string d = " ") { int i = 0, oldj = 0; bool ok = true; string[] r; for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } void main(string[] args) { auto s = splitS("abc bas ccc", " "); foreach(a; s) writeln(a); din.getc(); }
Jul 19 2013
On Friday, 19 July 2013 at 17:18:00 UTC, JS wrote:I'm trying to create a split function that can handle both char and string delims. I initially created two separate functions but this doesn't work for default parameters since the compiler doesn't know which one to choose(but in this case both would work fine and it would be nice to inform the compiler of that). I then tried to template and conditionally code the two but it still doesn't work: both functions work separately but when i uncomment the string version I get an error about the string version shadowing. import std.stdio, std.cstream; string[] split(T)(string s, T d) if (is(T == char) || is(T == string)) { int i = 0, oldj = 0; bool ok = true; string[] r; foreach(j, c; s) { static if (is(T == char)) { if (c == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j]; i++; oldj = j+1; ok = false; } else if (!ok) ok = true; } else if (is(T == string)) { /* for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (i == r.length) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } */ } } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } string[] splitS(string s, string d = " ") { int i = 0, oldj = 0; bool ok = true; string[] r; for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } void main(string[] args) { auto s = splitS("abc bas ccc", " "); foreach(a; s) writeln(a); din.getc(); }BTW, I'd like to have a default value for d. That or efficiently allow for variadic d, which then the default delim could easily be tested for.
Jul 19 2013
On Friday, 19 July 2013 at 17:25:34 UTC, JS wrote:BTW, I'd like to have a default value for d. That or efficiently allow for variadic d, which then the default delim could easily be tested for.To answer your previous question about shadowing, you are probably experiencing an old bug where you can't overload a template and non-template. This was fixed in HEAD, but is not yet available in a packaged version (eg, it is not in 2.063.2). The standard workaround is declaring your function as a "parameter-less parameterized function (!)" string[] split()(string s, string d); //This is actually a template. If you want d to be variadic, while still having a default case, any number of solutions are available, including simply doing this: string[] split()(string s); (1*) string[] split(Args...)(string s, Args args); (2) (1) is "more specialized" (I think), so will be considered the better match for "split("hello")". IF I'm wrong, simply add "if (Args.length > 0)" as a template restriction for the second function, and you are good to go. If you have access to head, then declare (1) as a straight up function. In that case, it most certainly *will* be the better match.
Jul 19 2013
On Friday, 19 July 2013 at 17:18:00 UTC, JS wrote:I'm trying to create a split function that can handle both char and string delims. I initially created two separate functions but this doesn't work for default parameters since the compiler doesn't know which one to choose(but in this case both would work fine and it would be nice to inform the compiler of that).Simply provide a default parameter for *one* of the functions. EG: string[] split(string s, char d = ' '); string[] split(string s, string d); This lifts the ambiguity. If *both* have default params, then the ambiguity is simply not solvable, even by a human being. Another solution is the "no default multiple sig" option, eg: string[] split(string s) { return split(s, ' '); } string[] split(string s, char d); string[] split(string s, string d); PS: Are you doing this to learn? std.array.split does the same thing for you.I then tried to template and conditionally code the two but it still doesn't work: both functions work separately but when i uncomment the string version I get an error about the string version shadowing. import std.stdio, std.cstream; string[] split(T)(string s, T d) if (is(T == char) || is(T == string)) { int i = 0, oldj = 0; bool ok = true; string[] r; foreach(j, c; s) { static if (is(T == char)) { if (c == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j]; i++; oldj = j+1; ok = false; } else if (!ok) ok = true; } else if (is(T == string)) { /* for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (i == r.length) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } */ } } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } string[] splitS(string s, string d = " ") { int i = 0, oldj = 0; bool ok = true; string[] r; for(int j = 0; j < s.length - d.length; j++) { if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; } void main(string[] args) { auto s = splitS("abc bas ccc", " "); foreach(a; s) writeln(a); din.getc(); }
Jul 19 2013
On Friday, 19 July 2013 at 17:18:00 UTC, JS wrote:both functions work separately but when i uncomment the string version I get an error about the string version shadowing. import std.stdio, std.cstream; string[] split(T)(string s, T d) if (is(T == char) || is(T == string)) { int i = 0, oldj = 0; bool ok = true;i and oldj should probably be size_t. The same for other ints throughout.string[] r; foreach(j, c; s)The first j is declared here.{ static if (is(T == char)) { if (c == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j]; i++; oldj = j+1; ok = false; } else if (!ok) ok = true; } else if (is(T == string)) { /* for(int j = 0; j < s.length - d.length; j++)This j would shadow the one above. Just choose another name.{ if (s[j..j + d.length] == d) { if (!ok) { oldj++; continue; } if (i == r.length) r.length += 5; r[i] = s[oldj..j - d.length + 1]; i++; oldj = j + d.length; ok = false; } else if (!ok) ok = true; } */ } } if (oldj < s.length) { if (r.length <= i) r.length++; r[i] = s[oldj..$]; i++; } r.length = i; return r; }
Jul 19 2013
On 07/19/2013 10:40 AM, anonymous wrote:On Friday, 19 July 2013 at 17:18:00 UTC, JS wrote:Even better: foreach (k; 0 .. s.length - d.length) or: foreach (k; iota(s.length - d.length)) Also, either code must deal with the case where d.length is greater than s.length. Otherwise, being a size_t, the subtraction will be a large value. Alifor(int j = 0; j < s.length - d.length; j++)This j would shadow the one above. Just choose another name.
Jul 19 2013
On Fri, Jul 19, 2013 at 07:17:57PM +0200, JS wrote: [...]string[] split(T)(string s, T d) if (is(T == char) || is(T == string)) { int i = 0, oldj = 0; bool ok = true; string[] r; foreach(j, c; s) { static if (is(T == char)) { if (c == d) { if (!ok) { oldj++; continue; } if (r.length <= i) r.length += 5; r[i] = s[oldj..j]; i++; oldj = j+1; ok = false; } else if (!ok) ok = true; } else if (is(T == string))^^ This should be "else static if", otherwise it will probably not do what you expect. :) T -- There are two ways to write error-free programs; only the third one works.
Jul 19 2013