Jump to page: 1 2
Thread overview
Generic collection/element function signatures in D2 versus D1
Sep 04, 2010
Nick Sabalausky
Sep 04, 2010
Nick Sabalausky
Sep 04, 2010
Jacob Carlborg
Sep 12, 2010
Nick Sabalausky
Sep 12, 2010
Brad Roberts
Sep 05, 2010
Jonathan M Davis
Sep 05, 2010
BLS
Sep 07, 2010
Jacob Carlborg
Sep 07, 2010
Pelle
Sep 07, 2010
Pelle
Sep 08, 2010
Pelle
Sep 07, 2010
Jacob Carlborg
September 04, 2010
In D1 I did this sort of thing a fair amount:

void foo(T)(T[] collection, T elem)
{
    // Blah, whatever
}

Worked for any of the string types, worked for any array, or anything with the appropriate opIndexes, and for all I know there may be some improvement that could still be made. But of course, in D2 strings have that extra immutable part that mucks up the above for strings (and then there's ranges), so: Is there a typical generally-best way in D2 to declare a function signature for operating on collections and elements? I know it would involve using the standard range interfaces in the body and choosing the most restrictive range type that gets the job done, and I'm fine with all that, but is there a good example of a typical "best-practice" generic-function signature in D2?

-------------------------------
Not sent from an iPhone.


September 04, 2010
"Nick Sabalausky" <a@a.a> wrote in message news:i5su5e$23mk$1@digitalmars.com...
> In D1 I did this sort of thing a fair amount:
>
> void foo(T)(T[] collection, T elem)
> {
>    // Blah, whatever
> }
>
> Worked for any of the string types, worked for any array, or anything with the appropriate opIndexes, and for all I know there may be some improvement that could still be made. But of course, in D2 strings have that extra immutable part that mucks up the above for strings (and then there's ranges), so: Is there a typical generally-best way in D2 to declare a function signature for operating on collections and elements? I know it would involve using the standard range interfaces in the body and choosing the most restrictive range type that gets the job done, and I'm fine with all that, but is there a good example of a typical "best-practice" generic-function signature in D2?
>

Oh, also, and perhaps more importantly (I forgot, this was my main original reason for even posting the question):

What would be the *right* D2 version of the above code that *didn't* bother with ranges, and just stuck with arrays and strings? Sometimes I need to do something in CTFE and using ranges leads to using "std.algorithm", and CTFE still tends to choke on a lot of "std.algorithm".


September 04, 2010
On 2010-09-04 10:02, Nick Sabalausky wrote:
> "Nick Sabalausky"<a@a.a>  wrote in message
> news:i5su5e$23mk$1@digitalmars.com...
>> In D1 I did this sort of thing a fair amount:
>>
>> void foo(T)(T[] collection, T elem)
>> {
>>     // Blah, whatever
>> }
>>
>> Worked for any of the string types, worked for any array, or anything with
>> the appropriate opIndexes, and for all I know there may be some
>> improvement that could still be made. But of course, in D2 strings have
>> that extra immutable part that mucks up the above for strings (and then
>> there's ranges), so: Is there a typical generally-best way in D2 to
>> declare a function signature for operating on collections and elements? I
>> know it would involve using the standard range interfaces in the body and
>> choosing the most restrictive range type that gets the job done, and I'm
>> fine with all that, but is there a good example of a typical
>> "best-practice" generic-function signature in D2?
>>
>
> Oh, also, and perhaps more importantly (I forgot, this was my main original
> reason for even posting the question):
>
> What would be the *right* D2 version of the above code that *didn't* bother
> with ranges, and just stuck with arrays and strings? Sometimes I need to do
> something in CTFE and using ranges leads to using "std.algorithm", and CTFE
> still tends to choke on a lot of "std.algorithm".

If you're not going to modify the content of the array I think this will work:

void foo (T) (const(T)[] collection, T elem) {}

This will allow both mutable, immutable and const arrays. But it will not let you modify the array like this:

collection[3] = 'a';


-- 
/Jacob Carlborg
September 05, 2010
On Saturday 04 September 2010 00:57:48 Nick Sabalausky wrote:
> In D1 I did this sort of thing a fair amount:
> 
> void foo(T)(T[] collection, T elem)
> {
>     // Blah, whatever
> }
> 
> Worked for any of the string types, worked for any array, or anything with the appropriate opIndexes, and for all I know there may be some improvement that could still be made. But of course, in D2 strings have that extra immutable part that mucks up the above for strings (and then there's ranges), so: Is there a typical generally-best way in D2 to declare a function signature for operating on collections and elements? I know it would involve using the standard range interfaces in the body and choosing the most restrictive range type that gets the job done, and I'm fine with all that, but is there a good example of a typical "best-practice" generic-function signature in D2?
> 
> -------------------------------
> Not sent from an iPhone.

Okay, here's a shot at it:

import std.algorithm;
import std.array;
import std.container;
import std.stdio;
import std.traits;

void foo(T, U)(T collection, U elem)
    if(is(U : Unqual!(typeof(collection[].front))))
{
    if(elem == collection.front)
        writefln("%s == %s", elem, collection.front);
    else
        writefln("%s != %s", elem, collection.front);
}

void bar(R, U)(R range, U elem)
    if(is(U : Unqual!(typeof(range.front))))
{
    if(elem == range.front)
        writefln("%s == %s", elem, range.front);
    else
        writefln("%s != %s", elem, range.front);
}

void main()
{
    dstring a = "hello world";
    foo(a, 'h');
    foo(a, 'g');
    bar(a, 'h');
    bar(a, 'g');

    writeln();
    Array!int b;
    b.insert(1);
    b.insert(2);
    b.insert(3);

    foo(b, 1);
    foo(b, 2);
    bar(b, 1);
    bar(b, 2);

    writeln();
    SList!int c;
    c.insert(3);
    c.insert(2);
    c.insert(1);

    foo(c, 1);
    foo(c, 2);
    bar(c, 1);
    bar(c, 2);

    writeln();
    auto d = find(c[], 2);

    bar(d, 1);
    bar(d, 2);
}


foo() takes a container type where you can get a range to the whole thing with a slice, and bar() works on ranges. However, it looks like all of the containers in std.container currently implement front(), so both foo() and bar() work on them. Of course, if you doing stuff that isn't on a range, then bar() wouldn't work, and foo() won't work on ranges. So, which you want probably depends on what you're trying to do. A function like bar will work on more but will be restricted to range-base operations only. And depending on what you do in a function like bar(), you might need more template constraints to constrain the type of range.

I haven't tried any of this with CTFE, but the function signatures should work just fine with it. Whether you can use CTFE should therefore be a question of what you try to do in the function.

In any case, I think that Unqual is the secret sauce that you're looking for here.

- Jonathan M Davis
September 05, 2010
On 05/09/2010 02:16, Jonathan M Davis wrote:
> void foo(T)(T[] collection, T elem)
>>  {
>>       // Blah, whatever
>>  }
>>

I am curious, how this will look and feel once inout is working ?

inout void foo(T)(inout(T)[] collection, inout T elem)
{
  // Blah, whatever}
}

September 07, 2010
On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy@hotmail.de> wrote:

> On 05/09/2010 02:16, Jonathan M Davis wrote:
>> void foo(T)(T[] collection, T elem)
>>>  {
>>>       // Blah, whatever
>>>  }
>>>
>
> I am curious, how this will look and feel once inout is working ?
>
> inout void foo(T)(inout(T)[] collection, inout T elem)
> {
>    // Blah, whatever}
> }
>

inout void doesn't make any sense.  You can't have a const void or immutable void.

Now, if foo is a member function, then inout applies to the "this" pointer, but even then, you need a return type other than void for inout to be used.

-Steve
September 07, 2010
On 2010-09-07 14:49, Steven Schveighoffer wrote:
> On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy@hotmail.de> wrote:
>
>> On 05/09/2010 02:16, Jonathan M Davis wrote:
>>> void foo(T)(T[] collection, T elem)
>>>> {
>>>> // Blah, whatever
>>>> }
>>>>
>>
>> I am curious, how this will look and feel once inout is working ?
>>
>> inout void foo(T)(inout(T)[] collection, inout T elem)
>> {
>> // Blah, whatever}
>> }
>>
>
> inout void doesn't make any sense. You can't have a const void or
> immutable void.
>
> Now, if foo is a member function, then inout applies to the "this"
> pointer, but even then, you need a return type other than void for inout
> to be used.
>
> -Steve

inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable.

-- 
/Jacob Carlborg
September 07, 2010
On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob@me.com> wrote:

> On 2010-09-07 14:49, Steven Schveighoffer wrote:
>> On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy@hotmail.de> wrote:
>>
>>> On 05/09/2010 02:16, Jonathan M Davis wrote:
>>>> void foo(T)(T[] collection, T elem)
>>>>> {
>>>>> // Blah, whatever
>>>>> }
>>>>>
>>>
>>> I am curious, how this will look and feel once inout is working ?
>>>
>>> inout void foo(T)(inout(T)[] collection, inout T elem)
>>> {
>>> // Blah, whatever}
>>> }
>>>
>>
>> inout void doesn't make any sense. You can't have a const void or
>> immutable void.
>>
>> Now, if foo is a member function, then inout applies to the "this"
>> pointer, but even then, you need a return type other than void for inout
>> to be used.
>>
>> -Steve
>
> inout is only used when you want to return the same constness (mutable, const, immutable) as you passed in to the function. If you don't want that, or don't want to return anything then const(T)[] is what you want. It will accept mutable, const and immutable.

Yes, exactly.  This is why inout functions cannot return void.

-Steve
September 07, 2010
On 09/07/2010 03:15 PM, Steven Schveighoffer wrote:
> On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob@me.com> wrote:
>
>> On 2010-09-07 14:49, Steven Schveighoffer wrote:
>>> On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy@hotmail.de> wrote:
>>>
>>>> On 05/09/2010 02:16, Jonathan M Davis wrote:
>>>>> void foo(T)(T[] collection, T elem)
>>>>>> {
>>>>>> // Blah, whatever
>>>>>> }
>>>>>>
>>>>
>>>> I am curious, how this will look and feel once inout is working ?
>>>>
>>>> inout void foo(T)(inout(T)[] collection, inout T elem)
>>>> {
>>>> // Blah, whatever}
>>>> }
>>>>
>>>
>>> inout void doesn't make any sense. You can't have a const void or
>>> immutable void.
>>>
>>> Now, if foo is a member function, then inout applies to the "this"
>>> pointer, but even then, you need a return type other than void for inout
>>> to be used.
>>>
>>> -Steve
>>
>> inout is only used when you want to return the same constness
>> (mutable, const, immutable) as you passed in to the function. If you
>> don't want that, or don't want to return anything then const(T)[] is
>> what you want. It will accept mutable, const and immutable.
>
> Yes, exactly. This is why inout functions cannot return void.
>
> -Steve

Hmm.

class C {
    void foo(void delegate(inout(C)) f) inout {
        f(this);
    }
}

Am I missing something?
September 07, 2010
On Tue, 07 Sep 2010 09:28:18 -0400, Pelle <pelle.mansson@gmail.com> wrote:

> On 09/07/2010 03:15 PM, Steven Schveighoffer wrote:
>> On Tue, 07 Sep 2010 08:56:15 -0400, Jacob Carlborg <doob@me.com> wrote:
>>
>>> On 2010-09-07 14:49, Steven Schveighoffer wrote:
>>>> On Sun, 05 Sep 2010 09:40:59 -0400, BLS <windevguy@hotmail.de> wrote:
>>>>
>>>>> On 05/09/2010 02:16, Jonathan M Davis wrote:
>>>>>> void foo(T)(T[] collection, T elem)
>>>>>>> {
>>>>>>> // Blah, whatever
>>>>>>> }
>>>>>>>
>>>>>
>>>>> I am curious, how this will look and feel once inout is working ?
>>>>>
>>>>> inout void foo(T)(inout(T)[] collection, inout T elem)
>>>>> {
>>>>> // Blah, whatever}
>>>>> }
>>>>>
>>>>
>>>> inout void doesn't make any sense. You can't have a const void or
>>>> immutable void.
>>>>
>>>> Now, if foo is a member function, then inout applies to the "this"
>>>> pointer, but even then, you need a return type other than void for inout
>>>> to be used.
>>>>
>>>> -Steve
>>>
>>> inout is only used when you want to return the same constness
>>> (mutable, const, immutable) as you passed in to the function. If you
>>> don't want that, or don't want to return anything then const(T)[] is
>>> what you want. It will accept mutable, const and immutable.
>>
>> Yes, exactly. This is why inout functions cannot return void.
>>
>> -Steve
>
> Hmm.
>
> class C {
>      void foo(void delegate(inout(C)) f) inout {
>          f(this);
>      }
> }
>
> Am I missing something?

Yes, a valid return.  Your function should be:

void foo(void delegate(const(C) f) const

It helps to understand that inout/const/immutable has NOTHING to do with code generation, it only has to do with limiting what compiles.  For this reason, an inout function is compiled once, and works on all three constancies (4 if you have a nested inout function).  For the entire function any inout variable is treated as a non-changeable value, just like const.  Then when you return, it's converted at the call site back to the constancy with which it was called.  If the return value is void, then there's nothing to convert, and no reason to use inout over const.

I'll repeat -- there is no benefit to inout if you are not returning anything.

-Steve
« First   ‹ Prev
1 2