digitalmars.D - Should std.range.primitives.ElementType have sig constraints?
- H. S. Teoh via Digitalmars-d (34/34) Jan 20 2016 Currently, std.range.primitives.ElementType has no sig constraints, so
- Jonathan M Davis (11/46) Jan 20 2016 I'm not sure that I'd consider it a good idea to reuse the name
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 2016
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 2016