[Issue 19767] Classes that inherit from an interface can override static interface methods

2022-12-17 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=19767

Iain Buclaw  changed:

   What|Removed |Added

   Priority|P1  |P3

--


[Issue 19767] Classes that inherit from an interface can override static interface methods

2020-03-20 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=19767

Basile-z  changed:

   What|Removed |Added

 CC|b2.t...@gmx.com |

--


[Issue 19767] Classes that inherit from an interface can override static interface methods

2019-03-27 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=19767

Andrei Alexandrescu  changed:

   What|Removed |Added

 CC||and...@erdani.com
   Assignee|nob...@puremagic.com|edi33...@gmail.com

--- Comment #2 from Andrei Alexandrescu  ---
Yah, this should be clarified in the spec. Thanks Edi!

--


[Issue 19767] Classes that inherit from an interface can override static interface methods

2019-03-27 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=19767

Basile-z  changed:

   What|Removed |Added

 CC||b2.t...@gmx.com
   Hardware|x86_64  |All
 OS|Linux   |All
   Severity|enhancement |normal

--- Comment #1 from Basile-z  ---
I don't know if the report is valid.

1. You can still call the interface version of foo, e.g `(new C).D.foo();`
2. C.foo() is not virtual and does not call the inherited D.foo().

Because 2, the specs are respected. It's not an override but rather a case of 
hijacking.

--


[Issue 19767] New: Classes that inherit from an interface can override static interface methods

2019-03-27 Thread d-bugmail--- via Digitalmars-d-bugs
https://issues.dlang.org/show_bug.cgi?id=19767

  Issue ID: 19767
   Summary: Classes that inherit from an interface can override
static interface methods
   Product: D
   Version: D2
  Hardware: x86_64
OS: Linux
Status: NEW
  Severity: enhancement
  Priority: P1
 Component: dmd
  Assignee: nob...@puremagic.com
  Reporter: edi33...@gmail.com

