www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - A look inside "filter" function defintion

reply pascal111 <judas.the.messiah.111 gmail.com> writes:
This is the definition of "filter" function, and I think it 
called itself within its definition. I'm guessing how it works?

'''D
template filter(alias predicate)
if (is(typeof(unaryFun!predicate)))
{
     /**
     Params:
         range = An $(REF_ALTTEXT input range, isInputRange, 
std,range,primitives)
         of elements
     Returns:
         A range containing only elements `x` in `range` for
         which `predicate(x)` returns `true`.
      */
     auto filter(Range)(Range range) if 
(isInputRange!(Unqual!Range))
     {
         return FilterResult!(unaryFun!predicate, Range)(range);
     }
}
'''

I think this line needs explanation:

'''D
return FilterResult!(unaryFun!predicate, Range)(range);
'''
Aug 01 2022
next sibling parent reply frame <frame86 live.com> writes:
On Monday, 1 August 2022 at 23:35:13 UTC, pascal111 wrote:
 This is the definition of "filter" function, and I think it 
 called itself within its definition. I'm guessing how it works?
It's a template that defines the function called "Eponymous Templates": https://dlang.org/spec/template.html#implicit_template_properties A template generates code, it cannot be called, only instantiated. The common syntax is just a shortcut for using it. Otherwise you would need to write `filter!(a => a > 0).filter([1, -1, 2, 0, -3])`. Like UFCS, some magic the compiler does for you.
Aug 01 2022
parent reply pascal111 <judas.the.messiah.111 gmail.com> writes:
On Tuesday, 2 August 2022 at 04:06:30 UTC, frame wrote:
 On Monday, 1 August 2022 at 23:35:13 UTC, pascal111 wrote:
 This is the definition of "filter" function, and I think it 
 called itself within its definition. I'm guessing how it works?
It's a template that defines the function called "Eponymous Templates": https://dlang.org/spec/template.html#implicit_template_properties A template generates code, it cannot be called, only instantiated. The common syntax is just a shortcut for using it. Otherwise you would need to write `filter!(a => a > 0).filter([1, -1, 2, 0, -3])`. Like UFCS, some magic the compiler does for you.
Instantiation seems some complicated to me. I read "If a template contains members whose name is the same as the template identifier then these members are assumed to be referred to in a template instantiation:" in the provided link, but I'm still stuck. Do you have a down-to-earth example for beginners to understand this concept?
Aug 02 2022
next sibling parent reply frame <frame86 live.com> writes:
On Tuesday, 2 August 2022 at 12:39:41 UTC, pascal111 wrote:

 Instantiation seems some complicated to me. I read "If a 
 template contains members whose name is the same as the 
 template identifier then these members are assumed to be 
 referred to in a template instantiation:" in the provided link, 
 but I'm still stuck. Do you have a down-to-earth example for 
 beginners to understand this concept?
There are obvious examples direct below. Where do you get stuck? Maybe this helps: A template can be seen as a static struct too, so you can access its members with the scope operator "." and if there is only one member of the same name as the template ifself, the compiler auto completes it to this member. You could always write out `name!(someTemplateArg).name(someRuntimeArg)`, we just prefer the short syntax `name!(someTemplateArg)(someRuntimeArg)` or `name(someRuntimeArg)` (if there are no template arguments or it could be auto deducted by the compiler). The last syntax shows that it can be called as a normal function while in fact it's a template.
Aug 02 2022
parent reply pascal111 <judas.the.messiah.111 gmail.com> writes:
On Tuesday, 2 August 2022 at 14:24:50 UTC, frame wrote:
 On Tuesday, 2 August 2022 at 12:39:41 UTC, pascal111 wrote:

 Instantiation seems some complicated to me. I read "If a 
 template contains members whose name is the same as the 
 template identifier then these members are assumed to be 
 referred to in a template instantiation:" in the provided 
 link, but I'm still stuck. Do you have a down-to-earth example 
 for beginners to understand this concept?
There are obvious examples direct below. Where do you get stuck? Maybe this helps: A template can be seen as a static struct too, so you can access its members with the scope operator "." and if there is only one member of the same name as the template ifself, the compiler auto completes it to this member.
I guess you mean if we will understand the templates concept as a static struct that the template is like the struct or - "records" in Pascal - that preserve its members values each time of calling through the runtime because they are "static". Isn't like that or what do you mean?
Aug 02 2022
next sibling parent frame <frame86 live.com> writes:
On Tuesday, 2 August 2022 at 14:58:52 UTC, pascal111 wrote:

 Maybe this helps:

 A template can be seen as a static struct too, so you can 
 access its members with the scope operator "." and if there is 
 only one member of the same name as the template ifself, the 
 compiler auto completes it to this member.
I guess you mean if we will understand the templates concept as a static struct that the template is like the struct or - "records" in Pascal - that preserve its members values each time of calling through the runtime because they are "static". Isn't like that or what do you mean?
I don't know anything about Pascal - I can only say that the template scope can be seen like that from a logical point of view. A function defined in a template is a static member of that template but not necessarily static context in runtime. It depends on the usage and scope. But most library functions in Phobos are very simple like that and you have just to know that most functions are templates. They just may not require template arguments to be supplied and others do.
Aug 02 2022
prev sibling parent novice2 <sorryno em.ail> writes:
leyts try very rough simlified concept:

