January 19, 2019
On Friday, 18 January 2019 at 23:10:12 UTC, luckoverthere wrote:
> On Friday, 18 January 2019 at 12:35:33 UTC, Nicholas Wilson wrote:
>> q.enqueue!(f!(args))(arg_set1)(arg_set2);
>>
>> and the function within that needs `g` also needs `f`. The expected usage is a whole lot of those calls all in one spot with different `f`, `args`, `arg_set1`, `arg_set2` I really don't want the user to have to repeat themselves anymore than absolutely necessary.
>
> Isn't that the usual argument between using globals and not using them. It's a lot cleaner when using them, especially when it is some sort of data that needs to be passed to basically everything. But then you deal with the joys of globals.
>
> The use case for this is very narrow and the implementation is error prone.

How do you know? I don't think it would be all that much more complex than default arguments.

> Having to go through and check functions to see which one's have altered behavior in a with statement isn't going to be fun.

grep?  ^f? Also again, this isn't any worse than default arguments.

> In the general case this doesn't make any sense,

That is a bold claim: have a watch of Martin's keynote.

> eg I don't see this being used anywhere in phobos at all.

Of course not, phobos doesn't deal in contexts (except maybe std.concurrency / std.parallelism, IDK, I haven't looked at their implementation). That doesn't mean that lots of other code doesn't.

> It'd be the very specific case of an API that needs to pass around some sort of state-like object a bunch of functions.
>
> The rationale is also pretty weak, you want reduce the number of arguments you have to pass in this one specific use case.

The case of dealing with contexts is hardly unique to me.

> Honestly from the looks of that function call, it might be better just finding a better way of implementing whatever it is you are trying to implement.

Its globals or this, and I'd rather not use globals. More specifically, in

q.enqueue!(f!(args))(arg_set1)(arg_set2);

arg_set1 is the shape of the kernel dispatch and (if `q` is an out of order Queue) the dependency list of enqueue and other things that need to finish before the (user supplied) kernel `f` executes.

arg_set2 relates to Parameters!f

there is no logical room to put it, it belongs in neither of the two argument lists.
January 19, 2019
On Saturday, 19 January 2019 at 00:23:40 UTC, Nicholas Wilson wrote:
> On Friday, 18 January 2019 at 23:10:12 UTC, luckoverthere wrote:
>> On Friday, 18 January 2019 at 12:35:33 UTC, Nicholas Wilson wrote:
>>> q.enqueue!(f!(args))(arg_set1)(arg_set2);
>>>
>>> and the function within that needs `g` also needs `f`. The expected usage is a whole lot of those calls all in one spot with different `f`, `args`, `arg_set1`, `arg_set2` I really don't want the user to have to repeat themselves anymore than absolutely necessary.
>>
>> Isn't that the usual argument between using globals and not using them. It's a lot cleaner when using them, especially when it is some sort of data that needs to be passed to basically everything. But then you deal with the joys of globals.
>>
>> The use case for this is very narrow and the implementation is error prone.
>
> How do you know? I don't think it would be all that much more complex than default arguments.

Default arguments don't change. In every context you look the function will behave the same way no matter where it is used. It'd be no different than adding an overload. With the with statement though, it'd not obvious where it might be used.

>> Having to go through and check functions to see which one's have altered behavior in a with statement isn't going to be fun.
>
> grep?  ^f? Also again, this isn't any worse than default arguments.

You can't grep or find because the with statement removes it all entirely. That's sort of my point, you'd have to look at every function definition to see which ones get modified. At the call point you have no indication that the behavior is different. It's not the same as default arguments. You can tell at call point the number of parameters being passed to the function, and the behavior is the same everywhere that function is used. The two are absolutely different. The behavior of your suggested feature changes based on scope and context.

>> In the general case this doesn't make any sense,
>
> That is a bold claim: have a watch of Martin's keynote.

Why did you split my sentence in half? You agree with me in the reply to the example given with this sentence.

>> It'd be the very specific case of an API that needs to pass around some sort of state-like object a bunch of functions.
>>
>> The rationale is also pretty weak, you want reduce the number of arguments you have to pass in this one specific use case.
>
> The case of dealing with contexts is hardly unique to me.

Contexts is the specific use case, not you.