This directly contradicts the interface
[spec](https://dlang.org/spec/interface.html), pt. 8:

"Classes that inherit from an interface may not override final or static
interface member functions."

interface D
{
void bar();
static void foo() { }
}

class C : D
{
void bar() { } // ok
void foo() { } // BUG: this is ok, but should error because we cannot
override static D.foo()
}

--


static interface for structs

2011-10-11 Thread Marco Leise
First things first: I've been told on IRC that this idea has already come  
up and was rejected in favor of template guards. But it wasn't clear what  
the reasons were.


The idea is to have static interface or protocol for structs similar  
to the interface for classes. The benefit comes from the fact that in D  
we often see structs used in a way other languages can't. A prime example  
are function templates for sorting algorithms that can take any kind of  
range (built-in, class, struct). But with this broader use, comes the need  
to be explicit about the interface of a struct akin to interfaces for  
classes. A compiler or IDE can detect missing or incorrectly spelled  
methods on structs that implement a protocol. Readers of your code can  
understand from the declaration that a struct is forward-iterable or  
supports some other protocol.


These are the rules:
1. Protocols share the common symbol space with classes, interfaces, etc.
2. They can be (multiple-)inherited by interfaces and other protocols.
3. They can be implemented by structs as well as classes.

I use protocol as a keyword to avoid any confusion with what interface  
allows you to do at runtime. Also this is not C++ concepts in disguise.  
Actually I didn't know about until now. It is somewhat of a really small  
subset of that though.



protocol InputRange(E) {
@property bool empty;
@property E front;
E popFront();
}

// defines a property that returns the declared range type
protocol ForwardRange(E) : InputRange!E {
@property typeof(this) save;
}

// just a tag
protocol InfiniteRange(E) : ForwardRange!E {}


I used the range module as an example, just because it is the first that  
came to my head. Actually on browsing the source for a while I realized  
that checks like hasLength, which look like a candidate for a protocol  
are more flexible than a method/field declaration. length can be a field  
or property and return any integral type. So on 32-bit systems it works  
with 64-bit file sizes and 32-bit indexes on arrays just as well. So even  
if protocols make for a nice syntax, they don't fit the bill. Other ideas  
for struct interfaces?


Re: static interface for structs

2011-10-11 Thread Gor Gyolchanyan
Actually, the __traits(compiles, ...) is a marvelous and very powerful
tool that will allow you to test if the struct is fit for your
particular task by just specifying the task.

On Tue, Oct 11, 2011 at 4:30 PM, Marco Leise marco.le...@gmx.de wrote:
 First things first: I've been told on IRC that this idea has already come up
 and was rejected in favor of template guards. But it wasn't clear what the
 reasons were.

 The idea is to have static interface or protocol for structs similar to
 the interface for classes. The benefit comes from the fact that in D we
 often see structs used in a way other languages can't. A prime example are
 function templates for sorting algorithms that can take any kind of range
 (built-in, class, struct). But with this broader use, comes the need to be
 explicit about the interface of a struct akin to interfaces for classes. A
 compiler or IDE can detect missing or incorrectly spelled methods on structs
 that implement a protocol. Readers of your code can understand from the
 declaration that a struct is forward-iterable or supports some other
 protocol.

 These are the rules:
 1. Protocols share the common symbol space with classes, interfaces, etc.
 2. They can be (multiple-)inherited by interfaces and other protocols.
 3. They can be implemented by structs as well as classes.

 I use protocol as a keyword to avoid any confusion with what interface
 allows you to do at runtime. Also this is not C++ concepts in disguise.
 Actually I didn't know about until now. It is somewhat of a really small
 subset of that though.


 protocol InputRange(E) {
        @property bool empty;
        @property E front;
        E popFront();
 }

 // defines a property that returns the declared range type
 protocol ForwardRange(E) : InputRange!E {
        @property typeof(this) save;
 }

 // just a tag
 protocol InfiniteRange(E) : ForwardRange!E {}


 I used the range module as an example, just because it is the first that
 came to my head. Actually on browsing the source for a while I realized that
 checks like hasLength, which look like a candidate for a protocol are more
 flexible than a method/field declaration. length can be a field or property
 and return any integral type. So on 32-bit systems it works with 64-bit file
 sizes and 32-bit indexes on arrays just as well. So even if protocols make
 for a nice syntax, they don't fit the bill. Other ideas for struct
 interfaces?



Re: static interface for structs

2011-10-11 Thread Andrej Mitrovic
On 10/11/11, Gor Gyolchanyan gor.f.gyolchan...@gmail.com wrote:
 Actually, the __traits(compiles, ...) is a marvelous and very powerful
 tool that will allow you to test if the struct is fit for your
 particular task by just specifying the task.

Yeah, but you have to write very specific code to test if it really is
a compatible type. And even after all that hard work you could still
easily pass a type that walks like a duck but that you know is
actually incompatible. So then you have to write specific if(!is(T ==
IncompatibleType)), and this doesn't scale too well.

This is why I resort to having an enum boolean as the first field of a
struct that defines its protocol, but I really see that as a
poor-man's implementation of interfaces.


Re: static interface for structs

2011-10-11 Thread Gor Gyolchanyan
Right. It is far too verbose, but those protocols are too restrictive.
With no run-time value, the protocols must be very flexible to contain
any kind of requirements on structs, that are practically useful to
have.
The __traits(compiles, ...) would be awesome to be automatically be
used in templates:

void func(Type)(Type param)
{
Type temp = new Type;
temp.method(param);
}

This code requires the Type to be either a class or a struct with a
this(typeof(this)*) { } implemented in it.
If the test for it was automatically included in the template's
constraint, it would make templates so much easier to use.
Templates would then overload on their bodies. You'd just write
several implementations of the template and the correct one would be
automatically chosen, based on the implementation itself.
And in case none of them are applicable, the compiler would be able to
tell you exactly what does your template parameter lack.
But we don't have that, unfortunately.

On Tue, Oct 11, 2011 at 6:01 PM, Andrej Mitrovic
andrej.mitrov...@gmail.com wrote:
 On 10/11/11, Gor Gyolchanyan gor.f.gyolchan...@gmail.com wrote:
 Actually, the __traits(compiles, ...) is a marvelous and very powerful
 tool that will allow you to test if the struct is fit for your
 particular task by just specifying the task.

 Yeah, but you have to write very specific code to test if it really is
 a compatible type. And even after all that hard work you could still
 easily pass a type that walks like a duck but that you know is
 actually incompatible. So then you have to write specific if(!is(T ==
 IncompatibleType)), and this doesn't scale too well.

 This is why I resort to having an enum boolean as the first field of a
 struct that defines its protocol, but I really see that as a
 poor-man's implementation of interfaces.



Re: static interface for structs

2011-10-11 Thread Gor Gyolchanyan
BTW, you can make a template, which takes an interface type and a
struct type and evaluates to a bool, indicating whether the struct
theoretically implements the interface.
I actually had a success in doing something similar.
Here are the main features I use in these situations:
__traits(allMembers, Type);
is(typeof(member))
__traits(getOverloads, Type);

On Tue, Oct 11, 2011 at 6:01 PM, Andrej Mitrovic
andrej.mitrov...@gmail.com wrote:
 On 10/11/11, Gor Gyolchanyan gor.f.gyolchan...@gmail.com wrote:
 Actually, the __traits(compiles, ...) is a marvelous and very powerful
 tool that will allow you to test if the struct is fit for your
 particular task by just specifying the task.

 Yeah, but you have to write very specific code to test if it really is
 a compatible type. And even after all that hard work you could still
 easily pass a type that walks like a duck but that you know is
 actually incompatible. So then you have to write specific if(!is(T ==
 IncompatibleType)), and this doesn't scale too well.

 This is why I resort to having an enum boolean as the first field of a
 struct that defines its protocol, but I really see that as a
 poor-man's implementation of interfaces.



Re: static interface for structs

2011-10-11 Thread Gor Gyolchanyan
You can have those protocols: import(my_protocol.pr);
mixin(parseProtocol(protocol)), etc...

On Tue, Oct 11, 2011 at 6:24 PM, Gor Gyolchanyan
gor.f.gyolchan...@gmail.com wrote:
 BTW, you can make a template, which takes an interface type and a
 struct type and evaluates to a bool, indicating whether the struct
 theoretically implements the interface.
 I actually had a success in doing something similar.
 Here are the main features I use in these situations:
 __traits(allMembers, Type);
 is(typeof(member))
 __traits(getOverloads, Type);

 On Tue, Oct 11, 2011 at 6:01 PM, Andrej Mitrovic
 andrej.mitrov...@gmail.com wrote:
 On 10/11/11, Gor Gyolchanyan gor.f.gyolchan...@gmail.com wrote:
 Actually, the __traits(compiles, ...) is a marvelous and very powerful
 tool that will allow you to test if the struct is fit for your
 particular task by just specifying the task.

 Yeah, but you have to write very specific code to test if it really is
 a compatible type. And even after all that hard work you could still
 easily pass a type that walks like a duck but that you know is
 actually incompatible. So then you have to write specific if(!is(T ==
 IncompatibleType)), and this doesn't scale too well.

 This is why I resort to having an enum boolean as the first field of a
 struct that defines its protocol, but I really see that as a
 poor-man's implementation of interfaces.




Re: static interface

2009-11-19 Thread Simen kjaeraas

Leandro Lucarella llu...@gmail.com wrote:


What do you think?


I was inspired:

template staticInterface( T, iface ) {
static assert( is( iface == interface ) );
static assert( is( T == struct ) );
alias staticInterfaceImpl!( T, MemberTuple!( iface ) ) staticInterface;
}

template staticInterfaceImpl( T, U... ) {
static if ( U.length ) {
		enum staticInterfaceImpl = isIn!( U[ 0 ], U[ 1 ], MemberTuple!( T ) )   
staticInterfaceImpl!( T, U[ 2..$ ] );

} else {
enum staticInterfaceImpl = true;
}
}

template MemberTuple( T ) {
alias allMembersToTypeTuple!( T, __traits( allMembers, T ) ) 
MemberTuple;
}

template allMembersToTypeTuple( T, alias U, V... ) {
static if( U.length ) {
		alias allMembersToTypeTuple!( T, U[1..$], U[ 0 ], typeof( mixin(  
T.stringof ~ . ~ U[ 0 ] ) ), V ) allMembersToTypeTuple;

} else {
alias V allMembersToTypeTuple;
}
}

template isIn( string name, T, U... ) {
static if ( U.length ) {
		enum isIn = ( name == U[ 0 ]  is( T == U[ 1 ] ) ) || isIn!( name, T,  
U[ 2..$ ] );

} else {
enum isIn = false;
}
}

Usage:

interface I;
struct S;
static if ( staticInterface!( S, I ) ) {}

There may be problems with this, and it might not match everything as  
nicely as it should, but it's a proof-of-concept. I'm open to suggestions  
on how to extend/fix it.


--
Simen


Re: static interface

2009-11-19 Thread Leandro Lucarella
Simen kjaeraas, el 19 de noviembre a las 12:47 me escribiste:
 Leandro Lucarella llu...@gmail.com wrote:
 
 What do you think?
 
 I was inspired:
 
[...]
 
 Usage:
 
 interface I;
 struct S;
 static if ( staticInterface!( S, I ) ) {}
[...]

Nice! :)


