www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Constraints

reply =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
// SAMPLE CONSTRAINTS
//=============================================================

constraint CInputRange
{
	static assert (is(typeof(
	{
		typeof(this) r = void;
		if (r.empty) {}
		r.popFront();
		auto h = r.front;
	})));
}

constraint CForwardRange : CInputRange
{
	static assert (is(typeof(
	{
		typeof(this) r1 = void;
		typeof(this) r2 = r1.save;
	})));
}

constraint CBidirectionalRange : CForwardRange
{
	static assert (is(typeof(
	{
		typeof(this) r = void;
		r.popBack();
		auto t = r.back;
		auto w = r.front;
		static assert(is(typeof(t) == typeof(w)));
	})));
}

constraint CRandomAccessRange : CBidirectionalRange
	if (!isInfinite!typeof(this))
{
	static assert (is(typeof(
	{
		typeof(this) r = void;
		auto e = r[1];
	})));
	static assert(hasLength!typeof(this));
     static assert(!isNarrowString!typeof(this));
}

constraint CRandomAccessRange : CForwardRange
	if (isInfinite!typeof(this))
{
	static assert (is(typeof(
	{
		typeof(this) r = void;
		auto e = r[1];
	})));
}

// SAMPLE USAGES
//=========================================================

struct InputRange : CInputRange // Apply constraint to a struct
{
	....
}

struct ForwardRange // Do not apply any constraint but implement 
a ForwardRange
{
	....
}

interface IBidirectionalRange : CBidirectionalRange // Apply 
constraint to the classes derived from IBidirectionalRange
{
	....
}

class BidirectionalRange : IBidirectionalRange  // Implement 
BidirectionalRange and apply constraint CBidirectionalRange
{
	...
}

struct RandomAccessFinite : CRandomAccessRange
{
	...
}

struct RandomAccessInfinite : CRandomAccessRange
{
	...
}

//-----------------------------------------------------------

void foo(Range : CInputRange)(Range r) { }         // (1)
void foo(Range : CForwardRange)(Range r) { }       // (2)
void foo(Range : CBidirectionalRange)(Range r) { } // (3)
void foo(Range : CRandomAccessRange)(Range r) { }  // (4)

//-----------------------------------------------------------

void main()
{
	InputRange ir;
	ForwardRange fr;
	auto br = new BidirectionalRange();
	RandomAccessFinite rfr;
	RandomAccessInfinite rir;
	
	foo(ir);  // calls (1)
	foo(fr);  // calls (2)
	foo(br);  // calls (3)
	foo(rfr); // calls (4)
	foo(rir); // calls (4)
}
May 09 2012
next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
// implement foo's without constraints
//------------------------------------------------------------

void foo(Range)(Range r)
	if (isInputRange!Range && !isForwardRange!Range)
{ }

void foo(Range)(Range r)
	if (isForwardRange!Range && !isBidirectionalRange!Range &&
!isRandomAccessRange!Range)
{ }

void foo(Range)(Range r)
	if (isBidirectionalRange!Range && !isRandomAccessRange!Range)
{ }

void foo(Range)(Range r)
	if (isRandomAccessRange!Range)
{ }
May 09 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
Idea is simple: we need same constraints on "implementation" and 
"argument deduction. Syntax may change.
May 09 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
Sorry I mean "template specialization" instead of "argument 
deduction".
May 09 2012
prev sibling next sibling parent "Chris Cain" <clcain uncg.edu> writes:
We can already kind of do what you're asking without a language 
feature. For instance, if you want to define that something is a 
type of range...

struct MyRange { ... }

static assert(isInputRange!MyRange); // won't compile unless 
MyRange is an input range

On Wednesday, 9 May 2012 at 15:04:51 UTC, İbrahim Gökhan 
YANIKLAR wrote:
 // implement foo's without constraints
 //------------------------------------------------------------

 void foo(Range)(Range r)
 	if (isInputRange!Range && !isForwardRange!Range)
 { }

 void foo(Range)(Range r)
 	if (isForwardRange!Range && !isBidirectionalRange!Range &&
 !isRandomAccessRange!Range)
 { }

 void foo(Range)(Range r)
 	if (isBidirectionalRange!Range && !isRandomAccessRange!Range)
 { }

 void foo(Range)(Range r)
 	if (isRandomAccessRange!Range)
 { }