>> Honestly from the looks of that function call, it might be better just finding a better way of implementing whatever it is you are trying to implement.
>
> Its globals or this, and I'd rather not use globals. More specifically, in
>
> q.enqueue!(f!(args))(arg_set1)(arg_set2);
>
> arg_set1 is the shape of the kernel dispatch and (if `q` is an out of order Queue) the dependency list of enqueue and other things that need to finish before the (user supplied) kernel `f` executes.
>
> arg_set2 relates to Parameters!f
>
> there is no logical room to put it, it belongs in neither of the two argument lists.

Even if you were to use a global or this new proposed "with" feature, that function call is atrocious. That is what I meant by finding a better way of implementing what you are trying to do.

January 19, 2019
On Saturday, 19 January 2019 at 00:51:28 UTC, luckoverthere wrote:
> On Saturday, 19 January 2019 at 00:23:40 UTC, Nicholas Wilson wrote:
>> How do you know? I don't think it would be all that much more complex than default arguments.
>
> Default arguments don't change. In every context you look the function will behave the same way no matter where it is used. It'd be no different than adding an overload. With the with statement though, it'd not obvious where it might be used.

Yes they can: https://run.dlang.io/is/IEQb0O
This would be like that, except: a) without the global, and b) you specifying that you want to use `a` where a implicit int parameter is expected.

> You can't grep or find because the with statement removes it all entirely.

Uh, yes you can: "grep with", it will show up in the function signature _and_ in the scope of the call site. Its like being able to grep for "cast" (which is literally the entire reason for having cast as a keyword).

> That's sort of my point, you'd have to look at every function definition to see which ones get modified. At the call point you have no indication that the behavior is different.

Again this is not different to default parameters, also you have a `with (foo)` in scope.

> It's not the same as default arguments. You can tell at call point the number of parameters being passed to the function, and the behavior is the same everywhere that function is used. The two are absolutely different.

What? Firstly with default parameters you _can't_ tell how many parameters are actually passed to the function at the call site. Secondly, this is _exactly_ the same as default parameters. But also like default parameters, you typically don't care because they are default for a reason i.e. the defaults make sense.

> Why did you split my sentence in half? You agree with me in the reply to the example given with this sentence.

Because there were two halves to the sentence.

>> The case of dealing with contexts is hardly unique to me.
> Contexts is the specific use case, not you.

Contexts are the general use case, yes. I'm not sure what you're point is there.

> Even if you were to use a global or this new proposed "with" feature, that function call is atrocious.

Welcome to the wonderful world of compute API, and believe me, this is nice. That single call in OpenCL is 4 + O(arg_set2) calls, CUDA its about 4 and they are all horrible and involve no end of casts to void* and is as type unsafe as its is possible be. The fact that it is a single call and type safe speaks wonders for D's meta programming.

January 19, 2019
On Saturday, 19 January 2019 at 01:35:41 UTC, Nicholas Wilson wrote:
> On Saturday, 19 January 2019 at 00:51:28 UTC, luckoverthere
> wrote:
>> On Saturday, 19 January 2019 at 00:23:40 UTC, Nicholas Wilson
>> wrote:
>>> How do you know? I don't think it would be all that much more
>>> complex than default arguments.
>>
>> Default arguments don't change. In every context you look the
>> function will behave the same way no matter where it is used.
>> It'd be no different than adding an overload. With the with
>> statement though, it'd not obvious where it might be used.
>
> Yes they can: https://run.dlang.io/is/IEQb0O
> This would be like that, except: a) without the global, and b)
> you specifying that you want to use `a` where a implicit int
> parameter is expected.

That's pretty awful too, let's not propagate that any further with with. But not really what I mean, at the very least with that default value you know that function access a global for some reason, and should probably be avoided.

>> You can't grep or find because the with statement removes it
>> all entirely.
>
> Uh, yes you can: "grep with", it will show up in the function
> signature _and_ in the scope of the call site. Its like being
> able to grep for "cast" (which is literally the entire reason
> for having cast as a keyword).

Lol I can only imagine this, does anyone actually even grep. I wonder just how many hits doing grep __traits does with something like phobos. This is by no means scalable at all. When reading code no one wants to have to grep around the entire code base because someone was lazy.

>> That's sort of my point, you'd have to look at every function
>> definition to see which ones get modified. At the call point
>> you have no indication that the behavior is different.
>
> Again this is not different to default parameters, also you
> have a `with (foo)` in scope.