-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
- Los romanos no tenían paz, loco... Necesitaban un poco de chala...


Re: static interface

2009-11-18 Thread のしいか (noshiika)

In order to achieve good completion support by editors (like
IntelliSense) with duck-typed variables, concept-checking code should
contain more type information than that of the code now used in Phobos.

Example:

  static interface InputRange(T) {
const bool empty();
T front();
void popFront();
  }

or in the current D syntax,

  template isInputRange(T, R) {
enum isInputRange =
  is(const(R).init.empty() == bool) 
  is(R.init.front() == T) 
  is(R.init.popFront() == void);
  }

How do you think about this?


Re: static interface

2009-11-17 Thread Lars T. Kyllingstad

Bill Baxter wrote:

On Mon, Nov 16, 2009 at 9:25 AM, Leandro Lucarella llu...@gmail.com wrote:

This topic is actually very close to a discussion last week about
retrieving error messages from failures of __traits(compiles, xxx).

My question is: is it really that much of an improvement?

I've rearranged your code to see the equivalent snippets side-by-side:


static interface InputRange(T) {
   bool empty();
   T front();
   void popFront();
}




template isInputRange(R)
{
   enum bool isInputRange = is(typeof(
   {
   R r;
   if (r.empty) {}
   r.popFront;
   auto h = r.front;
   }()));
}


There's actually not that much difference here.  Of course we would
like several general improvements that have been discussed before:
1) some kind of template 'this' so we don't have to repeat the template name.
2) something better than is(typeof()) (or __traits(compiles, ...)) to
check if code is ok. [hoping for meta.compiles(...)]

In some ways the current code is better, because it actually checks if
a construct works or not, rather than requiring a specific function
signature.  Whether the code will work is really the minimal
restriction you can place on the interface.  A specific may be too
tight.  For instance, above you don't really care if empty returns
bool or not.  Just if you can test it in an if.


Another, related way in which the current code is better is that it 
doesn't care whether empty, front, and popFront are functions or 
variables.  As we know, the standard trick for infinite ranges is to 
declare empty as an enum, not a function.


BTW, I find it interesting that I see meta.* being mentioned in 
discussions and even used in code snippets all over the NG these days. 
It seems to be a popular proposal. I hope it gets implemented too. :)


-Lars


Re: static interface

2009-11-17 Thread Leandro Lucarella
Bill Baxter, el 16 de noviembre a las 15:42 me escribiste:
 On Mon, Nov 16, 2009 at 9:25 AM, Leandro Lucarella llu...@gmail.com wrote:
 
 This topic is actually very close to a discussion last week about
 retrieving error messages from failures of __traits(compiles, xxx).
 
 My question is: is it really that much of an improvement?
 
 I've rearranged your code to see the equivalent snippets side-by-side:
 
  static interface InputRange(T) {
         bool empty();
         T front();
         void popFront();
  }
 
 
  template isInputRange(R)
  {
 enum bool isInputRange = is(typeof(
 {
 R r;
 if (r.empty) {}
 r.popFront;
 auto h = r.front;
 }()));
  }
 
 There's actually not that much difference here.  Of course we would
 like several general improvements that have been discussed before:
 1) some kind of template 'this' so we don't have to repeat the template name.
 2) something better than is(typeof()) (or __traits(compiles, ...)) to
 check if code is ok. [hoping for meta.compiles(...)]
 
 In some ways the current code is better, because it actually checks if
 a construct works or not, rather than requiring a specific function
 signature.  Whether the code will work is really the minimal
 restriction you can place on the interface.  A specific may be too
 tight.  For instance, above you don't really care if empty returns
 bool or not.  Just if you can test it in an if.

I think one could argue if being more restrictive is actually good or bad.
Being more restrictive cold lead to less errors. Maybe if a struct empty()
method returns, say, a pointer, I don't want to think it is *really*
a range. Maybe that method is doing a lot of work and removing stuff, and
then returning a pointer to some removed stuff. Anyway, I'm not saying
that that couldn't happen even if empty() return bool (that's a risk when
duck-typing, always :), I'm just saying I'm not so sure that being more
restrictive is really a *bad thing*.

