View mode: basic / threaded / horizontal-split · Log in · Help
May 09, 2012
Re: Constraints
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 10, 2012
Re: Constraints
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
Re: Constraints
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
Re: Constraints
//====================================================
//==                   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
Re: Constraints
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
Re: Constraints
When I see a better interface than D in another language, it 
really bothers me.
May 10, 2012
Re: Constraints
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
Re: Constraints
> 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
Re: Constraints
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
Re: Constraints
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.
1 2 3
Top | Discussion index | About this forum | D home