Yes you have with in scope, but that's it. You'd have to look through every function in that with scope to see which functions are affected by it. In the event something is wrong.

>> It's not the same as default arguments. You can tell at call
>> point the number of parameters being passed to the function,
>> and the behavior is the same everywhere that function is used.
>> The two are absolutely different.
>
> What? Firstly with default parameters you _can't_ tell how many
> parameters are actually passed to the function at the call
> site. Secondly, this is _exactly_ the same as default
> parameters. But also like default parameters, you typically
> don't care because they are default for a reason i.e. the
> defaults make sense.

It is NOT _exactly_ the same, irregardless of where you use a function with default values they are going to behavior the same no matter where they.

void test( int a, int b = 10 );


test( 10 );     // same behavior *everywhere*
test( 10, 10 ); // same behavior *everywhere*

with( codeSmell ) {
    test( 10 );     // same behavior *everywhere*
    test( 10, 10 ); // same behavior *everywhere*
}

static this() {
    test( 10 );     // same behavior *everywhere*
    test( 10, 10 ); // same behavior *everywhere*
}


Where as with your proposed DIP.


void test( int a = with );

test(); // nope can't do t his

int value;
with( value ) {
    test(); // ok different behavior given context, unexpected
}

This is honestly why I don't use with() basically at all. And neither does anyone else really. It just makes logic harder to reason about.


>> Why did you split my sentence in half? You agree with me in
>> the reply to the example given with this sentence.
>
> Because there were two halves to the sentence.

And you misunderstood both halves because you didn't treat them as a whole :).

>>> The case of dealing with contexts is hardly unique to me.
>> Contexts is the specific use case, not you.
>
> Contexts are the general use case, yes. I'm not sure what
> you're point is there.

They are a specific use case yes.

>> Even if you were to use a global or this new proposed "with"
>> feature, that function call is atrocious.
>
> Welcome to the wonderful world of compute API, and believe me,
> this is nice. That single call in OpenCL is 4 + O(arg_set2)
> calls, CUDA its about 4 and they are all horrible and involve
> no end of casts to void* and is as type unsafe as its is
> possible be. The fact that it is a single call and type safe
> speaks wonders for D's meta programming.

Yikes, I wouldn't be celebrating making that a single call. Especially since you are effectively passing 3 different sets of arguments in one line of code. That's not something to be celebrating.

Either way good luck getting this DIP passed, you'll need it.

January 20, 2019
On Saturday, 19 January 2019 at 22:55:49 UTC, luckoverthere wrote:
> That's pretty awful too, let's not propagate that any further with with. But not really what I mean, at the very least with that default value you know that function access a global for some reason, and should probably be avoided.

Globals are bad, yes, conceptually every function that takes a global does that except you can't ever specify something different in place of the global. This is trying to get rid of them.

> Lol I can only imagine this, does anyone actually even grep.

Thats not the point. If it works for grep, it will work for ^f, it will work for an intelligent editor etc.

> Yes you have with in scope, but that's it. You'd have to look through every function in that with scope to see which functions are affected by it. In the event something is wrong.

And the situation is _far worse_ with a global. Thats why they are considered to be so bad. At least in this case there is one specific type you are interested, also `-vcg-ast` will tell you exactly what the code does. So will debug info.

> It is NOT _exactly_ the same,

That was w.r.t. the mechanism (which it is), not the effect on readability, which, while not perfect by any means, is far better than using globals, which is the only other way to do it.

> This is honestly why I don't use with() basically at all. And neither does anyone else really. It just makes logic harder to reason about.

Again the baseline for comparison is globals, which are worse.

> Yikes, I wouldn't be celebrating making that a single call. Especially since you are effectively passing 3 different sets of arguments in one line of code. That's not something to be celebrating.

For reference, CUDA does this as:

kernel<templateargs><<<shape,args, queue>>>(parameters, of, kernel);

and is IMO the sole reason it is soooo much more popular than OpenCL (and therefore a significant part of the reason Nvidia is valued so much higher). I modelled the DCompute call off that. Both are completely type safe, but CUDA does the magic behind the scenes in the compiler whereas I do it in the library. Now not all kernels are templated, so most of the time that will be just two.

The reason to not go yikes at it is because that is a single logical operation (launch me this function with these configuration parameters on this queue, and these function parameters). The fact that it is a while load of calls is irrelevant to the user: what they want is to launch a kernel.


1 2
Next ›   Last »