And about what's nice or ugly, I agree the current way of doing stuff is
not too bad, there are a few details that are not *that* nice. But with
duck-typing I think the same that with tuples: those little details makes
you feel that D doesn't support the concept so well, and make people
resistant to use them. When something feels natural in a language, you use
it all the time, for me, the current way to do tuples and duck-typing
looks very artificial and harder than it should.

 But in terms of functionality it seems we cover pretty much everything
 static interface gives you.

I know that, I started this proposal just saying that =) Again, this
proposal is about what I say in the previous paragraphs.

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
Be nice to nerds
Chances are you'll end up working for one


Re: static interface

2009-11-17 Thread Leandro Lucarella
Lars T. Kyllingstad, el 17 de noviembre a las 09:54 me escribiste:
 In some ways the current code is better, because it actually checks if
 a construct works or not, rather than requiring a specific function
 signature.  Whether the code will work is really the minimal
 restriction you can place on the interface.  A specific may be too
 tight.  For instance, above you don't really care if empty returns
 bool or not.  Just if you can test it in an if.
 
 Another, related way in which the current code is better is that it
 doesn't care whether empty, front, and popFront are functions or
 variables.  As we know, the standard trick for infinite ranges is to
 declare empty as an enum, not a function.

Is not that hard to write:
bool empty() { return false; }
instead of
enum bool empty = false;

 BTW, I find it interesting that I see meta.* being mentioned in
 discussions and even used in code snippets all over the NG these
 days. It seems to be a popular proposal. I hope it gets implemented
 too. :)

We all do ;)

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
FALTAN 325 DIAS PARA LA PRIMAVERA
-- Crónica TV


Re: static interface

2009-11-17 Thread Leandro Lucarella
Jesse Phillips, el 16 de noviembre a las 19:14 me escribiste:
 Leandro Lucarella Wrote:
 
  
  The problem is regular interfaces provide dynamic dispatch. Andrei could
  implement all the range stuff using interfaces, but that would mean:
  1) You have to inherit from the interface (i.e., you can't use arrays)
  2) All calls to ranges functions are virtual (inefficient; this is
 particularly relevant since they are called inside loops = lot of
 times)
  
  A static interface don't have those problems, and I don't see a way to mix
  static and dynamic interfaces without introducing a new type of
  interfaces (static interface).
 
 I realize that a class that inherits an interface would have these
 issues, but if you aren't required to inherit the interface and the use
 of interface in a function parameter constitutes a compile-time check
 instead of inheritance check...
 
 But this does bring up the question in your suggestion the following
 code couldn't compile, but based on the signature it looks like it
 should:
 
 size_t walkLength(InputRange range, size_t upTo = size_t.max)
 {
 InputRange temp = range;
 // implementation
 }

That can be translated to something like:

size_t walkLength(Range)(Range range, size_t upTo = size_t.max)
if (isInputRange!(Range))
{
Range temp = range;
// implementation
}

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
DETUVIERON BANDA DE PIRATAS DEL ASFALTO
SON TODOS URUGUAYOS Y ROBARON MILES DE LITROS DE CERVEZA
-- Crónica TV


Re: static interface

2009-11-17 Thread Lars T. Kyllingstad

Leandro Lucarella wrote:

Lars T. Kyllingstad, el 17 de noviembre a las 09:54 me escribiste:

In some ways the current code is better, because it actually checks if
a construct works or not, rather than requiring a specific function
signature.  Whether the code will work is really the minimal
restriction you can place on the interface.  A specific may be too
tight.  For instance, above you don't really care if empty returns
bool or not.  Just if you can test it in an if.

Another, related way in which the current code is better is that it
doesn't care whether empty, front, and popFront are functions or
variables.  As we know, the standard trick for infinite ranges is to
declare empty as an enum, not a function.


Is not that hard to write:
bool empty() { return false; }
instead of
enum bool empty = false;



That's why I mentioned infinite ranges. An infinite range is *defined* 
as a range where empty is implemented as


  enum bool empty = false;

isInfinite(Range) tests whether this is the case, which it wouldn't be 
able to do if empty() was a function.


-Lars


Re: static interface

2009-11-17 Thread dsimcha
== Quote from Leandro Lucarella (llu...@gmail.com)'s article
 Lars T. Kyllingstad, el 17 de noviembre a las 09:54 me escribiste:
  In some ways the current code is better, because it actually checks if
  a construct works or not, rather than requiring a specific function
  signature.  Whether the code will work is really the minimal
  restriction you can place on the interface.  A specific may be too
  tight.  For instance, above you don't really care if empty returns
  bool or not.  Just if you can test it in an if.
 
  Another, related way in which the current code is better is that it
  doesn't care whether empty, front, and popFront are functions or
  variables.  As we know, the standard trick for infinite ranges is to
  declare empty as an enum, not a function.
 Is not that hard to write:
 bool empty() { return false; }
 instead of
 enum bool empty = false;

Yes, but there's a reason to use enum:  This convention enables compile time
introspection as to whether the ranges are infinite.  It's also more efficient
when inlining is disabled.


Re: static interface

2009-11-17 Thread Leandro Lucarella
Lars T. Kyllingstad, el 17 de noviembre a las 15:12 me escribiste:
 Leandro Lucarella wrote:
 Lars T. Kyllingstad, el 17 de noviembre a las 09:54 me escribiste:
 In some ways the current code is better, because it actually checks if
 a construct works or not, rather than requiring a specific function
 signature.  Whether the code will work is really the minimal
 restriction you can place on the interface.  A specific may be too
 tight.  For instance, above you don't really care if empty returns
 bool or not.  Just if you can test it in an if.
 Another, related way in which the current code is better is that it
 doesn't care whether empty, front, and popFront are functions or
 variables.  As we know, the standard trick for infinite ranges is to
 declare empty as an enum, not a function.
 
 Is not that hard to write:
 bool empty() { return false; }
 instead of
 enum bool empty = false;
 
 
 That's why I mentioned infinite ranges. An infinite range is
 *defined* as a range where empty is implemented as
 
   enum bool empty = false;
 
 isInfinite(Range) tests whether this is the case, which it wouldn't
 be able to do if empty() was a function.