And these could certainly use some library sugar. How about this: template isJustInputRange(R) { enum bool isJustInputRange = isInputRange!R && !isForwardRange!R; } template isJustForwardRange(R) ...etc...
May 09 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
Allways we have some ways to do somethings.
The question is: which is better, easier and understandable.
I think my proposal is better.


 And these could certainly use some library sugar. How about 
 this:

 template isJustInputRange(R) {
     enum bool isJustInputRange = isInputRange!R && 
 !isForwardRange!R;
 }

If we add for example isBufferedInputRange, we have to change isJustInputRange too. It's not a general solution.
May 09 2012
prev sibling next sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
what is the huge difference between D's current concepts - except that 
your idea allows to derive from concepts?

http://dlang.org/concepts.html
May 09 2012
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 09.05.2012 19:07, schrieb "İbrahim Gökhan YANIKLAR" 
<yanikibo gmail.com>":
 We can not write a common interface for classes and structs.
 Concepts or constraints can provide that.

we can write a common interface for both - but not a contract checking one
May 09 2012
prev sibling parent reply dennis luehring <dl.soluz gmx.net> writes:
Am 09.05.2012 19:02, schrieb "İbrahim Gökhan YANIKLAR" 
<yanikibo gmail.com>":
 There is not a huge difference, but this idea can be extended.
 After your reply, I have found this proposal for C++.

 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf

D's concept/constrains system is more powerfull like these C++ concepts (which where discussed very much...) why do i need to derive from one of these concept if i just can write template Bar(T) if (isFloatingPoint!(T)) { ... } and i can combine these concept/constrains checkers without any problem to something like template Bar(T,A,B) if (isFloatingPointAndMySpecialXYZAndSomethingElse!(T,A,B)) { ... } try to compare D's concepts and the proposed C++ concepts and you will find minor differences - or try to show the differences and what your idea makes better
May 09 2012
next sibling parent dennis luehring <dl.soluz gmx.net> writes:
Am 10.05.2012 11:55, schrieb "İbrahim Gökhan YANIKLAR" 
<yanikibo gmail.com>":
 Concepts provide us a common interface for structs, classes,
 interfaces, even arrays.

but for what then interfaces are? but what concept should for example an array have? the typecheck of the array itself???
 Concepts can be practically extended.

if your world is very OOPish orientated - but the generic world keeps itself away from "derived functionality"
 Concepts can be used for template specialization and as compile
 time constraints and as a static interface.

D current concepts can also be used like that - you just implement a very lossy tied boolean expression (direct or as function) and thats it - that is pure generic thinking you don't need to be part of an hierarchy - just have the shape that is needed
 Also we can use concepts as traits like that:

 static if (is(T : Concept)) { }

 instead of

 static if (satisfiesConcept!T) { }

but the type should only satisfy the concept its does not need to derived from that - think of the thoundsand of specialised concept-classes that will occure (for example in phobos)
May 10 2012
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-05-10 11:42, "İbrahim Gökhan YANIKLAR" <yanikibo gmail.com>" wrote:
 concept CInputRange(R)
 {
 static assert (isDefinable!R);
 static assert (isRange!R);
 bool empty();
 void popFront();
 ElementType!R front();
 }

 concept CForwardRange(R) : CInputRange!R
 {
 R save();
 }

 concept CBidirectionalRange(R) : CForwardRange!R
 {
 void popBack();
 ElementType!R back();
 }

 concept CRandomAccessRange(R) : CBidirectionalRange!R
 if (!isInfinite!R)
 {
 static assert (is(typeof(R.init[1])));
 static assert(hasLength!R);
 static assert(!isNarrowString!R);
 }

 concept CRandomAccessRange(R) : CForwardRange!R
 if (isInfinite!R)
 {
 static assert (is(typeof(R.init[1])));
 }

 //-----------------------------------------------------------

 struct InputRange : CInputRange;
 // same as struct InputRange : CInputRange!InputRange

 struct ForwardRange;
 // Satisfies CForwardRange concept but don't apply it

 interface IBidirectionalRange : CBidirectionalRange;
 // Apply concept to the classes derived from IBidirectionalRange

 class BidirectionalRange : IBidirectionalRange;
 // Implement IBidirectionalRange and apply CBidirectionalRange

 struct RandomAccessFinite : CRandomAccessRange;

 struct RandomAccessInfinite : CRandomAccessRange;

 //-----------------------------------------------------------

 void foo(Range : CInputRange)(Range r) { }
 void foo(Range : CForwardRange)(Range r) { }
 void foo(Range : CBidirectionalRange)(Range r) { }
 void foo(Range : CRandomAccessRange)(Range r) { }

