www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Should std.range.primitives.ElementType have sig constraints?

reply "H. S. Teoh via Digitalmars-d" <digitalmars-d puremagic.com> writes:
Currently, std.range.primitives.ElementType has no sig constraints, so
it will pick up all sorts of things that aren't ranges.  This is not so
nice, because ranges aren't the only thing that have elements, and it
would be nice if such a good name as ElementType could be reused for
other user-defined generic constructs.

For example, I wrote some generic code for working with 2D scalar
fields (i.e., arbitrary objects that define opIndex(double,double)), and
defined an ElementType template specific to fields:

	template ElementType(F)
		if (is2DField!F)
	{
		alias ElementType = typeof(F.init[0.0, 0.0]);
	}

However, this causes a conflict wherever I import std.range, since
std.range.primitives.ElementType matches *everything*, including 2D
field objects that have no resemblance whatsoever to ranges, only to
return `void`. Shouldn't ElementType be constrained to only those types
that it understands?

I dug through the git history, and it seems that ElementType has always
been defined this way, ever since Andrei first committed the
implementation of range primitives. The original docs did not mention
anything about picking up all types; that comment (part of the current
docs) was added much later by someone else.

What was the rationale for having no sig constraints for ElementType?
Was it an oversight? Doesn't seem like it, since it explicitly returns
`void` for non-range types. What's the purpose of that?  Would it be
acceptable to modify the definition of ElementType to:

	template ElementType(R)
		if (isInputRange!R)
	{ ... }

?


T

-- 
Любишь кататься - люби и саночки возить. 
Jan 20
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Wednesday, 20 January 2016 at 18:54:34 UTC, H. S. Teoh wrote:
 Currently, std.range.primitives.ElementType has no sig 
 constraints, so it will pick up all sorts of things that aren't 
 ranges.  This is not so nice, because ranges aren't the only 
 thing that have elements, and it would be nice if such a good 
 name as ElementType could be reused for other user-defined 
 generic constructs.

 For example, I wrote some generic code for working with 2D 
 scalar
 fields (i.e., arbitrary objects that define 
 opIndex(double,double)), and
 defined an ElementType template specific to fields:

 	template ElementType(F)
 		if (is2DField!F)
 	{
 		alias ElementType = typeof(F.init[0.0, 0.0]);
 	}

 However, this causes a conflict wherever I import std.range, 
 since std.range.primitives.ElementType matches *everything*, 
 including 2D field objects that have no resemblance whatsoever 
 to ranges, only to return `void`. Shouldn't ElementType be 
 constrained to only those types that it understands?

 I dug through the git history, and it seems that ElementType 
 has always been defined this way, ever since Andrei first 
 committed the implementation of range primitives. The original 
 docs did not mention anything about picking up all types; that 
 comment (part of the current docs) was added much later by 
 someone else.

 What was the rationale for having no sig constraints for 
 ElementType? Was it an oversight? Doesn't seem like it, since 
 it explicitly returns `void` for non-range types. What's the 
 purpose of that?  Would it be acceptable to modify the 
 definition of ElementType to:

 	template ElementType(R)
 		if (isInputRange!R)
 	{ ... }
I'm not sure that I'd consider it a good idea to reuse the name ElementType elsewhere given how pervasive std.range.primitives.ElementType is in code, but I don't see any reason why it shouldn't have a template constraint on it, and if it does, the module system would allow you to reuse the name. But even if we all agreed that reusing the name was a bad idea, the error messages when ElementType was misused would definitely be better if it had a template constraint no it. So, I see no problem with adding a constraint. - Jonathan M Davis
Jan 20