OK, there are way to fix that too, but I see your point now.

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
The Guinness Book of Records holds the record for being the most
stolen book in public libraries


Re: static interface

2009-11-17 Thread Michel Fortin
On 2009-11-17 09:12:04 -0500, Lars T. Kyllingstad 
pub...@kyllingen.nospamnet said:


That's why I mentioned infinite ranges. An infinite range is *defined* 
as a range where empty is implemented as


   enum bool empty = false;

isInfinite(Range) tests whether this is the case, which it wouldn't be 
able to do if empty() was a function.


Which makes me think: what about a range that can but may not 
necessarily be infinite depending on runtime parameters? For instance, 
you could have a range returning a rational number as decimal digits: 
some will be infinite and others will be finite depending on the 
rational number (like 1/3 vs. 1/4). You can't express that with an enum.


I guess you could fix that by overloading isInfinite for your specific 
range type though.


--
Michel Fortin
michel.for...@michelf.com
http://michelf.com/



Re: static interface

2009-11-17 Thread Bill Baxter
On Tue, Nov 17, 2009 at 5:51 AM, Leandro Lucarella llu...@gmail.com wrote:
 Bill Baxter, el 16 de noviembre a las 15:42 me escribiste:
 On Mon, Nov 16, 2009 at 9:25 AM, Leandro Lucarella llu...@gmail.com wrote:

 This topic is actually very close to a discussion last week about
 retrieving error messages from failures of __traits(compiles, xxx).

 My question is: is it really that much of an improvement?

 I've rearranged your code to see the equivalent snippets side-by-side:

  static interface InputRange(T) {
         bool empty();
         T front();
         void popFront();
  }


  template isInputRange(R)
  {
     enum bool isInputRange = is(typeof(
     {
         R r;
         if (r.empty) {}
         r.popFront;
         auto h = r.front;
     }()));
  }

 There's actually not that much difference here.  Of course we would
 like several general improvements that have been discussed before:
 1) some kind of template 'this' so we don't have to repeat the template name.
 2) something better than is(typeof()) (or __traits(compiles, ...)) to
 check if code is ok. [hoping for meta.compiles(...)]

 In some ways the current code is better, because it actually checks if
 a construct works or not, rather than requiring a specific function
 signature.  Whether the code will work is really the minimal
 restriction you can place on the interface.  A specific may be too
 tight.  For instance, above you don't really care if empty returns
 bool or not.  Just if you can test it in an if.

 I think one could argue if being more restrictive is actually good or bad.
 Being more restrictive cold lead to less errors. Maybe if a struct empty()
 method returns, say, a pointer, I don't want to think it is *really*
 a range. Maybe that method is doing a lot of work and removing stuff, and
 then returning a pointer to some removed stuff. Anyway, I'm not saying
 that that couldn't happen even if empty() return bool (that's a risk when
 duck-typing, always :), I'm just saying I'm not so sure that being more
 restrictive is really a *bad thing*.

If that's what you want, the D way gives you the option of checking

   is(typeof(R.empty)==bool)

But yeh, that is klunkier than just writing out the function signature
you're expecting.


 And about what's nice or ugly, I agree the current way of doing stuff is
 not too bad, there are a few details that are not *that* nice. But with
 duck-typing I think the same that with tuples: those little details makes
 you feel that D doesn't support the concept so well, and make people
 resistant to use them. When something feels natural in a language, you use
 it all the time, for me, the current way to do tuples and duck-typing
 looks very artificial and harder than it should.

Agreed.  But as for the duck typing aspect, I think there isn't
necessarily an either-or choice here.
For instance, in D, we could allow a static interface to have a static
assert block:

 static interface InputRange(T) {
 static assert (meta.compiles({
   if (this.empty) {};  // this is a shortcut for T.init
 }));
 T front();
 void popFront();
  }

Or something like that.  Invariant {} might be better there.

 But in terms of functionality it seems we cover pretty much everything
 static interface gives you.

 I know that, I started this proposal just saying that =)

Ah.  Sorry, I missed that comment.

--bb


static interface

2009-11-16 Thread Leandro Lucarella
Why not? ;)

I know you might want to hit me for bringing just another feature request
inspired in Google's Go, but please do read it without preconceptions,
because I think the features I'm suggesting are mostly already in D, but
in a less convenient way.

With ranges, D is already using some kind of duck-typing. It's implemented
with template, template constraints and __traits(compiles)/is(typeof())
mostly. The range module makes extensive use of this trick.

All those features are great, and general and useful for a lot of things
besides duck-typing. But (compile-time) duck-typing is a very nice feature
which might deserve a little magic to avoid the boilerplate (or at least
odd implementation).

What I'm suggesting is just some syntax sugar for compile-time
duck-typing. My suggestion is to make this (a real example from the range
module):

static interface InputRange(T) {
bool empty();
T front();
void popFront();
}

size_t walkLength(InputRange range, size_t upTo = size_t.max)
{
// implementation
}

struct Stride(T): InputRange(T) {
// implementation
}


Be somehow equivalent to:

template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r;
if (r.empty) {}
r.popFront;
auto h = r.front;
}()));
}

size_t walkLength(Range)(Range range, size_t upTo = size_t.max)
if (isInputRange!(Range))
{
// implementation
}

struct Stride(T) if (isInputRange!(Range)) {
// implementation
}


The former syntax is much pleasant for both defining 'static interfaces'
and writing algorithms for them.

I didn't thought about this too much, and I'm sure there are plenty of
holes to be worked out, but I wanted to throw the idea out there to see
what people think about it.

What do you think?

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
I always get the feeling that when lesbians look at me, they're thinking,
'*That's* why I'm not a heterosexual.'
-- George Constanza


Re: static interface

2009-11-16 Thread Frank Benoit
Leandro Lucarella schrieb:

 What do you think?
 