I like this one. Hopefully it could produce better error messages as well. -- /Jacob Carlborg
May 10 2012
prev sibling next sibling parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 5/10/12 4:41 AM, "İbrahim Gökhan YANIKLAR" <yanikibo gmail.com>" wrote:

Unrelated, but your name appears in Thunderbird as

=?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR"

I think this is Thunderbird's fault because forum.dlang.org shows it 
properly. Nevertheless I thought you should know.


Andrei
May 10 2012
parent reply Jacob Carlborg <doob me.com> writes:
On 2012-05-10 16:46, Andrei Alexandrescu wrote:
 On 5/10/12 4:41 AM, "İbrahim Gökhan YANIKLAR" <yanikibo gmail.com>" wrote:

 Unrelated, but your name appears in Thunderbird as

 =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR"

 I think this is Thunderbird's fault because forum.dlang.org shows it
 properly. Nevertheless I thought you should know.


 Andrei

I have no problem in Thunderbird 12, Mac OS X 10.7. -- /Jacob Carlborg
May 10 2012
parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 05/10/2012 09:50 AM, Jacob Carlborg wrote:
 On 2012-05-10 16:46, Andrei Alexandrescu wrote:
 On 5/10/12 4:41 AM, "İbrahim Gökhan YANIKLAR" <yanikibo gmail.com>"
 wrote:

 Unrelated, but your name appears in Thunderbird as

 =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR"

 I think this is Thunderbird's fault because forum.dlang.org shows it
 properly. Nevertheless I thought you should know.


 Andrei

I have no problem in Thunderbird 12, Mac OS X 10.7.

No problem in Thunderbird 11.0.1 on a lightweight Ubuntu. Ali -- D Programming Language Tutorial: http://ddili.org/ders/d.en/index.html
May 10 2012
prev sibling parent travert phare.normalesup.org (Christophe Travert) writes:
"Ibrahim Gokhan YANIKLAR" , dans le message (digitalmars.D:166850), a
 crit:

I would even have:

concept CInputRange(E)
{
	alias E ElementType;
	static assert (isDefinable!typeof(this));
	static assert (isRange!typeof(this));
	 property bool empty();
	 property void popFront();
	 property ElementType front();
}

Concepts allows to state your intent when you create a type. It self 
documents the code more nicely that a static assert. It would be 
much easier for newcomers to understand concepts. Finally, by creating a 
hierarchy, concepts allows to determine which is the more specialized 
template. Even if it is not a priority to add this to the langage, I 
don't think it is just syntactic sugar.


Several problems should be solved though:

concept CInfiniteRange(E) : CInputRange(E)
{
// empty was declared to be a property, here it is an enum.
      enum bool empty = false;
// or:
      final bool empty() { return false; }
}

struct SimpleCounter(E) : CInfiniteRange(E)
{
// front was declared as a property, here it is a member variable
    E front = 0;
    void popFront() { ++front; }
//or:
    E front_ = 0;
     property E front() const { return front_; } // now front is const
     property void popFront() { ++front_; }
}

It will not be obvious to define what is allowed and what is not so that 
the flexibility of current template constraints is reached, while 
keeping the definition natural.

-- 
Christophe
May 11 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
There is not a huge difference, but this idea can be extended.
After your reply, I have found this proposal for C++.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2081.pdf


On Wednesday, 9 May 2012 at 16:40:24 UTC, dennis luehring wrote:
 what is the huge difference between D's current concepts - 
 except that your idea allows to derive from concepts?

 http://dlang.org/concepts.html

May 09 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
We can not write a common interface for classes and structs. 
Concepts or constraints can provide that.
May 09 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
Sorry about my writing is not very good.

We may decide:
1) Which is nicer?
2) Which is easier?
3) Which is more readable and understandable?
4) Which is more automatic?
etc.

We can do all these stuff by using "boost::enable_if", 
"boost::mpl::and_", "boost::mpl::or_" in c++, but it is really 
hard to write, read and understand.

The question is: "Can we do it better?"