template itself - is compile-time program (parameterizable), it 
can generate some code for you.

template instantiation (like "calling") with "!" - instruct 
compiler to "start this compile-time program here with this 
parameters".
Aug 03 2022
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 8/2/22 05:39, pascal111 wrote:

 I'm still stuck. Do you have a
 down-to-earth example for beginners to understand this concept?
I will refer to my explanation because down-to-earth has always been my goal. I hope i succeeded: http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.eponymous%20template However, my chapters assume that previous chapters have already been read. Ali
Aug 09 2022
parent pascal111 <judas.the.messiah.111 gmail.com> writes:
On Tuesday, 9 August 2022 at 18:23:04 UTC, Ali Çehreli wrote:
 On 8/2/22 05:39, pascal111 wrote:

 I'm still stuck. Do you have a
 down-to-earth example for beginners to understand this
concept? I will refer to my explanation because down-to-earth has always been my goal. I hope i succeeded: http://ddili.org/ders/d.en/templates_more.html#ix_templates_more.eponymous%20template However, my chapters assume that previous chapters have already been read. Ali
I'll read this when I'll study template with more details. Thanks!
Aug 09 2022
prev sibling next sibling parent Patrick Schluter <Patrick.Schluter bbox.fr> writes:
On Tuesday, 2 August 2022 at 12:39:41 UTC, pascal111 wrote:
 On Tuesday, 2 August 2022 at 04:06:30 UTC, frame wrote:
 On Monday, 1 August 2022 at 23:35:13 UTC, pascal111 wrote:
 This is the definition of "filter" function, and I think it 
 called itself within its definition. I'm guessing how it 
 works?
It's a template that defines the function called "Eponymous Templates": https://dlang.org/spec/template.html#implicit_template_properties A template generates code, it cannot be called, only instantiated. The common syntax is just a shortcut for using it. Otherwise you would need to write `filter!(a => a > 0).filter([1, -1, 2, 0, -3])`. Like UFCS, some magic the compiler does for you.
Instantiation seems some complicated to me. I read "If a template contains members whose name is the same as the template identifier then these members are assumed to be referred to in a template instantiation:" in the provided link, but I'm still stuck. Do you have a down-to-earth example for beginners to understand this concept?
A template is conceptually like a macro with parameters in C. An instantiation is like the using of the macro in your C program. The fundamental difference is, that the template is syntactically and semantically linked to the language. In C, the preprocessor was just a textual replacement done before the proper compilation. This meant that there are things that you couldn't do in the pre-processor (like `#if sizeof(int)==4`) and (horrible) things that never should have been possible (I used to use the C pre-processor with other languages like AutoLISP and dBase III).
Aug 09 2022
prev sibling parent Kyle Ingraham <kyle kyleingraham.com> writes:
On Tuesday, 2 August 2022 at 12:39:41 UTC, pascal111 wrote:
 but I'm still stuck. Do you have a down-to-earth example for 
 beginners to understand this concept?
I often go back to this post when writing templates: https://dlang.org/blog/2020/07/31/the-abcs-of-templates-in-d/ It helped me when I was first trying to understand them.
Aug 14 2022
prev sibling next sibling parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Monday, 1 August 2022 at 23:35:13 UTC, pascal111 wrote:
 I think this line needs explanation:

 '''D
 return FilterResult!(unaryFun!predicate, Range)(range);
 '''
Create an object of type `FilterResult!(unaryFun!predicate, Range)` by passing `range` to its ctor, then return that object.
Aug 02 2022
prev sibling parent Meta <jared771 gmail.com> writes:
On Monday, 1 August 2022 at 23:35:13 UTC, pascal111 wrote:
 This is the definition of "filter" function, and I think it 
 called itself within its definition. I'm guessing how it works?

 '''D
 template filter(alias predicate)
 if (is(typeof(unaryFun!predicate)))
 {
     /**
     Params:
         range = An $(REF_ALTTEXT input range, isInputRange, 
 std,range,primitives)
         of elements
     Returns:
         A range containing only elements `x` in `range` for
         which `predicate(x)` returns `true`.
      */
     auto filter(Range)(Range range) if 
 (isInputRange!(Unqual!Range))
     {
         return FilterResult!(unaryFun!predicate, Range)(range);
     }
 }
 '''

 I think this line needs explanation:

 '''D
 return FilterResult!(unaryFun!predicate, Range)(range);
 '''
To give a vastly simplified answer, the term "eponymous template" essentially means that if you have an item declared inside a template that has a same name as the template: ```D template SomeTemplate(T) { alias SomeTemplate = T; } ``` It is not a compile error. Instead, when you use the template: ```D SomeTemplate!int n; ``` The compiler rewrites your code like to: ```D SomeTemplate!int.SomeTemplate n; ``` Because normally when you instantiate a template, you have to refer to the declarations inside it by name: ```D template SomeOtherTemplate(T) { alias SomeAlias = T; } //SomeOtherTemplate!int n; Error: `SomeOtherTemplate!int` is used as a type SomeOtherTemplate!int.SomeAlias n; //Ok ``` Except in the special case I outlined above. It's essentially a hack that was brought over from C++. It makes using templates more ergonomic.
Aug 09 2022