digitalmars.D - RFC: std.*.concept convention
- Jakob Ovrum (63/63) Feb 11 2015 ------------
- Rikki Cattermole (3/61) Feb 11 2015 As long as the std.concept package get's good documentation, I think its...
- Jakob Ovrum (11/13) Feb 11 2015 In the spirit of type concepts as a federation of types, not a
- Rikki Cattermole (2/8) Feb 11 2015 I'm not too concerned. Gets the same job done.
- ketmar (2/2) Feb 11 2015 i like the idea. "concept programming" rocks, and having concept checker...
- Jonathan M Davis via Digitalmars-d (15/24) Feb 11 2015 I think that the idea is a good one, and this isn't the first time that ...
- Jakob Ovrum (7/16) Feb 11 2015 My opinion is the opposite. I've never seen anyone use the term
- Jonathan M Davis via Digitalmars-d (7/17) Feb 11 2015 We have a whole module full of them - std.traits - so we're already usin...
- Jakob Ovrum (18/27) Feb 11 2015 There is a difference between a concept and a trait. A concept
- Jonathan M Davis via Digitalmars-d (13/23) Feb 11 2015 _Every_ trait is just a "checker template" - be it isInputRange,
- Baz (9/9) Feb 11 2015 Hello, I remember the first post about this, a few monthes ago,
- Brad Anderson (6/18) Feb 11 2015 +1. Makes a lot of sense to do it this way.
- David Gileadi (6/23) Feb 11 2015 My uneducated feeling is that if there's a clear dividing line as to
- "Ola Fosheim =?UTF-8?B?R3LDuHN0YWQi?= (18/18) Feb 12 2015 Just make sure that what is implemented is what is needed.
------------ Preface ------------ I'd like to start by saying that this is a relatively low-impact enhancement in the short term, but should pay off in the long term. It also requires very little effort, so it is low-hanging fruit, although it requires some foresight to see the benefit. ------------ Primer of type concepts for the uninitiated (skip if you know this stuff) ------------ In D we have the idea of a type concept. Current notable concepts are the range concept and the container concept. The idea is that any type that satisfies the operations of a certain usage pattern can be said to satisfy a certain type concept, and thus be usable in algorithms that use a permutation of said usage pattern. The operations making up a type concept are called the primitives of the concept. For example, for a type to satisfy the input range concept, the following usage pattern must compile: --- R r; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range of non-void type --- The three required operations for the input range concept are the front, empty and popFront primitives. In addition there may be certain restrictions on runtime behaviour; for example, `front` should never be called on an empty range. For convenient verification of a type satisfying a concept, we have concept checker templates such as isInputRange[1]. ------------ Suggestion ------------ Lately there is a trend of splitting up modules into packages in Phobos. Notably, std.range and std.container have been split up into packages. Currently all the range concept checkers are defined in a module std.range.primitives, bundled with the UFCS implementations of the range primitives for in-built slice types. Containers do not (yet) have concept checkers, but I consider it likely we'll see them in the future, as we see more generic container algorithms as well as higher-order containers. Additionally, Andrei has suggested a new type RefCountedSlice!T that presents the same dynamic array interface of T[], but with a reference-counted backend in lieu of the GC backend of T[]. It is conceivable that generic array algorithms may want to accept either type, and thus the "dynamic slice" concept is born. Putting the complexity of the container concept aside; I think we should factor out the concept checkers from std.range.primitives and put them in std.range.concept and establish a convention of using modules named std.*.concept for concept checkers in the future. The consistency gained by such a convention makes type concepts easier to understand and commonly used module names easier to remember. If we do it now, there is no breakage, as the splitting of std.range has not yet been released: hence the otherwise clumsy timing of this suggestion. It is very little work, but anticipating complaints of bike-shedding if I didn't explain myself, I decided to post here first. I'd like to get some feedback before I file a PR. [1] http://dlang.org/phobos/std_range#isInputRange
Feb 11 2015
On 11/02/2015 9:00 p.m., Jakob Ovrum wrote:------------ Preface ------------ I'd like to start by saying that this is a relatively low-impact enhancement in the short term, but should pay off in the long term. It also requires very little effort, so it is low-hanging fruit, although it requires some foresight to see the benefit. ------------ Primer of type concepts for the uninitiated (skip if you know this stuff) ------------ In D we have the idea of a type concept. Current notable concepts are the range concept and the container concept. The idea is that any type that satisfies the operations of a certain usage pattern can be said to satisfy a certain type concept, and thus be usable in algorithms that use a permutation of said usage pattern. The operations making up a type concept are called the primitives of the concept. For example, for a type to satisfy the input range concept, the following usage pattern must compile: --- R r; // can define a range object if (r.empty) {} // can test for empty r.popFront(); // can invoke popFront() auto h = r.front; // can get the front of the range of non-void type --- The three required operations for the input range concept are the front, empty and popFront primitives. In addition there may be certain restrictions on runtime behaviour; for example, `front` should never be called on an empty range. For convenient verification of a type satisfying a concept, we have concept checker templates such as isInputRange[1]. ------------ Suggestion ------------ Lately there is a trend of splitting up modules into packages in Phobos. Notably, std.range and std.container have been split up into packages. Currently all the range concept checkers are defined in a module std.range.primitives, bundled with the UFCS implementations of the range primitives for in-built slice types. Containers do not (yet) have concept checkers, but I consider it likely we'll see them in the future, as we see more generic container algorithms as well as higher-order containers. Additionally, Andrei has suggested a new type RefCountedSlice!T that presents the same dynamic array interface of T[], but with a reference-counted backend in lieu of the GC backend of T[]. It is conceivable that generic array algorithms may want to accept either type, and thus the "dynamic slice" concept is born. Putting the complexity of the container concept aside; I think we should factor out the concept checkers from std.range.primitives and put them in std.range.concept and establish a convention of using modules named std.*.concept for concept checkers in the future. The consistency gained by such a convention makes type concepts easier to understand and commonly used module names easier to remember. If we do it now, there is no breakage, as the splitting of std.range has not yet been released: hence the otherwise clumsy timing of this suggestion. It is very little work, but anticipating complaints of bike-shedding if I didn't explain myself, I decided to post here first. I'd like to get some feedback before I file a PR. [1] http://dlang.org/phobos/std_range#isInputRangeAs long as the std.concept package get's good documentation, I think its a damn good idea!
Feb 11 2015
On Wednesday, 11 February 2015 at 08:21:40 UTC, Rikki Cattermole wrote:As long as the std.concept package get's good documentation, I think its a damn good idea!In the spirit of type concepts as a federation of types, not a hierarchy of types, I think std.*.concept, such as std.range.concept, is more appropriate than an std.concept package. It would be the intuitive go-to module for documenting the concept, including abstract information, which we've had a hard time working into the reference documentation so far. To wit, the documentation for std.range defers to Andrei's informit.com article on ranges.
Feb 11 2015
On 11/02/2015 9:47 p.m., Jakob Ovrum wrote:On Wednesday, 11 February 2015 at 08:21:40 UTC, Rikki Cattermole wrote:I'm not too concerned. Gets the same job done.As long as the std.concept package get's good documentation, I think its a damn good idea!In the spirit of type concepts as a federation of types, not a hierarchy of types, I think std.*.concept, such as std.range.concept, is more appropriate than an std.concept package.
Feb 11 2015
i like the idea. "concept programming" rocks, and having concept checkers=20 in well-defined places too.=
Feb 11 2015
On Wednesday, February 11, 2015 08:00:53 Jakob Ovrum via Digitalmars-d wrote:Putting the complexity of the container concept aside; I think we should factor out the concept checkers from std.range.primitives and put them in std.range.concept and establish a convention of using modules named std.*.concept for concept checkers in the future. The consistency gained by such a convention makes type concepts easier to understand and commonly used module names easier to remember. If we do it now, there is no breakage, as the splitting of std.range has not yet been released: hence the otherwise clumsy timing of this suggestion.I think that the idea is a good one, and this isn't the first time that it's been suggested, but I think that it would be more consistent if we used the term traits rather than the term concepts. We really haven't been using the term concepts for anything in D, and instead have been heavily using the term traits for what you're talking about - e.g. isInputRange is considered to be a trait. In addition, we probably don't want to confuse them with C++'s concepts. Much as they're similar, they're quite not the same thing. So, if we go this route, I think that it should be std.*.traits and not std.*.concept. But I think that the idea is a solid one, particularly because it allows us to import the traits for use in template constraints without having to import any of the functions related to them, and then those functions can be imported as appropriate with local imports. - Jonathan M Davis
Feb 11 2015
On Wednesday, 11 February 2015 at 08:54:41 UTC, Jonathan M Davis wrote:We really haven't been using the term concepts for anything in D, and instead have been heavily using the term traits for what you're talking about - e.g. isInputRange is considered to be a trait.My opinion is the opposite. I've never seen anyone use the term "traits", but I have seen the term "concept".In addition, we probably don't want to confuse them with C++'s concepts. Much as they're similar, they're quite not the same thing.The implementation differs in the details but the idea is exactly the same. Using the same term is helpful for people who are familiar with C++ concepts.
Feb 11 2015
On Wednesday, February 11, 2015 08:59:30 Jakob Ovrum via Digitalmars-d wrote:On Wednesday, 11 February 2015 at 08:54:41 UTC, Jonathan M Davis wrote:We have a whole module full of them - std.traits - so we're already using that term in Phobos, whereas you won't find the term concepts in there anywhere. And you seem to be looking for exactly the same thing except in specific areas - ranges, containers, etc. - rather than having all them sitting in std.traits. - Jonathan M DavisWe really haven't been using the term concepts for anything in D, and instead have been heavily using the term traits for what you're talking about - e.g. isInputRange is considered to be a trait.My opinion is the opposite. I've never seen anyone use the term "traits", but I have seen the term "concept".
Feb 11 2015
On Wednesday, 11 February 2015 at 09:11:18 UTC, Jonathan M Davis wrote:We have a whole module full of them - std.traits - so we're already using that term in Phobos, whereas you won't find the term concepts in there anywhere. And you seem to be looking for exactly the same thing except in specific areas - ranges, containers, etc. - rather than having all them sitting in std.traits.There is a difference between a concept and a trait. A concept can be composed of multiple traits. In the context of a concept, these traits could be called primitives. Saying that `isInputRange` is a trait is just clumsy. It's a checker template. You could rephrase it and say that it's a checker template for the input range trait; but it doesn't check for a single distinguishing quality[1], it checks if all of a number of traits are present. Querying whether or not a type has "the input range trait" is just plain linguistically awkward. Using the term concept puts us in line with C++, the biggest - perhaps the only - competitor D has in the field of template metaprogramming, which surely aids learning. Indeed, even the Wikipedia article on C++ concepts[2] seems like a good resource for understanding the same idea we have in D. [1] http://www.merriam-webster.com/dictionary/trait [2] https://en.wikipedia.org/wiki/Concepts_%28C%2B%2B%29
Feb 11 2015
On Wednesday, February 11, 2015 09:30:12 Jakob Ovrum via Digitalmars-d wrote:There is a difference between a concept and a trait. A concept can be composed of multiple traits. In the context of a concept, these traits could be called primitives. Saying that `isInputRange` is a trait is just clumsy. It's a checker template. You could rephrase it and say that it's a checker template for the input range trait; but it doesn't check for a single distinguishing quality[1], it checks if all of a number of traits are present._Every_ trait is just a "checker template" - be it isInputRange, isDynamicArray, isInteger, isSomeString, hasLength, etc. In all cases, they're checking something about a type. I don't see anything different about isInputRange from hasLength or isPointer except for what they're checking for, and that's different for every trait. And some of the traits in std.traits are quite complicated, so it's not like the ones in there are simple, and the ones elsewhere in Phobos are complex.Querying whether or not a type has "the input range trait" is just plain linguistically awkward.I don't see why you'd even need to talk that way. It's not a question of whether something has the input range trait or whether something has the input range concept. It's a question of whether something _is_ an input range, and the trait isInputRange checks that. - Jonathan M Davis
Feb 11 2015
Hello, I remember the first post about this, a few monthes ago, and the concept of concept is interesting. Do you think it'll be possible to extract a collection of delegate from an agregate which verifies a concept ? - get the concept from an interface - check if this concept is in a struct - extract the concept methods from the struct => almost polymorphic struct ! Don't know if it's clear.
Feb 11 2015
On Wednesday, 11 February 2015 at 08:00:54 UTC, Jakob Ovrum wrote:[snip] Putting the complexity of the container concept aside; I think we should factor out the concept checkers from std.range.primitives and put them in std.range.concept and establish a convention of using modules named std.*.concept for concept checkers in the future. The consistency gained by such a convention makes type concepts easier to understand and commonly used module names easier to remember. If we do it now, there is no breakage, as the splitting of std.range has not yet been released: hence the otherwise clumsy timing of this suggestion. [snip]+1. Makes a lot of sense to do it this way. I prefer "concept" over "trait". I think of traits as more primitive building blocks. With a trait you are querying information about a type. With a concept you are fitting a type to its requirements.
Feb 11 2015
On 2/11/15 12:47 PM, Brad Anderson wrote:On Wednesday, 11 February 2015 at 08:00:54 UTC, Jakob Ovrum wrote:My uneducated feeling is that if there's a clear dividing line as to what is a trait and what is a concept—for instance if they have different syntax—then it makes sense to have two names. Otherwise I think it makes more sense to have just one. Fuzzy categorization tends to hurt.[snip] Putting the complexity of the container concept aside; I think we should factor out the concept checkers from std.range.primitives and put them in std.range.concept and establish a convention of using modules named std.*.concept for concept checkers in the future. The consistency gained by such a convention makes type concepts easier to understand and commonly used module names easier to remember. If we do it now, there is no breakage, as the splitting of std.range has not yet been released: hence the otherwise clumsy timing of this suggestion. [snip]+1. Makes a lot of sense to do it this way. I prefer "concept" over "trait". I think of traits as more primitive building blocks. With a trait you are querying information about a type. With a concept you are fitting a type to its requirements.
Feb 11 2015
Just make sure that what is implemented is what is needed. I have gone over std.traits to see what is used in phobos and the following constraints appears not to be used at all: hasNested isAbstractClass isBasicType isBuiltinType isFinalClass isNested isTypeTuple isUnsafe And these only once: isCovariantWith isExpressionTuple isFinalFunction isInstanceOf isScalarType ...
Feb 12 2015