You can choose one of below:
May 10 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
concept CInputRange(R)
{
	static assert (isDefinable!R);
	static assert (isRange!R);
	bool empty();
	void popFront();
	ElementType!R front();
}

concept CForwardRange(R) : CInputRange!R
{
	R save();
}

concept CBidirectionalRange(R) : CForwardRange!R
{
	void popBack();
	ElementType!R back();
}

concept CRandomAccessRange(R) : CBidirectionalRange!R
	if (!isInfinite!R)
{
	static assert (is(typeof(R.init[1])));
	static assert(hasLength!R);
      static assert(!isNarrowString!R);
}

concept CRandomAccessRange(R) : CForwardRange!R
	if (isInfinite!R)
{
	static assert (is(typeof(R.init[1])));
}

//-----------------------------------------------------------

struct InputRange : CInputRange;
// same as struct InputRange : CInputRange!InputRange

struct ForwardRange;
// Satisfies CForwardRange concept but don't apply it

interface IBidirectionalRange : CBidirectionalRange;
// Apply concept to the classes derived from IBidirectionalRange

class BidirectionalRange : IBidirectionalRange;
// Implement IBidirectionalRange and apply CBidirectionalRange

struct RandomAccessFinite : CRandomAccessRange;

struct RandomAccessInfinite : CRandomAccessRange;

//-----------------------------------------------------------

void foo(Range : CInputRange)(Range r) { }
void foo(Range : CForwardRange)(Range r) { }
void foo(Range : CBidirectionalRange)(Range r) { }
void foo(Range : CRandomAccessRange)(Range r) { }
May 10 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
//====================================================
//==                   OR                          ===
//====================================================


template isInputRange(R)
{
     enum bool isInputRange = is(typeof(
     {
         R r = void;       // can define a range object
         if (r.empty) {}   // can test for empty
         r.popFront();     // can invoke popFront()
         auto h = r.front; // can get the front of the range
     }));
}

template isJustInputRange(R)
{
     enum bool isJustInputRange = isInputRange!R && 
!isForwardRange!R;
}

template isForwardRange(R)
{
     enum bool isForwardRange = isInputRange!R && is(typeof(
     {
         R r1 = void;
         R r2 = r1.save; // can call "save" against a range object
     }));
}

template isJustForwardRange(R)
{
     enum bool isJustForwardRange = isForwardRange!R && 
!isBidirectionalRange!R && !isRandomAccessRange!R;
}

template isBidirectionalRange(R)
{
     enum bool isBidirectionalRange = isForwardRange!R && 
is(typeof(
     {
         R r = void;
         r.popBack();
         auto t = r.back;
         auto w = r.front;
         static assert(is(typeof(t) == typeof(w)));
     }));
}

template isJustBidirectionalRange(R)
{
     enum bool isJustBidirectionalRange = isBidirectionalRange!R 
&& !isRandomAccessRange!R;
}

template isRandomAccessRange(R)
{
     enum bool isRandomAccessRange = is(typeof(
     {
         static assert(isBidirectionalRange!R ||
                       isForwardRange!R && isInfinite!R);
         R r = void;
         auto e = r[1];
         static assert(!isNarrowString!R);
         static assert(hasLength!R || isInfinite!R);
     }));
}

//-----------------------------------------------------------

struct InputRange
{
	....
	static assert (isInputRange!InputRange);
}

struct ForwardRange
{
	....
	static assert (isForwardRange!ForwardRange);
}

interface IBidirectionalRange
{
	....
	// static assert (isBidirectionalRange!IBidirectionalRange);
	// can not be used in interfaces
}

class BidirectionalRange : IBidirectionalRange
{
	...
	static assert (isBidirectionalRange!BidirectionalRange); 	
}

struct RandomAccessFinite
{
	...
	static assert (isRandomAccessRange!RandomAccessFinite);
}

struct RandomAccessInfinite
{
	...
	static assert (isRandomAccessRange!RandomAccessInfinite);
}

//-----------------------------------------------------------

void foo(Range)(Range r) if (isJustInputRange!Range) { }
void foo(Range)(Range r) if (isJustForwardRange!Range) { }
void foo(Range)(Range r) if (isJustBidirectionalRange!Range) { }
void foo(Range)(Range r) if (isRandomAccessRange!Range) { }
May 10 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
Concepts provide us a common interface for structs, classes, 
interfaces, even arrays.
Concepts can be practically extended.
Concepts can be used for template specialization and as compile 
time constraints and as a static interface.