I like it.


Re: static interface

2009-11-16 Thread bearophile
Leandro Lucarella Wrote:

 static interface InputRange(T) {

Few days ago a professional C# programmer, a smart person that doesn't know 
much about D, has asked me if in D there are static interfaces. I think he was 
thinking about something similar.

I think that's a nice idea, or it can become a nice idea after some improvement.

Bye,
bearophile


Re: static interface

2009-11-16 Thread Jesse Phillips
Is there a reason not to have all interfaces compile time checked? It would 
still be allowable to state a class implements an interface and have the 
compiler check it.

The reason I say this is it would remove the complexity of having the two types 
of interfaces. And if you wanted to be able to check for the interface at 
run-time the same interface can be used.



Re: static interface

2009-11-16 Thread grauzone

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in this. 
Because they didn't show any interest so far. D will probably be doomed 
to compile time bug-typing I mean duck-typing forever.



static interface InputRange(T) {
bool empty();
T front();
void popFront();
}

size_t walkLength(InputRange range, size_t upTo = size_t.max)
{
// implementation
}

struct Stride(T): InputRange(T) {
// implementation
}


Or just:

interface InputRange(T) {
...
}

struct Stride(T) : InputRange(T) { ... }

size_t size_t walkLength(Range : InputRange)(Range range, ...

The main purpose of the interface is to allow the compiler to do some 
type checking.


(Interestingly, you could get an actual interface from a struct pointer. 
The compiler just needs to statically allocate a vtable (similar to a 
TypeInfo when writing typeid(T)). But I don't know if it'd be useful and 
is besides the point.)


Actually I'd prefer your proposal, because walkLength could access only 
members that are actually in InputRange. But the declaration looks too 
much like an untemplated function.


On the other hand, I remember that D2 once wanted to make this possible:

void foo(static int x, int y) { ... }

becomes

void foo(int x)(int y) { ... }

What happened to this? If it gets/got implemented, it would provide a 
nice opportunity to add syntax for such static interfaces.


Re: static interface

2009-11-16 Thread Andrei Alexandrescu

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in this. 
Because they didn't show any interest so far. D will probably be doomed 
to compile time bug-typing I mean duck-typing forever.


There's an embarrassment of riches when it comes to finding stuff to 
work on for D2. I think we need to resign ourselves to the idea that we 
need to focus only on one subset of the stream of good ideas that are 
being proposed.


FWIW I was keen on structs interacting in interesting ways with 
interfaces (and submitted a number of enhancements in that directions) 
but then realized there are a number of problems that structs/interfaces 
cannot solve. I believe that a better path to pursue in checking 
interface conformance is via reflection.



Andrei


Re: static interface

2009-11-16 Thread grauzone

Andrei Alexandrescu wrote:

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in this. 
Because they didn't show any interest so far. D will probably be 
doomed to compile time bug-typing I mean duck-typing forever.


There's an embarrassment of riches when it comes to finding stuff to 
work on for D2. I think we need to resign ourselves to the idea that we 
need to focus only on one subset of the stream of good ideas that are 
being proposed.


That's understandable of course.

FWIW I was keen on structs interacting in interesting ways with 
interfaces (and submitted a number of enhancements in that directions) 
but then realized there are a number of problems that structs/interfaces 
cannot solve. I believe that a better path to pursue in checking 
interface conformance is via reflection.


That's a possible solution (and an easy way out to get rid of language 
design problems), but I'm sure it's not the best solution. (It also 
should be a little bit extended to give the user better error messages.) 
I hope cleaner solutions will be considered later, possibly after D2 is 
done.


Which are the problems you mentioned?



Andrei


Re: static interface

2009-11-16 Thread Andrei Alexandrescu

grauzone wrote:

Andrei Alexandrescu wrote:

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in 
this. Because they didn't show any interest so far. D will probably 
be doomed to compile time bug-typing I mean duck-typing forever.


There's an embarrassment of riches when it comes to finding stuff to 
work on for D2. I think we need to resign ourselves to the idea that 
we need to focus only on one subset of the stream of good ideas that 
are being proposed.


That's understandable of course.

FWIW I was keen on structs interacting in interesting ways with 
interfaces (and submitted a number of enhancements in that directions) 
but then realized there are a number of problems that 
structs/interfaces cannot solve. I believe that a better path to 
pursue in checking interface conformance is via reflection.


That's a possible solution (and an easy way out to get rid of language 
design problems), but I'm sure it's not the best solution. (It also 
should be a little bit extended to give the user better error messages.) 
I hope cleaner solutions will be considered later, possibly after D2 is 
done.


Which are the problems you mentioned?


I knew this was going to be asked. One issue I remember was that it's 
difficult to talk about a struct must define a type with certain 
properties. You will say but you can express that type as another 
interface but that solves the problem by increasing the size of the 
feature. It gets even more complicated when you want to say defines a 
type with these or these other properties, depending on the properties 
of this type parameter. I think that all can be solved through 
something that is very similar to C++ concepts, and I would want to 
avoid going that route.


Andrei


Re: static interface

2009-11-16 Thread grauzone

Andrei Alexandrescu wrote:

grauzone wrote:

Andrei Alexandrescu wrote:

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in 
this. Because they didn't show any interest so far. D will probably 
be doomed to compile time bug-typing I mean duck-typing forever.


There's an embarrassment of riches when it comes to finding stuff to 
work on for D2. I think we need to resign ourselves to the idea that 
we need to focus only on one subset of the stream of good ideas that 
are being proposed.


That's understandable of course.

FWIW I was keen on structs interacting in interesting ways with 
interfaces (and submitted a number of enhancements in that 
directions) but then realized there are a number of problems that 
structs/interfaces cannot solve. I believe that a better path to 
pursue in checking interface conformance is via reflection.


That's a possible solution (and an easy way out to get rid of language 
design problems), but I'm sure it's not the best solution. (It also 
should be a little bit extended to give the user better error 
messages.) I hope cleaner solutions will be considered later, possibly 
after D2 is done.


