www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Template Interface

reply "Nathan M. Swan" <nathanmswan gmail.com> writes:
When writing a generic function which takes an unknown type, the 
signature is written like so:

void fun(L)(L l) if (isList!L);

While writing a generic interface is written like so:

template isList(L) {
     enum bool isList = is(typeof(
     (inout int _dummy=0)
     {
         L l;
         if (l.nil) {}
         auto e = l.car;
         l = l.cdr;
     ));
}

This doesn't seem very intuitive to me. OOP languages handle this 
with interfaces, but in D for things like ranges we often use 
structs, making it incompatible with the current "interface."

I'm suggesting something like a "template interface", which is 
compatible with all types, and serves as a placeholder for any 
type for which the body compiles:

void fun(List l);

template interface List {
     List l;
     if (l.nil) {}
     auto e = l.car;
     l = l.cdr;
}

It might be have parameters:

void fun(List!string l);

template interface List(E) : List {
     List!E l;
     E e = l.car;
}

It makes writing generic code much cleaner.

Thoughts?
NMS
Jun 12 2012
next sibling parent reply Nick Treleaven <nospam example.net> writes:
On 12/06/2012 18:56, Nathan M. Swan wrote:
 When writing a generic function which takes an unknown type, the
 signature is written like so:

 void fun(L)(L l) if (isList!L);

 While writing a generic interface is written like so:

 template isList(L) {
 enum bool isList = is(typeof(
 (inout int _dummy=0)
The above line seems unnecessary as we have {no_argument_lambda;} syntax - or is there a special reason why?
 {
 L l;
 if (l.nil) {}
 auto e = l.car;
 l = l.cdr;
 ));
 }
BTW I think Walter said we could have enum template syntax, which would improve the above a little: enum bool isList(L) = is(typeof(...
 This doesn't seem very intuitive to me. OOP languages handle this with
 interfaces, but in D for things like ranges we often use structs, making
 it incompatible with the current "interface."
A possible enhancement is to allow structs to implement interfaces (but this has a runtime cost, unlike using templates).
 I'm suggesting something like a "template interface", which is
 compatible with all types, and serves as a placeholder for any type for
 which the body compiles:
[snip]
 void fun(List!string l);
Maybe: void fun(L:IList)(L l); template interface IList(E) {
 template interface List(E) : List {
 List!E l;
 E e = l.car;
 }

 It makes writing generic code much cleaner.
I'm not quite sure what the ': List' part means - is it just to declare that the List struct is used below? Maybe it would be better for the template interface body to contain method signatures/members rather than code? I think it might be an interesting idea, but it would probably need to be significantly better than the current way with constraints to get adopted by D. Nick
Jun 13 2012
next sibling parent "Nathan M. Swan" <nathanmswan gmail.com> writes:
On Wednesday, 13 June 2012 at 13:34:25 UTC, Nick Treleaven wrote:
 On 12/06/2012 18:56, Nathan M. Swan wrote:
 When writing a generic function which takes an unknown type, 
 the
 signature is written like so:

 void fun(L)(L l) if (isList!L);

 While writing a generic interface is written like so:

 template isList(L) {
 enum bool isList = is(typeof(
 (inout int _dummy=0)
The above line seems unnecessary as we have {no_argument_lambda;} syntax - or is there a special reason why?
I'm not sure, I just found it throughout std.range
 {
 L l;
 if (l.nil) {}
 auto e = l.car;
 l = l.cdr;
 ));
 }
BTW I think Walter said we could have enum template syntax, which would improve the above a little: enum bool isList(L) = is(typeof(...
 This doesn't seem very intuitive to me. OOP languages handle 
 this with
 interfaces, but in D for things like ranges we often use 
 structs, making
 it incompatible with the current "interface."
A possible enhancement is to allow structs to implement interfaces (but this has a runtime cost, unlike using templates).
 I'm suggesting something like a "template interface", which is
 compatible with all types, and serves as a placeholder for any 
 type for
 which the body compiles:
[snip]
 void fun(List!string l);
Maybe: void fun(L:IList)(L l); template interface IList(E) {
 template interface List(E) : List {
 List!E l;
 E e = l.car;
 }

 It makes writing generic code much cleaner.
I'm not quite sure what the ': List' part means - is it just to declare that the List struct is used below?
That List!E "inherits" from list. I'm not sure this is necessary or not.
 Maybe it would be better for the template interface body to 
 contain method signatures/members rather than code?
I considered that, but somethings aren't just methods. A range's empty could be "enum empty = false", "bool empty", or " property bool empty". The whole point of the range interface is syntactic similarity, though the semantics might be different.
 I think it might be an interesting idea, but it would probably 
 need to be significantly better than the current way with 
 constraints to get adopted by D.

 Nick
Yea, this isn't a specific proposal, just an idea put out there. NMS
Jun 13 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-06-13 15:34, Nick Treleaven wrote:

 Maybe it would be better for the template interface body to contain
 method signatures/members rather than code?
I would prefer that.
 I think it might be an interesting idea, but it would probably need to
 be significantly better than the current way with constraints to get
 adopted by D.
In general I like the idea. -- /Jacob Carlborg
Jun 13 2012
prev sibling parent "Mehrdad" <wfunction hotmail.com> writes:
On Tuesday, 12 June 2012 at 17:56:26 UTC, Nathan M. Swan wrote:
 When writing a generic function which takes an unknown type, 
 the signature is written like so:

 void fun(L)(L l) if (isList!L);

 While writing a generic interface is written like so:

 template isList(L) {
     enum bool isList = is(typeof(
     (inout int _dummy=0)
     {
         L l;
         if (l.nil) {}
         auto e = l.car;
         l = l.cdr;
     ));
 }

 This doesn't seem very intuitive to me. OOP languages handle 
 this with interfaces, but in D for things like ranges we often 
 use structs, making it incompatible with the current 
 "interface."

 I'm suggesting something like a "template interface", which is 
 compatible with all types, and serves as a placeholder for any 
 type for which the body compiles:
What you're looking for were also proposed for C++; they were called "concepts"
 void fun(List l);

 template interface List {
     List l;
     if (l.nil) {}
     auto e = l.car;
     l = l.cdr;
 }

 It might be have parameters:

 void fun(List!string l);

 template interface List(E) : List {
     List!E l;
     E e = l.car;
 }

 It makes writing generic code much cleaner.

 Thoughts?
 NMS
Jun 13 2012