Thread overview
Issue with char and string overlap
Jul 19, 2013
JS
Jul 19, 2013
JS
Jul 19, 2013
monarch_dodra
Jul 19, 2013
monarch_dodra
Jul 19, 2013
anonymous
Jul 19, 2013
Ali Çehreli
Jul 19, 2013
H. S. Teoh
July 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();
}
July 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.
July 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();
> }
July 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;
> }
July 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.
July 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.
July 19, 2013
On 07/19/2013 10:40 AM, anonymous wrote:

> On Friday, 19 July 2013 at 17:18:00 UTC, JS wrote:

>>             for(int j = 0; j < s.length - d.length; j++)
>
> This j would shadow the one above. Just choose another name.

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.

Ali