Which are the problems you mentioned?


I knew this was going to be asked. One issue I remember was that it's 
difficult to talk about a struct must define a type with certain 
properties. You will say but you can express that type as another 
interface but that solves the problem by increasing the size of the 
feature. It gets even more complicated when you want to say defines a 
type with these or these other properties, depending on the properties 
of this type parameter. I think that all can be solved through 
something that is very similar to C++ concepts, and I would want to 
avoid going that route.


In other words, a general solution inside the language would be too 
complex (because it had to support all sorts of type interfaces), so 
you'll just leave it to the user, who will implement the same thing with 
is() and friends?



Andrei


Re: static interface

2009-11-16 Thread Andrei Alexandrescu

grauzone wrote:

Andrei Alexandrescu wrote:

grauzone wrote:

Andrei Alexandrescu wrote:

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)


The actual question is if Andrei/Walter are interested at all in 
this. Because they didn't show any interest so far. D will probably 
be doomed to compile time bug-typing I mean duck-typing forever.


There's an embarrassment of riches when it comes to finding stuff to 
work on for D2. I think we need to resign ourselves to the idea that 
we need to focus only on one subset of the stream of good ideas that 
are being proposed.


That's understandable of course.

FWIW I was keen on structs interacting in interesting ways with 
interfaces (and submitted a number of enhancements in that 
directions) but then realized there are a number of problems that 
structs/interfaces cannot solve. I believe that a better path to 
pursue in checking interface conformance is via reflection.


That's a possible solution (and an easy way out to get rid of 
language design problems), but I'm sure it's not the best solution. 
(It also should be a little bit extended to give the user better 
error messages.) I hope cleaner solutions will be considered later, 
possibly after D2 is done.


Which are the problems you mentioned?


I knew this was going to be asked. One issue I remember was that it's 
difficult to talk about a struct must define a type with certain 
properties. You will say but you can express that type as another 
interface but that solves the problem by increasing the size of the 
feature. It gets even more complicated when you want to say defines a 
type with these or these other properties, depending on the properties 
of this type parameter. I think that all can be solved through 
something that is very similar to C++ concepts, and I would want to 
avoid going that route.


In other words, a general solution inside the language would be too 
complex (because it had to support all sorts of type interfaces), so 
you'll just leave it to the user, who will implement the same thing with 
is() and friends?


I don't think that's a fair characterization. With reflection you can 
implement such capability in a library. Sometimes a motivated and 
well-intended feature could grow into a monster of generalization. This 
is what happened to C++ concepts and what could have happened to typedef 
if we hadn't clipped it.


Andrei


Re: static interface

2009-11-16 Thread Leandro Lucarella
Jesse Phillips, el 16 de noviembre a las 13:19 me escribiste:
 Is there a reason not to have all interfaces compile time checked? It
 would still be allowable to state a class implements an interface and
 have the compiler check it.
 
 The reason I say this is it would remove the complexity of having the
 two types of interfaces. And if you wanted to be able to check for the
 interface at run-time the same interface can be used.

The problem is regular interfaces provide dynamic dispatch. Andrei could
implement all the range stuff using interfaces, but that would mean:
1) You have to inherit from the interface (i.e., you can't use arrays)
2) All calls to ranges functions are virtual (inefficient; this is
   particularly relevant since they are called inside loops = lot of
   times)

A static interface don't have those problems, and I don't see a way to mix
static and dynamic interfaces without introducing a new type of
interfaces (static interface).

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
Si pudiera acercarme un poco más, hacia vos
Te diría que me tiemblan los dos pies, cuando me mirás
Si supieras todo lo que me costó, llegar
Hoy sabrías que me cuesta respirar, cuando me mirás


Re: static interface

2009-11-16 Thread Leandro Lucarella
Andrei Alexandrescu, el 16 de noviembre a las 12:19 me escribiste:
 grauzone wrote:
 Leandro Lucarella wrote:
 Why not? ;)
 
 The actual question is if Andrei/Walter are interested at all in
 this. Because they didn't show any interest so far. D will
 probably be doomed to compile time bug-typing I mean duck-typing
 forever.
 
 There's an embarrassment of riches when it comes to finding stuff to
 work on for D2. I think we need to resign ourselves to the idea that
 we need to focus only on one subset of the stream of good ideas that
 are being proposed.

I completely agree and understand. I wish I had the time to make patches
myself for the things I propose. But it's very different if something is
not implemented because it sucks or just because the lack of men power :)

If some good feature has Walter's blessing, maybe other person can
implement it. Nobody wants to implement something if it doesn't have
Walter's blessing, because we all know he's very tough to convince, and
nobody wants to work on something it won't get accepted.

 FWIW I was keen on structs interacting in interesting ways with
 interfaces (and submitted a number of enhancements in that
 directions) but then realized there are a number of problems that
 structs/interfaces cannot solve. I believe that a better path to
 pursue in checking interface conformance is via reflection.

But that's very laborious, to be honest, I saw some points in std.range
that would be hard to cover with static interfaces, but for those things
you have all the flexibility you're already using. But static interfaces
could cover a wide range of applications, making static duck-typing very
easy to use.

-- 
Leandro Lucarella (AKA luca) http://llucax.com.ar/
--
GPG Key: 5F5A8D05 (F8CD F9A7 BF00 5431 4145  104C 949E BFB6 5F5A 8D05)
--
Breathe, breathe in the air.
Don't be afraid to care.
Leave but don't leave me.
Look around and choose your own ground.


Re: static interface

2009-11-16 Thread Bill Baxter
On Mon, Nov 16, 2009 at 9:25 AM, Leandro Lucarella llu...@gmail.com wrote:
 Why not? ;)

 I know you might want to hit me for bringing just another feature request
 inspired in Google's Go, but please do read it without preconceptions,
 because I think the features I'm suggesting are mostly already in D, but
 in a less convenient way.

