January 12, 2021
On Tuesday, 12 January 2021 at 21:32:46 UTC, Ola Fosheim Grøstad wrote:
> auto pop_second(T)(T* obj){
>     auto stack = obj.as_StackConcept();
>     static assert (is_StackConcept!(typeof(stack)));
> 	auto tmp = stack.pop();
>     auto tmp2 = stack.pop();
>     stack.push(tmp);
>     return tmp2;
> }

An improvement is to define a helper function:

auto as_stack(T)(T* obj){
    auto stack = obj.as_StackConcept();
    static assert (is_StackConcept!(typeof(stack)));
    return stack;
}


Then you can just do:

auto pop_second(T)(T* obj){
    auto stack = obj.as_stack();
    auto tmp = stack.pop();
    auto tmp2 = stack.pop();
    stack.push(tmp);
    return tmp2;
}


Or:

auto pop_second(T)(T* obj){
    auto tmp =  obj.as_stack.pop();
    auto tmp2 =  obj.as_stack.pop();
    obj.as_stack.push(tmp);
    return tmp2;
}




January 12, 2021
On Tuesday, 12 January 2021 at 21:32:46 UTC, Ola Fosheim Grøstad wrote:
> So, this is one, perhaps clumsy way of doing it:
>
[...]
>
> auto pop_second(T)(T* obj){
>     auto stack = obj.as_StackConcept();
>     static assert (is_StackConcept!(typeof(stack)));
> 	auto tmp = stack.pop();
>     auto tmp2 = stack.pop();
>     stack.push(tmp);
>     return tmp2;
> }

You have written a generic function that accepts any type (unconstrained `T`), but fails to instantiate for most of them (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.
January 12, 2021
On Tuesday, 12 January 2021 at 22:23:51 UTC, Paul Backus wrote:
> You have written a generic function that accepts any type (unconstrained `T`), but fails to instantiate for most of them (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.

Hm? pop_second requires StackConcept!(T,E) ?

January 12, 2021
On Tuesday, 12 January 2021 at 22:29:09 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 12 January 2021 at 22:23:51 UTC, Paul Backus wrote:
>> You have written a generic function that accepts any type (unconstrained `T`), but fails to instantiate for most of them (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.
>
> Hm? pop_second requires StackConcept!(T,E) ?

Works fine for me:


void push(int* x, bool b){ *x = (*x<<1)|b; }
bool pop(int* x){ bool tmp = *x&1; *x=*x>>1; return tmp; }
auto as_StackConcept(int* x){ return StackConcept!(int,bool)(x);}


void main()
{
    int stack = 5;
    pop_second(&stack);
    writeln(pop(&stack));
    writeln(pop(&stack));
}
January 12, 2021
On Tuesday, 12 January 2021 at 22:23:51 UTC, Paul Backus wrote:
> (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.

Maybe you want it to just bypass it to allow overloading? Then you just test for the presence of as_StackConcept as a constraint in the signature?


January 12, 2021
On Tuesday, 12 January 2021 at 22:41:03 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 12 January 2021 at 22:29:09 UTC, Ola Fosheim Grøstad wrote:
>> On Tuesday, 12 January 2021 at 22:23:51 UTC, Paul Backus wrote:
>>> You have written a generic function that accepts any type (unconstrained `T`), but fails to instantiate for most of them (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.
>>
>> Hm? pop_second requires StackConcept!(T,E) ?
>
> Works fine for me:
>
>
> void push(int* x, bool b){ *x = (*x<<1)|b; }
> bool pop(int* x){ bool tmp = *x&1; *x=*x>>1; return tmp; }
> auto as_StackConcept(int* x){ return StackConcept!(int,bool)(x);}
>
>
> void main()
> {
>     int stack = 5;
>     pop_second(&stack);
>     writeln(pop(&stack));
>     writeln(pop(&stack));
> }

What about

auto pop_second(T)(T* obj)
    if (__traits(compiles, {
            T input = T.init;
            auto stack = input.as_StackConcept();
        }))
{
    ...
}
January 12, 2021
On Tuesday, 12 January 2021 at 22:53:39 UTC, jmh530 wrote:
>
> What about
>
> auto pop_second(T)(T* obj)
>     if (__traits(compiles, {
>             T input = T.init;
>             auto stack = input.as_StackConcept();
>         }))
> {
>     ...
> }

Yes, something like that! Except we wrap it up as hasStackConcept!T.

So then you can use the constraint "if(hasStackConcept!T)"

January 12, 2021
On Tuesday, 12 January 2021 at 22:41:03 UTC, Ola Fosheim Grøstad wrote:
> On Tuesday, 12 January 2021 at 22:29:09 UTC, Ola Fosheim Grøstad wrote:
>> On Tuesday, 12 January 2021 at 22:23:51 UTC, Paul Backus wrote:
>>> You have written a generic function that accepts any type (unconstrained `T`), but fails to instantiate for most of them (e.g. `pop_second!int` would not compile). In a language like Rust or Java with type-checked generics, the compiler would reject this function definition.
>>
>> Hm? pop_second requires StackConcept!(T,E) ?
>
> Works fine for me:
>
> [...]

The goal is to make it produce a compile-time error given only the *definition* of `pop_second`--so, no main function, no unit tests, and no other usage code.

This is impossible to do in D (or C++) if `pop_second` is a template, because D (like C++) does not type-check uninstantiated templates.
January 12, 2021
On Tuesday, 12 January 2021 at 23:10:30 UTC, Paul Backus wrote:
> The goal is to make it produce a compile-time error given only the *definition* of `pop_second`--so, no main function, no unit tests, and no other usage code.

That's a bit pedantic. And it can never work because of static foreach.



January 12, 2021
On Tuesday, 12 January 2021 at 23:27:22 UTC, Ola Fosheim Grøstad wrote:
> That's a bit pedantic. And it can never work because of static foreach.

Well, I guess it could work, but it would be very challenging when you combine static foreach, static if, string mixins and recursive templates.

At some point you end up with an automatic theorem prover.