Also we can use concepts as traits like that:

static if (is(T : Concept)) { }

instead of

static if (satisfiesConcept!T) { }
May 10 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
When I see a better interface than D in another language, it 
really bothers me.
May 10 2012
prev sibling next sibling parent =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR" <yanikibo gmail.com> writes:
 but for what then interfaces are?

Interfaces are for classes, and provides a virtual interface. Concepts are for all, and provides a generic, static interface. Not to use as base class.
 but what concept should for example an array have? the 
 typecheck of the array itself???

For example CInputRange can be used for arrays, or other ranges that did not derived from CInputRange. It's only have some constraints.
 if your world is very OOPish orientated - but the generic world
 keeps itself away from "derived functionality"

Not derived functionality, derived constraints. When you derive a concept you only compose the constraints by AND logic.
 but the type should only satisfy the concept
 its does not need to derived from that - think of the thoundsand
 of specialised concept-classes that will occure (for example in 
 phobos)

You can use a different syntax instead of inheritance. Simple things should be done by using template constraints. I did not offer to remove template constraints. So if you need an interface like Ranges you use concepts, if you don't need an interface you use template constraints.
May 10 2012
prev sibling next sibling parent "Chris Cain" <clcain uncg.edu> writes:
I do kind of like your way better, as it's more succinct and 
clear. As of right now I rarely use classes in D because they 
just aren't necessary in most cases, and using structs with 
templates is nearly as powerful and (probably) generates faster 
code (although, probably fatter code as well as it has to make 
several versions of the same functions depending on the types).

With your idea, it seems like I would have even less need for 
classes because you can specify "interfaces" to that generic code.

That all said, I think your code is tiny bit unrealistic in terms 
of usage for these things which make them look far more useful 
than they really would be. Take, for instance, some actual code:

https://gist.github.com/2d32de50d2e856c00e9d#file_insert_back.d

So, in this case, I see no potential savings at all. I'd still 
have to have "isImplicitlyConvertible" in there and therefore I'd 
still need the current constraint on the method. My insertFront 
method is more complicated:

https://gist.github.com/2d32de50d2e856c00e9d#file_insert_front.d

But even though it's more complicated, I'd also like to see how 
your method would simplify this as well.

Overall, I think it sounds nice in theory, but I'm just not sure 
how effective it will be in practice.

I hope I'm not asking too much of you... I'm not trying to 
discourage you, I'm asking genuine questions about how this will 
work on more realistic code.

On Thursday, 10 May 2012 at 09:43:00 UTC, İbrahim Gökhan 
YANIKLAR wrote:
 concept CInputRange(R)
 {
 	static assert (isDefinable!R);
 	static assert (isRange!R);
 	bool empty();
 	void popFront();
 	ElementType!R front();
 }

Also, something that would _have_ to be solved is ElementType!R ... as of right now, ElementType!R figures out what a range holds by what its front() property returns. So, I think this definition would be invalid. However, once we can show that this will improve things on real code and these things are sorted out, I wouldn't mind seeing this in the language.
May 10 2012
prev sibling next sibling parent Sean Kelly <sean invisibleduck.org> writes:
On May 10, 2012, at 7:46 AM, Andrei Alexandrescu wrote:

 On 5/10/12 4:41 AM, "=C4=B0brahim G=C3=B6khan YANIKLAR" =

=20
 Unrelated, but your name appears in Thunderbird as
=20
 =3D?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=3D?=3D YANIKLAR"
=20
 I think this is Thunderbird's fault because forum.dlang.org shows it =

I haven't seen an email client yet that fully supports Q-encoding (well, = except the one I wrote of course ;-)). At a glance, that looks = correctly formatted. In short, the underlying data is in UTF-8, and the = "B" means that the payload is encoded as Base64. If anyone cares to = file a bug with Thunderbird, it's RFC 2047. To be fair to the = Thunderbird folks, the problem may actually be that they're doing the = full RFC required validation to determine if something is Q-encoded. = The sad truth is that basically no clients obey all the formatting = rules, and nearly all the required validation has to be disabled or a = huge percentage of stuff meant to be Q-encoded is rejected as invalid = and displayed as-is.=
May 10 2012
prev sibling next sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, May 10, 2012 09:46:42 Andrei Alexandrescu wrote:
 On 5/10/12 4:41 AM, "İbrahim Gökhan YANIKLAR" <yanikibo gmail.com>" wrote:
 
 Unrelated, but your name appears in Thunderbird as
 
 =?UTF-8?B?IsSwYnJhaGltIEfDtmtoYW4=?= YANIKLAR"
 
 I think this is Thunderbird's fault because forum.dlang.org shows it
 properly. Nevertheless I thought you should know.

