Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread bossfong via Digitalmars-d-learn

Could we possibly have a template like the following:

satisfiesInterface!(T, Interface);

that would return true when T satisfies Interface and otherwise gives 
descriptive error messages via __pragma(error, ...) ?


Then isInputRange could simply use satisfiesInterface under the hood and 
user code had a nice tool to check their very own requirements.

I'm not sure if such a template is possible though.


Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jul 23, 2014 at 04:21:16PM +0200, bossfong via Digitalmars-d-learn 
wrote:
 Could we possibly have a template like the following:
 
 satisfiesInterface!(T, Interface);
 
 that would return true when T satisfies Interface and otherwise gives
 descriptive error messages via __pragma(error, ...) ?
 
 Then isInputRange could simply use satisfiesInterface under the hood
 and user code had a nice tool to check their very own requirements.
 I'm not sure if such a template is possible though.

We could, though it's not quite the same as a native concepts
implementation where the compiler can check templates for code that
wrongly makes assumptions about the incoming type that aren't defined by
the concept.


T

-- 
I think Debian's doing something wrong, `apt-get install pesticide', doesn't 
seem to remove the bugs on my system! -- Mike Dresser


Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread bossfong via Digitalmars-d-learn

Am 23.07.2014 16:27, schrieb H. S. Teoh via Digitalmars-d-learn:


We could, though it's not quite the same as a native concepts
implementation where the compiler can check templates for code that
wrongly makes assumptions about the incoming type that aren't defined by
the concept.


T


true.

Still, maybe compiler errors could be provided by a library that defines 
an Concept(Interface) UDA that you could use to annotate 
implementations of Concepts?


import concepts;

@Concept(InputRange)
struct MyInputRange
{
// ...
}

verifyConcepts();

Is it that what you mean?

Just thinking things through here...


Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jul 23, 2014 at 04:46:20PM +0200, bossfong via Digitalmars-d-learn 
wrote:
 Am 23.07.2014 16:27, schrieb H. S. Teoh via Digitalmars-d-learn:
 
 We could, though it's not quite the same as a native concepts
 implementation where the compiler can check templates for code that
 wrongly makes assumptions about the incoming type that aren't defined by
 the concept.
 
 
 T
 
 true.
 
 Still, maybe compiler errors could be provided by a library that
 defines an Concept(Interface) UDA that you could use to annotate
 implementations of Concepts?
 
 import concepts;
 
 @Concept(InputRange)
 struct MyInputRange
 {
 // ...
 }
 
 verifyConcepts();
 
 Is it that what you mean?
 
 Just thinking things through here...

No, I'm talking about catching errors like this:

auto myRangeAlgo(R)(R range)
if (isInputRange!R)
{
...
auto r = range.save;// --- oops
...
return Result(...);
}

unittest
{
auto testData = [1,2,3];
auto result = myRangeAlgo(testData);

// Test will pass, because arrays are also forward
// ranges, which have a .save method. So we fail to
// catch the bug in the code above.
assert(result.equal(expectedResults));
}


T

-- 
Bomb technician: If I'm running, try to keep up.


Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread Bossfong via Digitalmars-d-learn
On Wednesday, 23 July 2014 at 15:28:34 UTC, H. S. Teoh via 
Digitalmars-d-learn wrote:
On Wed, Jul 23, 2014 at 04:46:20PM +0200, bossfong via 
Digitalmars-d-learn wrote:
Am 23.07.2014 16:27, schrieb H. S. Teoh via 
Digitalmars-d-learn:


We could, though it's not quite the same as a native concepts
implementation where the compiler can check templates for 
code that
wrongly makes assumptions about the incoming type that aren't 
defined by

the concept.


T

true.

Still, maybe compiler errors could be provided by a library 
that
defines an Concept(Interface) UDA that you could use to 
annotate

implementations of Concepts?

import concepts;

@Concept(InputRange)
struct MyInputRange
{
// ...
}

verifyConcepts();

Is it that what you mean?

Just thinking things through here...


No, I'm talking about catching errors like this:

auto myRangeAlgo(R)(R range)
if (isInputRange!R)
{
...
auto r = range.save;// --- oops
...
return Result(...);
}

unittest
{
auto testData = [1,2,3];
auto result = myRangeAlgo(testData);

// Test will pass, because arrays are also forward
// ranges, which have a .save method. So we fail to
// catch the bug in the code above.
assert(result.equal(expectedResults));
}


T


What about a small wrapper struct then:
A struct Concept that implements opdispatch and forwards all 
calls specified in the interface but for every other method do a 
pragma error.
Then take this struct as a parameter in the function instead of 
any type T.
Maybe, if that is possible, allow implicit conversion from any 
type to Concept, so the callsite doesnt change.
Is there something obvious im missing? Im justbrainstorming 
here...


Re: Compile-Time Interfaces (Concepts)