I, for one, think these are great things to talk about.
Even if it's decided that it's a bad idea for D to get such a feature,
then as many people as possible should know that reason so we can talk
intelligently about why D does things the way it does.  Because if
we're asking ourselves why D doesn't have X, you can bet there are
others who will wonder the same when they see D.

--bb


Re: static interface

2009-11-16 Thread Andrei Alexandrescu

Leandro Lucarella wrote:

Andrei Alexandrescu, el 16 de noviembre a las 12:19 me escribiste:

grauzone wrote:

Leandro Lucarella wrote:

Why not? ;)

The actual question is if Andrei/Walter are interested at all in
this. Because they didn't show any interest so far. D will
probably be doomed to compile time bug-typing I mean duck-typing
forever.

There's an embarrassment of riches when it comes to finding stuff to
work on for D2. I think we need to resign ourselves to the idea that
we need to focus only on one subset of the stream of good ideas that
are being proposed.


I completely agree and understand. I wish I had the time to make patches
myself for the things I propose. But it's very different if something is
not implemented because it sucks or just because the lack of men power :)

If some good feature has Walter's blessing, maybe other person can
implement it. Nobody wants to implement something if it doesn't have
Walter's blessing, because we all know he's very tough to convince, and
nobody wants to work on something it won't get accepted.


What I can tell is that Walter's keenness on adding/changing something 
has a 10-fold improvement if a patch is present. For example Walter was 
sort of ambivalent about opDollar and opDollar!(dim)() until Don simply 
added it.



FWIW I was keen on structs interacting in interesting ways with
interfaces (and submitted a number of enhancements in that
directions) but then realized there are a number of problems that
structs/interfaces cannot solve. I believe that a better path to
pursue in checking interface conformance is via reflection.


But that's very laborious, to be honest, I saw some points in std.range
that would be hard to cover with static interfaces, but for those things
you have all the flexibility you're already using. But static interfaces
could cover a wide range of applications, making static duck-typing very
easy to use.


There's a saying that most all girls may look good in the dark. 
Paraphrasing that, I'd say all language features look nice and easy when 
(a) detail is not discussed, (b) all the rest of the language is assumed 
to be mastered.


There are places in D where we can't do what we want to do. Those are 
top priority. Those that do easier what we can do anyway (struct mixins, 
static interfaces, even the better switch which I actually personally 
like) are below top priority. The barrier is fuzzy because either I, 
Walter, or Don may suddenly catch fancy to a specific thing to work on, 
but I wish we were more, not less disciplined about that.



Andrei


Re: static interface

2009-11-16 Thread Bill Baxter
On Mon, Nov 16, 2009 at 9:25 AM, Leandro Lucarella llu...@gmail.com wrote:

This topic is actually very close to a discussion last week about
retrieving error messages from failures of __traits(compiles, xxx).

My question is: is it really that much of an improvement?

I've rearranged your code to see the equivalent snippets side-by-side:

 static interface InputRange(T) {
        bool empty();
        T front();
        void popFront();
 }


 template isInputRange(R)
 {
enum bool isInputRange = is(typeof(
{
R r;
if (r.empty) {}
r.popFront;
auto h = r.front;
}()));
 }

There's actually not that much difference here.  Of course we would
like several general improvements that have been discussed before:
1) some kind of template 'this' so we don't have to repeat the template name.
2) something better than is(typeof()) (or __traits(compiles, ...)) to
check if code is ok. [hoping for meta.compiles(...)]

In some ways the current code is better, because it actually checks if
a construct works or not, rather than requiring a specific function
signature.  Whether the code will work is really the minimal
restriction you can place on the interface.  A specific may be too
tight.  For instance, above you don't really care if empty returns
bool or not.  Just if you can test it in an if.


 struct Stride(T): InputRange(T) {
        // implementation
 }


 struct Stride(T) if (isInputRange!(T)) {
        // implementation
 }

There's really not a significant difference in those two.


 size_t walkLength(InputRange range, size_t upTo = size_t.max)
 {
// implementation
 }

 size_t walkLength(Range)(Range range, size_t upTo = size_t.max)
 if (isInputRange!(Range))
 {
// implementation
 }

Here is the only one where I see a significant improvement.  Basically
that all comes from not having to repeat yourself.
So maybe we'd be better off attacking that repetitiveness directly.

But in terms of functionality it seems we cover pretty much everything
static interface gives you.
The only exception may be that static interfaces could give you better
error messages about why your type doesn't satisfy the requirements.
That's where better ways to get the error messages from
__traits(compiles,...) errors come in.  But it's harder to make that
useful in D without giving up overloading.  In D if T doesn't satisfy
isInputRange!(T), it might satisfy some other overload of the
template.

--bb


Re: static interface

2009-11-16 Thread Jesse Phillips
Leandro Lucarella Wrote:

 
 The problem is regular interfaces provide dynamic dispatch. Andrei could
 implement all the range stuff using interfaces, but that would mean:
 1) You have to inherit from the interface (i.e., you can't use arrays)
 2) All calls to ranges functions are virtual (inefficient; this is
particularly relevant since they are called inside loops = lot of
times)
 
 A static interface don't have those problems, and I don't see a way to mix
 static and dynamic interfaces without introducing a new type of
 interfaces (static interface).

I realize that a class that inherits an interface would have these issues, but 
if you aren't required to inherit the interface and the use of interface in a 
function parameter constitutes a compile-time check instead of inheritance 
check...

But this does bring up the question in your suggestion the following code 
couldn't compile, but based on the signature it looks like it should:

size_t walkLength(InputRange range, size_t upTo = size_t.max)
{
InputRange temp = range;
// implementation
}

I only know enough about the inner workings of compiling Classes to be able to 
follow explanation why my ideas won't work. This could give a very clear 
compiler error, but just doesn't appear wrong outside of that.