Kmail does the same. It didn't even occur to me that that ridiculous string _wasn't_ his username. I was tempted to point out how ridicilous a name it was but didn't want to be rude. - Jonathan M Davis
May 10 2012
prev sibling next sibling parent "Ibrahim Gokhan YANIKLAR" <yanikibo gmail.com> writes:
On Thursday, 10 May 2012 at 14:44:00 UTC, Chris Cain wrote:
 I do kind of like your way better, as it's more succinct and 
 clear. As of right now I rarely use classes in D because they 
 just aren't necessary in most cases, and using structs with 
 templates is nearly as powerful and (probably) generates faster 
 code (although, probably fatter code as well as it has to make 
 several versions of the same functions depending on the types).

 With your idea, it seems like I would have even less need for 
 classes because you can specify "interfaces" to that generic 
 code.

 That all said, I think your code is tiny bit unrealistic in 
 terms of usage for these things which make them look far more 
 useful than they really would be. Take, for instance, some 
 actual code:

 https://gist.github.com/2d32de50d2e856c00e9d#file_insert_back.d

 So, in this case, I see no potential savings at all. I'd still 
 have to have "isImplicitlyConvertible" in there and therefore 
 I'd still need the current constraint on the method. My 
 insertFront method is more complicated:

 https://gist.github.com/2d32de50d2e856c00e9d#file_insert_front.d

isImplicitlyConvertible have to be there because it belongs to a template parameter out of the member function template parameters.
 But even though it's more complicated, I'd also like to see how 
 your method would simplify this as well.

void insertFront(U : T)(U item) { ... } void insertFront(Range : CBidirectionalRange)(Range r) if(isImplicitlyConvertible!(ElementType!Range, T)) { ... } void insertFront(Range : CInputRange)(Range r) if(isImplicitlyConvertible!(ElementType!Range, T)) { ... }
 Overall, I think it sounds nice in theory, but I'm just not 
 sure how effective it will be in practice.

 I hope I'm not asking too much of you... I'm not trying to 
 discourage you, I'm asking genuine questions about how this 
 will work on more realistic code.

 On Thursday, 10 May 2012 at 09:43:00 UTC, İbrahim Gökhan 
 YANIKLAR wrote:
 concept CInputRange(R)
 {
 	static assert (isDefinable!R);
 	static assert (isRange!R);
 	bool empty();
 	void popFront();
 	ElementType!R front();
 }

Also, something that would _have_ to be solved is ElementType!R ... as of right now, ElementType!R figures out what a range holds by what its front() property returns. So, I think this definition would be invalid.

It can be fixed like that: concept CInputRange(R, E) { static assert (isDefinable!R); static assert (isRange!R); bool empty(); void popFront(); E front(); } concept CForwardRange(R, E) : CInputRange!(R, E) { R save(); } concept CBidirectionalRange(R, E) : CForwardRange!(R, E) { void popBack(); E back(); } concept CRandomAccessRange(R, E) : CBidirectionalRange!(R, E) if (!isInfinite!R) { static assert (is(typeof(R.init[1]))); static assert(hasLength!R); static assert(!isNarrowString!R); } concept CRandomAccessRange(R, E) : CForwardRange!(R, E) if (isInfinite!R) { static assert (is(typeof(R.init[1]))); } The first template parameter is reserved for "typeof(this)", the others are deduced automatically.
 However, once we can show that this will improve things on real 
 code and these things are sorted out, I wouldn't mind seeing 
 this in the language.

