digitalmars.D.learn - Help needed to learn templates
- Vinod K Chandran (33/33) Mar 18 2022 Hi all,
- Salih Dincer (29/36) Mar 19 2022 You don't need anything extra while using it...
- Vinod K Chandran (3/3) Mar 19 2022 On Saturday, 19 March 2022 at 08:49:02 UTC, Salih Dincer wrote:
- Stanislav Blinov (19/30) Mar 19 2022 No.
- Vinod K Chandran (13/20) Mar 19 2022 First of all Thanks for the reply. The answer "No" is a wonder to
- =?UTF-8?Q?Ali_=c3=87ehreli?= (49/67) Mar 19 2022 I wrote a chapter about the is expression but it's still mysterious to
- =?UTF-8?Q?Ali_=c3=87ehreli?= (6/9) Mar 19 2022 Here is the clickable url:
- Vinod K Chandran (2/7) Mar 19 2022 Thanks. Let me read that chapter.
- Vinod K Chandran (14/36) Mar 19 2022 Thanks for the reply. I think I choose the wrong book. I knew
- Stanislav Blinov (33/58) Mar 19 2022 It is appearing not in the `static if`, but in the `is`
- Vinod K Chandran (8/35) Mar 20 2022 No, it was my mistake, I missed it.
Hi all, I am trying to learn D templates with Philippe Sigaud's "D Templates: A Tutorial". So far so good. I have completed first 19 pages and in the 20th page, I found an obstacle. This is the code. ```d module rank1; template rank(T) { static if (is(T t == U[], U)) // is T an array of U, for some type U? enum size_t rank = 1 + rank!(U); // then let’s recurse down. else enum size_t rank = 0; // Base case, ending the recursion. } module using_rank1; import rank1; static assert(rank!(int) == 0); static assert(rank!(int[]) == 1); static assert(rank!(int[][]) == 2); static assert(rank!(int[][][]) == 3); ``` Question 1 - `U` is appearing in the first static if statement. But we had to write `U` on the template line, right? Like - `template rank(T, U)` Question 2 - The statif if test is - `T t == U[ ]` What does that mean ? Question 3 - if `T t == U[ ]` is the test, then I think when we pass ```d rank!(int[ ][ ][ ]) ``` The test will be `int[ ][ ][ ] == U[ ]`, Right ?
Mar 18 2022
On Saturday, 19 March 2022 at 05:54:26 UTC, Vinod K Chandran wrote:Question 1 - `U` is appearing in the first static if statement. But we had to write `U` on the template line, right? Like - `template rank(T, U)` Question 2 - The statif if test is - `T t == U[ ]` What does that mean ? Question 3 - if `T t == U[ ]` is the test, then I think when we passYou don't need anything extra while using it... I think U is declare a range. Here is a recursive pattern. Just like the code I wrote below: ```d import std.stdio; alias outer O; struct outer { int i; O * o; } int rank(T)(T* s) { int count = 1; if(s.o is null) return count; return count + rank(s.o); } void main() { auto test = O(1, new O(2, new O(3, new O))); rank(test.o).writeln; test.i.write(", "); test.o.i.write(", "); test.o.o.i.writeln; } /* CONSOLEOUT: 3 1, 2, 3 */ ``` SDB 79
Mar 19 2022
On Saturday, 19 March 2022 at 08:49:02 UTC, Salih Dincer wrote:Thanks for the reply. You explained the idea very well and it's easy to understand for a novice.
Mar 19 2022
On Saturday, 19 March 2022 at 05:54:26 UTC, Vinod K Chandran wrote:Question 1 - `U` is appearing in the first static if statement. But we had to write `U` on the template line, right? Like - `template rank(T, U)`No.Question 2 - The statif if test is - `T t == U[ ]` What does that mean ?The test is not `T t == U[]`. It is `is(T t == U[], U)`. https://dlang.org/spec/expression.html#is-identifier-equal ``` is ( Type Identifier == TypeSpecialization ) The condition is satisfied if Type is semantically correct and is the same as TypeSpecialization. The Identifier is declared to be either an alias of the TypeSpecialization or, if TypeSpecialization is dependent on Identifier, the deduced type. ``` You simply introduce new identifiers. Basically, the test means "is T an array of some type which I would like referred to as U?". Actually, the lower case `t` is not needed there, you can simply write `is(T == U[], U)`.Question 3 - if `T t == U[ ]` is the test, then I think when we pass ```d rank!(int[ ][ ][ ]) ``` The test will be `int[ ][ ][ ] == U[ ]`, Right ?Yes, and `U` then becomes `int[][]`. Which is why the template recurses down and instantiates itself with `U`, until `T` fails the test.
Mar 19 2022
On Saturday, 19 March 2022 at 11:47:53 UTC, Stanislav Blinov wrote:No.First of all Thanks for the reply. The answer "No" is a wonder to me. Because, from my point of view, `U` is coming from nowhere. My understanding is, we can use any parameter of a template inside the template. So in this case `U` is not in the parameter list. It is suddenly appearing in that `static if`.The test is not `T t == U[]`. It is `is(T t == U[], U)`.Okay, I understand.Actually, the lower case `t` is not needed there, you can simply write `is(T == U[], U)`.So the `T` is not the type. It's the parameter. Right ? So a template doesn't need a type. Only the parameter, right ? (I think I am too dumb to ask this. Please forgive me.)Yes, and `U` then becomes `int[][]`. Which is why the template recurses down and instantiates itself with `U`, until `T` fails the test.In order to understand this, I need to understand from where the `U` comes.
Mar 19 2022
On 3/19/22 06:38, Vinod K Chandran wrote:On Saturday, 19 March 2022 at 11:47:53 UTC, Stanislav Blinov wrote:I wrote a chapter about the is expression but it's still mysterious to me. :) ddili.org/ders/d.en/is_expr.html I may be saying some things wrong there but that's my mental model.No.First of all Thanks for the reply. The answer "No" is a wonder to me.Because, from my point of view, `U` is coming from nowhere.Agreed. It is similar to U's coming from nowhere below: void foo(U)(U[] array) { } So, in my mental model, that use of the is expression is the same but written in the reverse order from foo above: static if (is(T t == U[], U)) It means "if T matches U[] and U is a type". "a type" because it is just U in the is expression list. I believe at least some of the traits have been added since that doc document was written. I would write it in a much simpler way using template constraints today: template rank(T) { import std.traits : isArray; import std.range : ElementType; static if (isArray!T) { enum size_t rank = 1 + rank!(ElementType!T); } else { enum size_t rank = 0; } } Or one can separate the logic in two template definitions: import std.traits : isArray; template rank(T) if (isArray!T) { import std.range : ElementType; enum size_t rank = 1 + rank!(ElementType!T); } template rank(T) if (!isArray!T) { enum size_t rank = 0; } However, note how the template constraints had to be repeated as isArray!T and !isArray!T in that case.My understanding is, we can use any parameter of a template inside the template. So in this case `U` is not in the parameter list. It is suddenly appearing in that `static if`.In my mental model, the is expression uses at least a part of the template system.T is the type because it is introduced as simply T in the parameter list. If it were 'int T', then it would be an int. So in that sense, it is a type-kind template parameter.you can simply write `is(T == U[], U)`.So the `T` is not the type.It's the parameter. Right ? So a template doesn't need a type. Only the parameter, right ?The way I read it is: "T is a type that matches U[] where U is a type as well."(I think I am too dumb to ask this. Please forgive me.)Not at all! The is expression is the weirdest part of D. Ali
Mar 19 2022
On 3/19/22 08:58, Ali Çehreli wrote:I wrote a chapter about the is expression but it's still mysterious to me. :) ddili.org/ders/d.en/is_expr.htmlHere is the clickable url: http://ddili.org/ders/d.en/is_expr.html I just read it again and I still like what I wrote there. :) (Usually it is the other way around.) Ali
Mar 19 2022
On Saturday, 19 March 2022 at 16:08:33 UTC, Ali Çehreli wrote:Here is the clickable url: http://ddili.org/ders/d.en/is_expr.html I just read it again and I still like what I wrote there. :) (Usually it is the other way around.) AliThanks. Let me read that chapter.
Mar 19 2022
On Saturday, 19 March 2022 at 15:58:25 UTC, Ali Çehreli wrote:I wrote a chapter about the is expression but it's still mysterious to me. :) ddili.org/ders/d.en/is_expr.htmlThanks for the reply. I think I choose the wrong book. I knew about your book but I thought this one is specially written for templates. I will read the template chapters in **`Programming in D`**.It means "if T matches U[] and U is a type". "a type" because it is just U in the is expression list.So as per the eponymous trick, **`enum size_t rank`** will be executed directly. Right ? But in that case, **`rank`** template doesn't take a parameter. There is only the type parameter which is **`T`**. So I am still in confusion about **`U`**.I believe at least some of the traits have been added since that doc document was written. I would write it in a much simpler way using template constraints today: ```d template rank(T) { import std.traits : isArray; import std.range : ElementType; static if (isArray!T) { enum size_t rank = 1 + rank!(ElementType!T); } else { enum size_t rank = 0; } } ```This template is very easy to understand and I have no confusions about it. Because, it only takes **`T`** as type parameter and there is no magical **`U`**.However, note how the template constraints had to be repeated as isArray!T and !isArray!T in that case.Yeah, I noted.Not at all! The is expression is the weirdest part of D.Oh I see.
Mar 19 2022
On Saturday, 19 March 2022 at 13:38:42 UTC, Vinod K Chandran wrote:On Saturday, 19 March 2022 at 11:47:53 UTC, Stanislav Blinov wrote:It is appearing not in the `static if`, but in the `is` expression, which I described further in the rest of my first reply. Sorry if that wasn't clear.No.First of all Thanks for the reply. The answer "No" is a wonder to me. Because, from my point of view, `U` is coming from nowhere. My understanding is, we can use any parameter of a template inside the template. So in this case `U` is not in the parameter list. It is suddenly appearing in that `static if`.Oh don't worry, this topic is not at all obvious with the `is` expression having its own syntax and semantics. `T` is a type, a type you instantiate `rank` with. `template rank(T)` *does* expect a type as a parameter. The other template syntax - `template foo(alias T)` can take as `T` any symbol, not just a type.The test is not `T t == U[]`. It is `is(T t == U[], U)`.Okay, I understand.Actually, the lower case `t` is not needed there, you can simply write `is(T == U[], U)`.So the `T` is not the type. It's the parameter. Right ? So a template doesn't need a type. Only the parameter, right ? (I think I am too dumb to ask this. Please forgive me.)It comes from you, the programmer. Like I said before, `is(T == U[], U)` means "is T an array of some type, the type which I (the programmer) would like to refer to as U?". That's all there is to it (well, not quite, but it should suffice for starters). You're simply introducing an identifier. So, when `T` is an `int[][][]`, naturally, `U` becomes an alias to `int[][]` (look at the converse - when `U` is `int[][]`, `U[]` is naturally an `int[][][]`). You can think of that test as this: ```d import std.traits : isDynamicArray; // ... static if (isDynamicArray!T) { alias U = typeof(T.init[0]); // ... } ``` ...which would roughly be the same thing - you test if `T` is a dynamic array of some type, and then make an alias for that array's element type. It's just that the `is` expression allows you to create such alias in situ.Yes, and `U` then becomes `int[][]`. Which is why the template recurses down and instantiates itself with `U`, until `T` fails the test.In order to understand this, I need to understand from where the `U` comes.
Mar 19 2022
On Saturday, 19 March 2022 at 22:31:19 UTC, Stanislav Blinov wrote:It is appearing not in the `static if`, but in the `is` expression, which I described further in the rest of my first reply. Sorry if that wasn't clear.No, it was my mistake, I missed it.The other template syntax - `template foo(alias T)` can take as `T` any symbol, not just a type.I understand this.It comes from you, the programmer. Like I said before, `is(T == U[], U)` means "is T an array of some type, the type which I (the programmer) would like to refer to as U?". That's all there is to it (well, not quite, but it should suffice for starters). You're simply introducing an identifier. So, when `T` is an `int[][][]`, naturally, `U` becomes an alias to `int[][]` (look at the converse - when `U` is `int[][]`, `U[]` is naturally an `int[][][]`).Okay, got it.You can think of that test as this: ```d import std.traits : isDynamicArray; // ... static if (isDynamicArray!T) { alias U = typeof(T.init[0]); // ... } ```Yes, in this case everything is simple and clear....which would roughly be the same thing - you test if `T` is a dynamic array of some type, and then make an alias for that array's element type. It's just that the `is` expression allows you to create such alias in situ.Okay. Got the point. Thanks. Now, I understand that why Ali suggest me to learn **`is()`** expression.
Mar 20 2022