2014-07-23 Thread H. S. Teoh via Digitalmars-d-learn
On Wed, Jul 23, 2014 at 05:09:54PM +, Bossfong via Digitalmars-d-learn 
wrote:
 On Wednesday, 23 July 2014 at 15:28:34 UTC, H. S. Teoh via
 Digitalmars-d-learn wrote:
 On Wed, Jul 23, 2014 at 04:46:20PM +0200, bossfong via Digitalmars-d-learn
 wrote:
[...]
 Still, maybe compiler errors could be provided by a library that
 defines an Concept(Interface) UDA that you could use to annotate
 implementations of Concepts?
 
 import concepts;
 
 @Concept(InputRange)
 struct MyInputRange
 {
 // ...
 }
 
 verifyConcepts();
 
 Is it that what you mean?
 
 Just thinking things through here...
 
 No, I'm talking about catching errors like this:
 
  auto myRangeAlgo(R)(R range)
  if (isInputRange!R)
  {
  ...
  auto r = range.save;// --- oops
  ...
  return Result(...);
  }
 
  unittest
  {
  auto testData = [1,2,3];
  auto result = myRangeAlgo(testData);
 
  // Test will pass, because arrays are also forward
  // ranges, which have a .save method. So we fail to
  // catch the bug in the code above.
  assert(result.equal(expectedResults));
  }
 
 
 T
 
 What about a small wrapper struct then:
 A struct Concept that implements opdispatch and forwards all calls
 specified in the interface but for every other method do a pragma
 error.
 Then take this struct as a parameter in the function instead of any
 type T.  Maybe, if that is possible, allow implicit conversion from
 any type to Concept, so the callsite doesnt change.
 Is there something obvious im missing? Im justbrainstorming here...

That's not a bad idea, and in fact something similar occurred to me as
well. Basically, my idea was to create dummy structs representing the
Concepts checked by the sig constraints, and have unittests instantiate
the algorithm with said structs. The structs will only have the methods
defined by the Concept, so this will catch any wrong code that tries to
access something outside of what the Concept defines.

Your idea is better, in fact, since you wouldn't have to rely on
programmer diligence to write such unittests. You wouldn't even need to
use pragma error; you just have opDispatch forward only the functions
implemented by the concept, and everything else will result in a no
such field error.

The only trouble is implicit conversion. I don't think the language
allows that right now, by design.


T

-- 
Question authority. Don't ask why, just do it.


Re: Compile-Time Interfaces (Concepts)

2014-07-21 Thread Atila Neves via Digitalmars-d-learn

On Thursday, 17 July 2014 at 22:52:37 UTC, Justin Whear wrote:

On Thu, 17 Jul 2014 22:49:30 +, Nordlöw wrote:


AFAIK there is no compile-time variant of interfaces right?

Why is that?

Wouldn't it be nice to say something like

 struct SomeRange realize InputRange {
 /* implement members of InputRange */
 }

and then the compiler will statically check that that all 
members are

implemented correctly.

I guess this requires some new syntax to describe what an 
InputRange is.


Kind of like C++ Concepts.


What benefits would accrue from adding this?  Static 
verification that a
structure implements the specified concepts?  If so, you can 
simply do

this instead:

static assert(isInputRange!SomeRange);


This is sufficient, but not adequate. Just as the built-in
unittest blocks with assertions, it's great when the assertion is
true but good luck finding out where the bug is when it's not.

The D Cookbook has an idiom to handle this by checking for __ctfe
but it's super hacky and there should be a better way.

I have lost count of how many times I wish the compiler would
help me with compile time interfaces as it does with runtime
code. static override and static interface? Yes please.

Atila


Re: Compile-Time Interfaces (Concepts)

2014-07-21 Thread Vlad Levenfeld via Digitalmars-d-learn

On Sunday, 20 July 2014 at 15:45:37 UTC, Atila Neves wrote:

On Thursday, 17 July 2014 at 22:52:37 UTC, Justin Whear wrote:

On Thu, 17 Jul 2014 22:49:30 +, Nordlöw wrote:


AFAIK there is no compile-time variant of interfaces right?

Why is that?

Wouldn't it be nice to say something like

struct SomeRange realize InputRange {
/* implement members of InputRange */
}

and then the compiler will statically check that that all 
members are

implemented correctly.

I guess this requires some new syntax to describe what an 
InputRange is.


Kind of like C++ Concepts.


What benefits would accrue from adding this?  Static 
verification that a
structure implements the specified concepts?  If so, you can 
simply do

this instead:

static assert(isInputRange!SomeRange);


This is sufficient, but not adequate. Just as the built-in
unittest blocks with assertions, it's great when the assertion 
is

true but good luck finding out where the bug is when it's not.

The D Cookbook has an idiom to handle this by checking for 
__ctfe

but it's super hacky and there should be a better way.

I have lost count of how many times I wish the compiler would
help me with compile time interfaces as it does with runtime
code. static override and static interface? Yes please.

Atila