When we prefer generic programming rather than oop (where oop is applicable), we will absolutely need an interface to make things as simple and practical as oop. Interfaces are not used always for polymorphism, sometimes we need only an interface to satisfy common needs. Sometimes the current status of D canalizes us to use classes and interfaces although it is not effective. The concept concept may meet these needs. :)
May 10 2012
prev sibling next sibling parent "Ibrahim Gokhan YANIKLAR" <yanikibo gmail.com> writes:
 void insertFront(U : T)(U item) { ... }

 void insertFront(Range : CBidirectionalRange)(Range r)
 	if(isImplicitlyConvertible!(ElementType!Range, T)) { ... }

 void insertFront(Range : CInputRange)(Range r)
 	if(isImplicitlyConvertible!(ElementType!Range, T)) { ... }

An alternative solution: concept CInputRange(R, E, T = E) { static assert (isDefinable!R); static assert (isRange!R); bool empty(); void popFront(); E front(); static assert (isImplicitlyConvertible!(E, T)); } concept CForwardRange(R, E, T = E) : CInputRange!(R, E, T) { R save(); } concept CBidirectionalRange(R, E, T = E) : CForwardRange!(R, E, T) { void popBack(); E back(); } concept CRandomAccessRange(R, E, T = E) : CBidirectionalRange!(R, E, T) if (!isInfinite!R) { static assert (is(typeof(R.init[1]))); static assert(hasLength!R); static assert(!isNarrowString!R); } concept CRandomAccessRange(R, E, T = E) : CForwardRange!(R, E, T) if (isInfinite!R) { static assert (is(typeof(R.init[1]))); } Then we can use this concepts in your functions like: void insertFront(U : T)(U item) { ... } void insertFront(Range : CBidirectionalRange!T)(Range r) { ... } void insertFront(Range : CInputRange!T)(Range r) { ... } The rule is simple: Do not specify the first parameter (e.g. "R": reserved for typeof(this)) and the automatically deduced parameters (e.g. "E": deduced from return type of "front()").
May 10 2012
prev sibling parent "Ibrahim Gokhan YANIKLAR" <yanikibo gmail.com> writes:
On Friday, 11 May 2012 at 07:58:54 UTC, 
travert phare.normalesup.org (Christophe Travert) wrote:
 "Ibrahim Gokhan YANIKLAR" , dans le message 
 (digitalmars.D:166850), a
  écrit :

 I would even have:

 concept CInputRange(E)
 {
 	alias E ElementType;
 	static assert (isDefinable!typeof(this));
 	static assert (isRange!typeof(this));
 	 property bool empty();
 	 property void popFront();
 	 property ElementType front();
 }

 Concepts allows to state your intent when you create a type. It 
 self
 documents the code more nicely that a static assert. It would be
 much easier for newcomers to understand concepts. Finally, by 
 creating a
 hierarchy, concepts allows to determine which is the more 
 specialized
 template. Even if it is not a priority to add this to the 
 langage, I
 don't think it is just syntactic sugar.


 Several problems should be solved though:

 concept CInfiniteRange(E) : CInputRange(E)
 {
 // empty was declared to be a property, here it is an enum.
       enum bool empty = false;
 // or:
       final bool empty() { return false; }
 }

 struct SimpleCounter(E) : CInfiniteRange(E)
 {
 // front was declared as a property, here it is a member 
 variable
     E front = 0;
     void popFront() { ++front; }
 //or:
     E front_ = 0;
      property E front() const { return front_; } // now front 
 is const
      property void popFront() { ++front_; }
 }

 It will not be obvious to define what is allowed and what is 
 not so that
 the flexibility of current template constraints is reached, 
 while
 keeping the definition natural.

Fixed: concept CInputRange(R, E, T = E) { static assert (isDefinable!R); static assert (isRange!R); property bool empty(); void popFront(); property E front(); static assert (isImplicitlyConvertible!(E, T)); } concept CForwardRange(R, E, T = E) : CInputRange!(R, E, T) { property R save(); } concept CBidirectionalRange(R, E, T = E) : CForwardRange!(R, E, T) { void popBack(); property E back(); } concept CRandomAccessRange(R, E, T = E) : CBidirectionalRange!(R, E, T) if (!isInfinite!R) { static assert (is(typeof(R.init[1]))); static assert(hasLength!R); static assert(!isNarrowString!R); } concept CRandomAccessRange(R, E, T = E) : CForwardRange!(R, E, T) if (isInfinite!R) { static assert (is(typeof(R.init[1]))); } Using the first template parameter as typeof(this) is more effective. The ElementType ( E ) can be deduced from the type ( or return type ) of front. When we declare front as a property, it should match both property functions and enums.
May 11 2012