+1, failing template constraints just gives a vague couldn't 
match overload type of error, and sometimes static assertions 
get suppressed. I've noticed that opDispatch is particularly bad 
about this. Even syntactic errors won't trigger compiler 
messages, and instead seems to behave like SFINAE which I was 
assured doesn't exist in D.
I have to use pragma (msg, ...) to get meaningful errors. Its so 
bad I generally avoid opDispatch despite its awesome potential 
and just generate template functions with mixins instead, because 
they are marginally easier to debug.


I wind up doing things like this to get the functionality I want:

static string assert_processing_stage_defined (string stage)()
{
	static immutable error_msg = `Model must define processing 
stage: ` ~stage~ ` ()`;


return q{
		static assert (hasMember!(This, } ``~stage~`` q{), } 
~error_msg~ q{);
		static assert (isSomeFunction!(__traits(getMember, This, } 
``~stage~`` q{)), } ~error_msg~ q{);
		static assert (ParameterTypeTuple!(__traits(getMember, This, } 
``~stage~`` q{)).length == 0, } ~error_msg~ q{);
		static assert (is (ReturnType!(__traits(getMember, This, } 
``~stage~`` q{)) == void), } ~error_msg~ q{);

};
}

mixin(``
~assert_processing_stage_defined!`initialize`
~assert_processing_stage_defined!`update`
);

I'm sure theres worse ways to do it but I still find this ugly 
and overly specific. I would much rather use something like what 
Nordlöw suggested. Something that is standardized across the 
language and generates meaningful error messages.


Re: Compile-Time Interfaces (Concepts)

2014-07-19 Thread Nordlöw
On Thursday, 17 July 2014 at 23:44:56 UTC, H. S. Teoh via 
Digitalmars-d-learn wrote:
So you see, this has forced us to be more precise about exactly 
what an
input range is, instead of the current imprecise definition 
which leads
to subtle, corner case bugs like std.algorithm not handling 
transient

ranges correctly, etc..


Great answer. Thanks alot!


Re: Compile-Time Interfaces (Concepts)

2014-07-19 Thread Nordlöw

On Thursday, 17 July 2014 at 22:52:37 UTC, Justin Whear wrote:

static assert(isInputRange!SomeRange);


I'll use that for now.

Thx


Compile-Time Interfaces (Concepts)

2014-07-17 Thread Nordlöw

AFAIK there is no compile-time variant of interfaces right?

Why is that?

Wouldn't it be nice to say something like

struct SomeRange realize InputRange
{
/* implement members of InputRange */
}

and then the compiler will statically check that that all members 
are implemented correctly.


I guess this requires some new syntax to describe what an 
InputRange is.


Kind of like C++ Concepts.


Re: Compile-Time Interfaces (Concepts)

2014-07-17 Thread Justin Whear via Digitalmars-d-learn
On Thu, 17 Jul 2014 22:49:30 +, Nordlöw wrote:

 AFAIK there is no compile-time variant of interfaces right?
 
 Why is that?
 
 Wouldn't it be nice to say something like
 
  struct SomeRange realize InputRange {
  /* implement members of InputRange */
  }
 
 and then the compiler will statically check that that all members are
 implemented correctly.
 
 I guess this requires some new syntax to describe what an InputRange is.
 
 Kind of like C++ Concepts.

What benefits would accrue from adding this?  Static verification that a 
structure implements the specified concepts?  If so, you can simply do 
this instead:

static assert(isInputRange!SomeRange);


Re: Compile-Time Interfaces (Concepts)

2014-07-17 Thread Justin Whear via Digitalmars-d-learn
On Thu, 17 Jul 2014 23:06:30 +, bearophile wrote:

 Justin Whear:
 
 What benefits would accrue from adding this?  Static verification that
 a structure implements the specified concepts?
 
 Not just that, but also the other way around: static verification that a
 Concept is strictly sufficient for any instantiation of a specific
 template. This is what Haskell/Rust do.
 
 Bye,
 bearophile

By this do mean replacing the template constraint `if (isInputRange!R)` 
syntax?  If so, we need concept definition syntax, but we do not 
necessarily need a struct realizes concept syntax.  And, in fact, I 
would argue against it as a static assert would continue to be sufficient.


Re: Compile-Time Interfaces (Concepts)

2014-07-17 Thread bearophile via Digitalmars-d-learn

Justin Whear:

By this do mean replacing the template constraint `if 
(isInputRange!R)`

syntax?  If so, we need concept definition syntax, but we do not
necessarily need a struct realizes concept syntax.  And, in 
fact, I
would argue against it as a static assert would continue to be 
sufficient.


I was not suggesting to put Concepts (or typeclasses) in D (and 
Andrei is against this idea), I was just trying to explain the 
basic difference between template constraints and concepts :-)


Bye,
bearophile


Re: Compile-Time Interfaces (Concepts)

2014-07-17 Thread Dicebot via Digitalmars-d-learn

..and call it mixin interface :P