www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - My two cents

reply Satoshi <satoshi rikarin.org> writes:
Hi,
I had been using D for almost 6 years and I want to share my 
opinion with you.
I don't want to blame anyone but I'll focus more on bad things 
and possible improvements.
And this is just how I see D from my perspective.
(Sorry for my English, I'm too lazy to take the lessons).


First, D started as a great new language with the best from all 
languages. But now D seems more and more conservative. New 
syntactic sugars aren't added just because they can be found in 
phobos. (this was Walter's answer when I asked for maybe monad 
syntactic sugar).

OK, what I'm missing in D and what I think is wrong?

syntactic sugar for:
tuples
maybe monad (why we cannot have same syntax as in C#?)
conditional dereferencing and stuff about that (same as in C#)
foo?.bar;
foo?[bar];
return foo ?? null;

async/await (vibe.d is nice but useless in comparison to C# or js 
async/await idiom)
I want to create function returning Promise/Task and await where 
I want to.
e.g.
auto result = device.start(foo, bar); // This is RPC to remote 
server returning Task!Bar
// do some important stuff
return await result; // wait for RPC finish, then return it's 
result

I want to do this and not any ugly workaround about that.


 trusted,  safe,  system - why we have 3 keywords instead of one? 
And why it's so complicated to use?

First, we should have one 'unsafe' keyword.
Second, everything should be safe by default.
3rd, if we want to declare  system func, use 'void foo() unsafe;'
if we want to declare  trusted func, use
void foo() {
unsafe {

}
}

This fulfills the D's idiom in better way, because we should be 
defining unsafe sections as small as possible.


C# properties instead of existing ones.
function and property should be two different things.
Calling function without () or assigning to it by = is a ugly 
behavior and should be avoided.

implement this thing from C# (just because it's cool)
new Foo() {
   property1 = 42,
   property2 = "bar"
};


Reference counting when we cannot use GC...


Commercial usage, shared libraries and stuff
There isn't any handy tool to download, manage and publish closed 
source stuff.
dub is great for simple solutions but useless in big projects 
with multiple targets, configurations, etc.
Everything is primary focused on opensource development (but 
everyone here wants to see D as a next successor of C++ in 
commercial sphere).


Still cannot easily develop closed source dlls on Windows. On 
Linux every symbol is public by default, but on Windows not so 
it's needed to export them manually.


Unable to publish closed source library without workaround and 
ugly PIMPL design.

Add dll/so usage without header files
(export enums, templates and stuff right into dll/so and let D 
compiler to import these stuff from it)



For me, it seems like Walter is solving edge case problems like 
return ref parameters and return functions but is unable to add 
some basic stuff.


Thanks for your time.
- Satoshi
Oct 18
next sibling parent reply Andrea Fontana <nospam example.com> writes:
I think you missed many things for example:

On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result
https://dlang.org/phobos/std_parallelism.html#.task
Oct 18
parent Satoshi <satoshi rikarin.org> writes:
On Wednesday, 18 October 2017 at 09:03:27 UTC, Andrea Fontana 
wrote:
 I think you missed many things for example:

 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result
https://dlang.org/phobos/std_parallelism.html#.task
Sorry, I mean Task from C# which is returned from async func, not the D's Task.
Oct 18
prev sibling next sibling parent Satoshi <satoshi rikarin.org> writes:
+syntactic sugar for dynamic types

some better explaining tutorials and examples about shared. After 
6 years I'm still unable to use it properly.
Oct 18
prev sibling next sibling parent reply Ali <fakeemailadress example.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 For me, it seems like Walter is solving edge case problems like 
 return ref parameters and return functions but is unable to add 
 some basic stuff.


 Thanks for your time.
 - Satoshi
well, i've been following this forum for a while now and i remember seeing posts by either Walter or Andrei Alexandrescu, saying something in the sense that D, has become too big, and is not being used to its full potential i.e. the usage of the existing features is not being exploited to their maximum potential and they were sort of hoping, the user community will start to develop "idioms" around what exist already instead of adding more features i am not sure how much of what you use can be fulfilled with "idioms" and i think Walter's or Andrei's intention seems fair but then again, i agree with you, it is hard to push for idioms as the expense of conveniance features when you dont have the user mass yet unfortunately D probably need to keep adding features, until it find its mass
Oct 18
next sibling parent aberba <karabutaworld gmail.com> writes:
On Wednesday, 18 October 2017 at 16:45:33 UTC, Ali wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
well, i've been following this forum for a while now and i remember seeing posts by either Walter or Andrei Alexandrescu, saying something in the sense that D, has become too big, and is not being used to its full potential i.e. the usage of the existing features is not being exploited to their maximum potential [...]
The language itself has too many that we can't even use 50%.
Oct 18
prev sibling parent reply Fra Mecca <me francescomecca.eu> writes:
On Wednesday, 18 October 2017 at 16:45:33 UTC, Ali wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 For me, it seems like Walter is solving edge case problems 
 like return ref parameters and return functions but is unable 
 to add some basic stuff.


 Thanks for your time.
 - Satoshi
well, i've been following this forum for a while now and i remember seeing posts by either Walter or Andrei Alexandrescu, saying something in the sense that D, has become too big, and is not being used to its full potential i.e. the usage of the existing features is not being exploited to their maximum potential and they were sort of hoping, the user community will start to develop "idioms" around what exist already instead of adding more features i am not sure how much of what you use can be fulfilled with "idioms" and i think Walter's or Andrei's intention seems fair but then again, i agree with you, it is hard to push for idioms as the expense of conveniance features when you dont have the user mass yet unfortunately D probably need to keep adding features, until it find its mass
I agree with what is being said. For example async is totally doable with the current level of control that D gives you. The problem in my opinion is the ecosystem. We miss a build system that is tailored towards enterprises and there is so much work to do with libraries (even discovery of them) and documentation by examples.
Oct 18
next sibling parent Adam Wilson <flyboynw gmail.com> writes:
On 10/18/17 23:50, Fra Mecca wrote:
[snip]
 The problem in my opinion is the ecosystem.
 We miss a build system that is tailored towards enterprises and there is
 so much work to do with libraries (even discovery of them) and
 documentation by examples.
Indeed ... :) -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 19
prev sibling parent reply Martin Nowak <code dawg.eu> writes:
On Thursday, 19 October 2017 at 06:50:12 UTC, Fra Mecca wrote:
 We miss a build system that is tailored towards enterprises
Anything more specific on that?
Oct 20
parent reply drug <drug2004 bk.ru> writes:
20.10.2017 17:46, Martin Nowak пишет:
 On Thursday, 19 October 2017 at 06:50:12 UTC, Fra Mecca wrote:
 We miss a build system that is tailored towards enterprises
Anything more specific on that?
My 2 cent: 1. dub needs ability to work with other repository than standard ones. 2. multicore building - entire project in D builds faster than C++ one (I have two implementation of the same), but in case of incremental building C++ faster. 3. dub single build mode does not caches builds so it builds entire project every time.
Oct 22
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 On Thursday, 19 October 2017 at 06:50:12 UTC, Fra Mecca wrote:
 We miss a build system that is tailored towards enterprises
Anything more specific on that?
My 2 cent: 1. dub needs ability to work with other repository than standard ones.
You can use "preGenerateCommands", "postGenerateCommands", "preBuildCommands" or "postBuildCommands", then simply have some shell script to invoke that performs what you need with other eco systems.
Oct 23
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 23/10/2017 10:58 AM, bauss wrote:
 On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 On Thursday, 19 October 2017 at 06:50:12 UTC, Fra Mecca wrote:
 We miss a build system that is tailored towards enterprises
Anything more specific on that?
My 2 cent: 1. dub needs ability to work with other repository than standard ones.
You can use "preGenerateCommands", "postGenerateCommands", "preBuildCommands" or "postBuildCommands", then simply have some shell script to invoke that performs what you need with other eco systems.
"other repositories" here probably means other than github, bitbucket and gitlab. Which isn't actually part of dub in the first place!
Oct 23
prev sibling parent reply drug <drug2004 bk.ru> writes:
23.10.2017 12:58, bauss пишет:
 On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 On Thursday, 19 October 2017 at 06:50:12 UTC, Fra Mecca wrote:
 We miss a build system that is tailored towards enterprises
Anything more specific on that?
My 2 cent: 1. dub needs ability to work with other repository than standard ones.
You can use "preGenerateCommands", "postGenerateCommands", "preBuildCommands" or "postBuildCommands", then simply have some shell script to invoke that performs what you need with other eco systems.
Of course I can, I just tried to describe what meant `a build system that is tailored towards enterprises` for me. Also such build system should provide a way to build C/C++ (and others) codebase or let other build systems build D codebase, using generated makefile for example.
Oct 23
parent Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 10:42:35 UTC, drug wrote:
 Also such build system should provide a way to build C/C++ (and 
 others) codebase or let other build systems build D codebase, 
 using generated makefile for example.
In fact dub can generate cmake files, more generators for e.g. ninja or meson could be added.
Oct 23
prev sibling parent reply Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 My 2 cent:
 1. dub needs ability to work with other repository than 
 standard ones.
You mount or clone whatever you want and use `dub add-local`.
 2. multicore building - entire project in D builds faster than 
 C++ one (I have two implementation of the same), but in case of 
 incremental building C++ faster.
I always assumed this to be the main point why people are asking for a better build tool, but it's not sth. dub can do atm. It's a limitation of the compiler that requires various changes and a slight redesign of our build model. In C++ incremental rebuilds are simple as you compile each file individually anyhow, but that's the crux for why C++ compilations are so slow in the first place. Compiling multiple modules at once provides lots of speedups as you do not have to reparse and analyze common/mutual imports, but on the downside it cannot be parallelized that well. Dub could parallelize building individual packages/sub-packages (target + dependencies) right now though.
 3. dub single build mode does not caches builds so it builds 
 entire project every time.
Could you please file an issue with a test case for that. Why do you use single build mode in the first place?
Oct 23
next sibling parent Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 11:02:41 UTC, Martin Nowak wrote:
 In C++ incremental rebuilds are simple as you compile each file 
 individually anyhow, but that's the crux for why C++ 
 compilations are so slow in the first place.
 Compiling multiple modules at once provides lots of speedups as 
 you do not have to reparse and analyze common/mutual imports, 
 but on the downside it cannot be parallelized that well.
dub supports --buildMode=singleFile --parallel to mimic that, but it's very wasteful. For example gtk-d took way over a minute with single file compilation, but only a few seconds when being compiled at once
Oct 23
prev sibling next sibling parent drug <drug2004 bk.ru> writes:
23.10.2017 14:02, Martin Nowak пишет:
 On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 My 2 cent:
 1. dub needs ability to work with other repository than standard ones.
You mount or clone whatever you want and use `dub add-local`.
This is workaround. Now I have bash script that does all I need, but it would be better if I should only specify my inhouse repos.
 
 2. multicore building - entire project in D builds faster than C++ one 
 (I have two implementation of the same), but in case of incremental 
 building C++ faster.
I always assumed this to be the main point why people are asking for a better build tool, but it's not sth. dub can do atm. It's a limitation of the compiler that requires various changes and a slight redesign of our build model. In C++ incremental rebuilds are simple as you compile each file individually anyhow, but that's the crux for why C++ compilations are so slow in the first place. Compiling multiple modules at once provides lots of speedups as you do not have to reparse and analyze common/mutual imports, but on the downside it cannot be parallelized that well.
I just build my project and it's silly to look at `top` output where seven cores idles while build takes tens of seconds. While building C++ project loads cores fully. I have no clear and robust opinion on this, considering you wrote above, but nevertheless.
 
 Dub could parallelize building individual packages/sub-packages (target 
 + dependencies) right now though.
I should try it.
 
 3. dub single build mode does not caches builds so it builds entire 
 project every time.
Could you please file an issue with a test case for that. Why do you use single build mode in the first place?
I have several utilities each of them is about 50 lines (including comment to enable single build mode) and I think this is case for single mode exactly. They are wrappers of rather fat library and building them takes about a minute what is too long for D. I do not state that it prevents D from enterprises etc, not at all. I'm sure that restructuring my project can improve building time too, for example. Just directions where we can do more to improve tooling.
Oct 23
prev sibling next sibling parent Atila Neves <atila.neves gmail.com> writes:
On Monday, 23 October 2017 at 11:02:41 UTC, Martin Nowak wrote:
 On Monday, 23 October 2017 at 06:05:50 UTC, drug wrote:
 20.10.2017 17:46, Martin Nowak пишет:
 My 2 cent:
 1. dub needs ability to work with other repository than 
 standard ones.
You mount or clone whatever you want and use `dub add-local`.
 2. multicore building - entire project in D builds faster than 
 C++ one (I have two implementation of the same), but in case 
 of incremental building C++ faster.
I always assumed this to be the main point why people are asking for a better build tool, but it's not sth. dub can do atm. It's a limitation of the compiler that requires various changes and a slight redesign of our build model.
Does it? Reggae can do parallel per-package builds (in fact, the default) right now.
 In C++ incremental rebuilds are simple as you compile each file 
 individually anyhow, but that's the crux for why C++ 
 compilations are so slow in the first place.
Not really. C++ is slow to compile anyway because parsing it is slow. C has the same compilation model and is much much faster to compile than C++. There's also the fact that the same headers are parsed over and over again. `#include <iostream>` requires parsing thousands of lines of code from dozens of files. However, if all you touched was a C++ implementation file, then incremental builds are faster than D. Really.
 Compiling multiple modules at once provides lots of speedups as 
 you do not have to reparse and analyze common/mutual imports, 
 but on the downside it cannot be parallelized that well.
I measured, and indeed compiling per package is faster than compiling all of the modules that have to be recompiled individually, even if done in parallel. Weirdly enough this is a disadvantage (time-wise) of having implementation and declarations in the same file.
 Dub could parallelize building individual packages/sub-packages 
 (target + dependencies) right now though.
reggae already does, just point it at a dub package directory. By default it'll even build the default target and a unittest one in parallel.
 3. dub single build mode does not caches builds so it builds 
 entire project every time.
Could you please file an issue with a test case for that. Why do you use single build mode in the first place?
I'd assume it'd be to only rebuild the necessary files C++-style. However, and as stated by you above, that's usually slower anyway. Atila
Oct 23
prev sibling parent reply Igor <stojkovic.igor gmail.com> writes:
On Monday, 23 October 2017 at 11:02:41 UTC, Martin Nowak wrote:
 In C++ incremental rebuilds are simple as you compile each file 
 individually anyhow, but that's the crux for why C++ 
 compilations are so slow in the first place.
 Compiling multiple modules at once provides lots of speedups as 
 you do not have to reparse and analyze common/mutual imports, 
 but on the downside it cannot be parallelized that well.
I wish I knew how Delphi was compiling things because it is by far the fastest compiler I have ever tried. It compiled individual files as well but not into obj files but some dcu files and it used them if source wasn't changed when compiling sources that depended on that module.
Oct 23
parent drug <drug2004 bk.ru> writes:
23.10.2017 23:25, Igor пишет:
 On Monday, 23 October 2017 at 11:02:41 UTC, Martin Nowak wrote:
 In C++ incremental rebuilds are simple as you compile each file 
 individually anyhow, but that's the crux for why C++ compilations are 
 so slow in the first place.
 Compiling multiple modules at once provides lots of speedups as you do 
 not have to reparse and analyze common/mutual imports, but on the 
 downside it cannot be parallelized that well.
I wish I knew how Delphi was compiling things because it is by far the fastest compiler I have ever tried. It compiled individual files as well but not into obj files but some dcu files and it used them if source wasn't changed when compiling sources that depended on that module.
Yeah, in time of Delphi 6 I thought that Delphi wasn't as serious as C++ (don't remember compiler version exactly) because Delphi compiles so fast comparing to C++. C++ was cool that time in my eyes because I can see it was doing something cool and of course very serious)) Delphi was really as fast as lightning and it was not interesting.
Oct 23
prev sibling next sibling parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 conditional dereferencing and stuff about that (same as in C#)
 foo?.bar;
 foo?[bar];
 return foo ?? null;
Tbh. these are some I really wish were in D, because it becomes tedious having to write something like this all the time: return foo ? foo : null; where return foo ?? null; would be so much easier. It especially becomes painful when you have something with multiple member accesses. Like: return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something : null; Which could just be: return foo?.bar?.baz?.something;
 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 I want to create function returning Promise/Task and await 
 where I want to.
 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result
I don't think this is much necessary, because the fiber implementations already are able to let you write code close to this. The only difference is you have to import the modules, but it's such a small thing I don't think you really need this.
 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };



 Thanks for your time.
 - Satoshi
I really wish this was implemented for classes too! Currently it exist for structs and it completely baffles me why it has never been implemented for structs.
Oct 19
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ? foo : null;

 where

 return foo ?? null; would be so much easier.
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something : 
 null;

 Which could just be:

 return foo?.bar?.baz?.something;
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
Oct 19
next sibling parent bauss <jj_1337 live.dk> writes:
On Friday, 20 October 2017 at 02:20:31 UTC, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:

 In dom.d, since I use this kind of thing somewhat frequently, I 
 wrote a function called `optionSelector` which returns a 
 wrapper type that is never null on the outside, but propagates 
 null through the members. So you can do

 foo.optionSelector("x").whatever.you.want.all.the.way.down

 and it handles null automatically.
That's pretty interesting.
Oct 19
prev sibling next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, October 20, 2017 02:20:31 Adam D. Ruppe via Digitalmars-d wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ? foo : null;

 where

 return foo ?? null; would be so much easier.
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something :
 null;

 Which could just be:

 return foo?.bar?.baz?.something;
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
For better or worse, solutions like this are the main reason that a number of things folks ask for don't get added to the language. It's frequently the case that what someone wants to do can already be done using the language as-is; it just may not be as syntactically pleasing as what the person wants, and they may not know D well enough yet to have come up with the solution on their own. - Jonathan M Davis
Oct 19
parent reply Satoshi <satoshi rikarin.org> writes:
On Friday, 20 October 2017 at 04:26:24 UTC, Jonathan M Davis 
wrote:
 On Friday, October 20, 2017 02:20:31 Adam D. Ruppe via 
 Digitalmars-d wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ? foo : null;

 where

 return foo ?? null; would be so much easier.
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something : 
 null;

 Which could just be:

 return foo?.bar?.baz?.something;
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
For better or worse, solutions like this are the main reason that a number of things folks ask for don't get added to the language. It's frequently the case that what someone wants to do can already be done using the language as-is; it just may not be as syntactically pleasing as what the person wants, and they may not know D well enough yet to have come up with the solution on their own. - Jonathan M Davis
Yeah, but if it can be done by stuff like you said it's not reason to not implement syntactic sugar for it. array[0 .. 42] can be substituted by array.slice(0, 42) too, but it's not. it's more handy to write void foo(int? a, string? b); than void foo(Maybe!int a, Maybe!string b); same for return a ?? null; than return getOr(a, null); foo.optionSelector("x").whatever.you.want.all.the.way.down it's not clear if you are able or not to able to hit the null. foo?.x?.whatever?.you?.want; is more clear and doesn't need any boilerplate. it doesn't need to be implemented in code.
Oct 20
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, October 20, 2017 08:09:59 Satoshi via Digitalmars-d wrote:
 On Friday, 20 October 2017 at 04:26:24 UTC, Jonathan M Davis

 wrote:
 On Friday, October 20, 2017 02:20:31 Adam D. Ruppe via

 Digitalmars-d wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ? foo : null;

 where

 return foo ?? null; would be so much easier.
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something :
 null;

 Which could just be:

 return foo?.bar?.baz?.something;
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
For better or worse, solutions like this are the main reason that a number of things folks ask for don't get added to the language. It's frequently the case that what someone wants to do can already be done using the language as-is; it just may not be as syntactically pleasing as what the person wants, and they may not know D well enough yet to have come up with the solution on their own. - Jonathan M Davis
Yeah, but if it can be done by stuff like you said it's not reason to not implement syntactic sugar for it. array[0 .. 42] can be substituted by array.slice(0, 42) too, but it's not. it's more handy to write void foo(int? a, string? b); than void foo(Maybe!int a, Maybe!string b); same for return a ?? null; than return getOr(a, null); foo.optionSelector("x").whatever.you.want.all.the.way.down it's not clear if you are able or not to able to hit the null. foo?.x?.whatever?.you?.want; is more clear and doesn't need any boilerplate. it doesn't need to be implemented in code.
Yes, there is syntactic sugar in the language, and yes, there could be more, but it reached the point a while ago where Walter and Andrei seem to have decided that additional syntactic sugar isn't worth it. For something to be added the language, it generally has to add actual capabilities or solve a problem that is just unreasonable or impossible to solve with a library solution. And honestly, where to draw the line on syntactic sugar is highly subjective. Something that one person might think makes the code nicely concise might seem annoyingly crpytic to someone else. And obviously, not everything can have syntactic sugar. Not everything can be built into the language. A line has to be drawn somewhere. It's just a question of where it makes the most sense to draw it, and that's not at all obvious. There's bound to be disagreement on the matter. D is an extremely powerful language, and for now at least, the conclusion seems to be that its power is being underutilized and that it simply isn't worth adding things to the language if they can be easily done with a library solution. Obviously, there are things that some folks would like to be in the language that aren't, but there's always going to be something that someone wants to be in the language but isn't, and the guys in charge seem to have decided that D is now featureful enough and powerful enough that it's not getting new features unless it actually needs them. Simply making some syntax look prettier isn't enough. A feature has to actually add capabilities that we're missing. There may be exceptions to that, but that's generally where things sit. And honestly, they were going to have to take this stance at some point. We can't keep adding syntactic sugar forever. They just happen to have stopped adding syntactic sugar before they added some syntactic sugar that you'd like D to have. If you can make a really good argument in a DIP as to why D really needs a feature that you want, then it may yet get added (even if it's only syntactic sugar), but it's going to have to be a really compelling argument that is likely going to need to show why the feature is objectively better and thus worth having rather than simply saving you a bit of typing or making the code look prettier. It's probably going to have to clearly reduce bugs or provide capabilities that can't reasonably be done with a library. D is long past the point where the language was in flux and we were constantly adding new features. Features do still get added, but they really have to pull their own weight rather than being a nice-to-have. - Jonathan M Davis
Oct 20
next sibling parent reply Satoshi <satoshi rikarin.org> writes:
On Friday, 20 October 2017 at 08:32:36 UTC, Jonathan M Davis 
wrote:
 On Friday, October 20, 2017 08:09:59 Satoshi via Digitalmars-d 
 wrote:
 On Friday, 20 October 2017 at 04:26:24 UTC, Jonathan M Davis

 wrote:
 On Friday, October 20, 2017 02:20:31 Adam D. Ruppe via

 Digitalmars-d wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 [...]
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 [...]
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
For better or worse, solutions like this are the main reason that a number of things folks ask for don't get added to the language. It's frequently the case that what someone wants to do can already be done using the language as-is; it just may not be as syntactically pleasing as what the person wants, and they may not know D well enough yet to have come up with the solution on their own. - Jonathan M Davis
Yeah, but if it can be done by stuff like you said it's not reason to not implement syntactic sugar for it. array[0 .. 42] can be substituted by array.slice(0, 42) too, but it's not. it's more handy to write void foo(int? a, string? b); than void foo(Maybe!int a, Maybe!string b); same for return a ?? null; than return getOr(a, null); foo.optionSelector("x").whatever.you.want.all.the.way.down it's not clear if you are able or not to able to hit the null. foo?.x?.whatever?.you?.want; is more clear and doesn't need any boilerplate. it doesn't need to be implemented in code.
Yes, there is syntactic sugar in the language, and yes, there could be more, but it reached the point a while ago where Walter and Andrei seem to have decided that additional syntactic sugar isn't worth it. For something to be added the language, it generally has to add actual capabilities or solve a problem that is just unreasonable or impossible to solve with a library solution. And honestly, where to draw the line on syntactic sugar is highly subjective. Something that one person might think makes the code nicely concise might seem annoyingly crpytic to someone else. And obviously, not everything can have syntactic sugar. Not everything can be built into the language. A line has to be drawn somewhere. It's just a question of where it makes the most sense to draw it, and that's not at all obvious. There's bound to be disagreement on the matter. D is an extremely powerful language, and for now at least, the conclusion seems to be that its power is being underutilized and that it simply isn't worth adding things to the language if they can be easily done with a library solution. Obviously, there are things that some folks would like to be in the language that aren't, but there's always going to be something that someone wants to be in the language but isn't, and the guys in charge seem to have decided that D is now featureful enough and powerful enough that it's not getting new features unless it actually needs them. Simply making some syntax look prettier isn't enough. A feature has to actually add capabilities that we're missing. There may be exceptions to that, but that's generally where things sit. And honestly, they were going to have to take this stance at some point. We can't keep adding syntactic sugar forever. They just happen to have stopped adding syntactic sugar before they added some syntactic sugar that you'd like D to have. If you can make a really good argument in a DIP as to why D really needs a feature that you want, then it may yet get added (even if it's only syntactic sugar), but it's going to have to be a really compelling argument that is likely going to need to show why the feature is objectively better and thus worth having rather than simply saving you a bit of typing or making the code look prettier. It's probably going to have to clearly reduce bugs or provide capabilities that can't reasonably be done with a library. D is long past the point where the language was in flux and we were constantly adding new features. Features do still get added, but they really have to pull their own weight rather than being a nice-to-have. - Jonathan M Davis
OK, you are right, except one thing. I think, saving a bit of typing and making the code look prettier is acceptable reason to add syntactic sugar. Actually, it's definition of syntactic sugar. I accept that the authors of D have their own line on s. sugar, but ideal opensource project should fulfills the requirements of the majority not represent subjective opinion of one. Personally, I had 3 options: 1. Use D and be angry every time when I must write getOne(foo, null) instead of foo ?? null and similar stuff. 2. Use different language, like C# 3. Fork D and implement the stuff by myself Actually, I chose C# just because I need to get project done ASAP and don't have time to implement the missing things by myself. Personally, I prefer user friendliness over fast performance because performance can be upgraded by upgrading hardware, but development speed cannot. If you need reason why is writing less code better just calculate the time of it. getOne(foo, null) // costs 3 sec. foo ?? null // cost 1 sec. if you need to write it for 10 times per day and you have company with 100 developers it costs 2000 sec (33 min) per day. It's 132 hours per year. And still, you are writing ugly code.
Oct 20
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 20 October 2017 at 09:40:26 UTC, Satoshi wrote:
 If you need reason why is writing less code better just 
 calculate the time of it.
 getOne(foo, null)  // costs 3 sec.
 foo ?? null // cost 1 sec.
Note that I do NOT object to these additions. I think they'd be trivial, backward compatible, and familiar to C# and even some Javascript coders. We could probably patch the compiler in under an hour to support them since they are such simple constructs and if you did that, I'd vote yes to merge them. But at the same time, be realistic. The time difference is actually insignificant, and the function is even more flexible (it can do things like type conversions too) and I'd choose a function over the sugar in many cases. We shouldn't be arguing about this, we should either be implementing it or just using the easily-written function.
Oct 20
prev sibling parent reply Adam Wilson <flyboynw gmail.com> writes:
On 10/20/17 01:32, Jonathan M Davis wrote:
 On Friday, October 20, 2017 08:09:59 Satoshi via Digitalmars-d wrote:
 On Friday, 20 October 2017 at 04:26:24 UTC, Jonathan M Davis

 wrote:
 On Friday, October 20, 2017 02:20:31 Adam D. Ruppe via

 Digitalmars-d wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ? foo : null;

 where

 return foo ?? null; would be so much easier.
return getOr(foo, null); That's really easy to do generically with a function. I wouldn't object to the ?? syntax, but if it really is something you write all over the place, you could just write the function.
 return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something :
 null;

 Which could just be:

 return foo?.bar?.baz?.something;
In dom.d, since I use this kind of thing somewhat frequently, I wrote a function called `optionSelector` which returns a wrapper type that is never null on the outside, but propagates null through the members. So you can do foo.optionSelector("x").whatever.you.want.all.the.way.down and it handles null automatically. You can do that semi-generically too with a function if it is something you use really frequently.
For better or worse, solutions like this are the main reason that a number of things folks ask for don't get added to the language. It's frequently the case that what someone wants to do can already be done using the language as-is; it just may not be as syntactically pleasing as what the person wants, and they may not know D well enough yet to have come up with the solution on their own. - Jonathan M Davis
Yeah, but if it can be done by stuff like you said it's not reason to not implement syntactic sugar for it. array[0 .. 42] can be substituted by array.slice(0, 42) too, but it's not. it's more handy to write void foo(int? a, string? b); than void foo(Maybe!int a, Maybe!string b); same for return a ?? null; than return getOr(a, null); foo.optionSelector("x").whatever.you.want.all.the.way.down it's not clear if you are able or not to able to hit the null. foo?.x?.whatever?.you?.want; is more clear and doesn't need any boilerplate. it doesn't need to be implemented in code.
Yes, there is syntactic sugar in the language, and yes, there could be more, but it reached the point a while ago where Walter and Andrei seem to have decided that additional syntactic sugar isn't worth it. For something to be added the language, it generally has to add actual capabilities or solve a problem that is just unreasonable or impossible to solve with a library solution. And honestly, where to draw the line on syntactic sugar is highly subjective. Something that one person might think makes the code nicely concise might seem annoyingly crpytic to someone else. And obviously, not everything can have syntactic sugar. Not everything can be built into the language. A line has to be drawn somewhere. It's just a question of where it makes the most sense to draw it, and that's not at all obvious. There's bound to be disagreement on the matter. D is an extremely powerful language, and for now at least, the conclusion seems to be that its power is being underutilized and that it simply isn't worth adding things to the language if they can be easily done with a library solution. Obviously, there are things that some folks would like to be in the language that aren't, but there's always going to be something that someone wants to be in the language but isn't, and the guys in charge seem to have decided that D is now featureful enough and powerful enough that it's not getting new features unless it actually needs them. Simply making some syntax look prettier isn't enough. A feature has to actually add capabilities that we're missing. There may be exceptions to that, but that's generally where things sit. And honestly, they were going to have to take this stance at some point. We can't keep adding syntactic sugar forever. They just happen to have stopped adding syntactic sugar before they added some syntactic sugar that you'd like D to have. If you can make a really good argument in a DIP as to why D really needs a feature that you want, then it may yet get added (even if it's only syntactic sugar), but it's going to have to be a really compelling argument that is likely going to need to show why the feature is objectively better and thus worth having rather than simply saving you a bit of typing or making the code look prettier. It's probably going to have to clearly reduce bugs or provide capabilities that can't reasonably be done with a library. D is long past the point where the language was in flux and we were constantly adding new features. Features do still get added, but they really have to pull their own weight rather than being a nice-to-have. - Jonathan M Davis
Here is the thing that bothers me about that stance. You are correct, but I don't think you've considered the logical conclusion of the direction your argument is headed. Pray tell, why must we stop adding syntactic sugar? Why does their need to be an (by your own admission) arbitrary limit? If we look at any moderately successful language (C++/C#/Java/Python/etc.) you will find that all of them have accumulated syntax sugar over the years at a fairly constant rate. For example, C# has added point releases to it's release schedule for which the express purpose is adding syntax sugar. I think the purpose of syntax sugar has been fundamentally misunderstood by grammando's the world over. The purpose of syntax sugar is to give the most commonly used idioms an expressive short-hand. Some examples of syntax sugar in the D language are: lambdas, virtual functions, ternary, I could go on. Some examples of syntax sugar is C# are obvious and have been previously been mentioned here, for example the ?? operator. Others are less obvious, for example, async/await is syntax sugar for a collection of Task-based idioms in C#. The logical conclusion (reductio ad absurdum) of your argument is coding in binary. Everything else is just syntax sugar. Grammando's suffer from a particularly pernicious cognitive bias called "Functional fixedness" or the inability to use a device in any way other than it is traditionally used. Grammando's believe that a grammar has always been a certain way, and that nothing need be added, removed, or modified. This bias is often enforced by The Curse of Knowledge (I know, so everyone else must know as well). The reality is that grammars, like any other social construct, change, often very rapidly. For example, in English, "ain't" used to be considered a "high class" word. Within the space of a few short years, as the low-born began to use it, the high-born rejected it and deemed it "low-class" and thus you have the situation we have today with that word. Contractions are the Syntax Sugar of the English language. You use them everyday without even thinking about it. And the ones you use today are quite different than the ones you used 10 or 20 years ago. And even the regional use can vary widely at any given point in time. Syntax sugar is no different in D than it is in English. For example: a ?? b is a contraction of: a !is null ? a : b which itself is a contraction of: if (a !is null) { return a; } else { return b; } Indeed, the CPU only ever sees the last one. Syntax sugar simply takes the common idioms that the culture around D has collected and then distills them into expressive forms. As with spoken language, to declare an "end" to syntax sugar is to declare an end to the culture that surrounds it. If the language cannot adapt to the culture changing around it, the language will die, and the culture will move on. -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 20
next sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, October 20, 2017 02:49:34 Adam Wilson via Digitalmars-d wrote:
 Here is the thing that bothers me about that stance. You are correct,
 but I don't think you've considered the logical conclusion of the
 direction your argument is headed. Pray tell, why must we stop adding
 syntactic sugar? Why does their need to be an (by your own admission)
 arbitrary limit?

 If we look at any moderately successful language
 (C++/C#/Java/Python/etc.) you will find that all of them have
 accumulated syntax sugar over the years at a fairly constant rate. For
 example, C# has added point releases to it's release schedule for which
 the express purpose is adding syntax sugar.
It simply doesn't make sense to add every stray feature that folks ask for. Maybe some additional syntactic sugar will be added to D in the future, but there are way too many feature requests for it to make sense to implement even a small fraction of them. Some things are worth adding, but many really aren't. We have to say no frequently, or we'll be drowned in stray features to implement. And only so much can be added to a language before it becomes completely unwieldy. For instance, how many people are actually experts on C++ and understand all of its ins and outs? _Very_ few people. It's simply too complicated a language. Other languages aren't necessarily as bad off in that regard, but if you add enough to any language, it will get there. Every time you add something to the language, you stand the chance of improving some aspect of the language, but it comes at the cost of additional complexity. Sometimes the addition is worth that complexity, and sometimes it isn't. Knowing when to add something and when not to is often a tough question, but it's still true that you can't add everything. And inevitably, some of the things you leave out will annoy some people by their absence, just as some of the things you add will annoy some folks by being there. For better or worse, Walter and Andrei's current stance is essentially that if something can be reasonably done already in the language as it is, they're not adding a feature to do it. D is already insanely powerful as it is, and too often folks are looking to add a feature to the language when it's trivial to do it with a library solution. That certainly doesn't mean that nothing new is going to be added, but we have far more important features to worry about than saving someone from having to type a few extra characters because they want to use a couple of ?'s instead of typing out the code themselves or using a function call to encapsulate the behavior - e.g. finishing sorting out stuff like scope, safety, and shared are far more critical. If someone has a really strong argument for why something is worth adding, then they're free to create a DIP for it, and if they can convince Walter and Andrei, it can make it into the language. But at this point in D's development, syntactic sugar really isn't high on the list of things that they consider to be of value. That doesn't mean that they're always right, but on the whole, I agree with them. - Jonathan M Davis
Oct 20
parent reply Adam Wilson <flyboynw gmail.com> writes:
On 10/20/17 04:04, Jonathan M Davis wrote:
 On Friday, October 20, 2017 02:49:34 Adam Wilson via Digitalmars-d wrote:
 Here is the thing that bothers me about that stance. You are correct,
 but I don't think you've considered the logical conclusion of the
 direction your argument is headed. Pray tell, why must we stop adding
 syntactic sugar? Why does their need to be an (by your own admission)
 arbitrary limit?

 If we look at any moderately successful language
 (C++/C#/Java/Python/etc.) you will find that all of them have
 accumulated syntax sugar over the years at a fairly constant rate. For
 example, C# has added point releases to it's release schedule for which
 the express purpose is adding syntax sugar.
It simply doesn't make sense to add every stray feature that folks ask for. Maybe some additional syntactic sugar will be added to D in the future, but there are way too many feature requests for it to make sense to implement even a small fraction of them. Some things are worth adding, but many really aren't. We have to say no frequently, or we'll be drowned in stray features to implement. And only so much can be added to a language before it becomes completely unwieldy. For instance, how many people are actually experts on C++ and understand all of its ins and outs? _Very_ few people. It's simply too complicated a language. Other languages aren't necessarily as bad off in that regard, but if you add enough to any language, it will get there. Every time you add something to the language, you stand the chance of improving some aspect of the language, but it comes at the cost of additional complexity. Sometimes the addition is worth that complexity, and sometimes it isn't. Knowing when to add something and when not to is often a tough question, but it's still true that you can't add everything. And inevitably, some of the things you leave out will annoy some people by their absence, just as some of the things you add will annoy some folks by being there. For better or worse, Walter and Andrei's current stance is essentially that if something can be reasonably done already in the language as it is, they're not adding a feature to do it. D is already insanely powerful as it is, and too often folks are looking to add a feature to the language when it's trivial to do it with a library solution. That certainly doesn't mean that nothing new is going to be added, but we have far more important features to worry about than saving someone from having to type a few extra characters because they want to use a couple of ?'s instead of typing out the code themselves or using a function call to encapsulate the behavior - e.g. finishing sorting out stuff like scope, safety, and shared are far more critical. If someone has a really strong argument for why something is worth adding, then they're free to create a DIP for it, and if they can convince Walter and Andrei, it can make it into the language. But at this point in D's development, syntactic sugar really isn't high on the list of things that they consider to be of value. That doesn't mean that they're always right, but on the whole, I agree with them. - Jonathan M Davis
I never said "every stray feature" should be added. What I said is that "common idioms" should be added. Preferably without having to perform herculean feats of persuasion. And let's be honest, as a community we have a pretty good handle on what the common idioms are, seeing as how books have been written on the subject. For example, ?? and ?. are ridiculously common idioms that we all perform every day in our D code. And as Mr. Ruppe rightly pointed out, it'd probably take about an hour each to knock together a complete PR for these features. But we have spent years arguing over because somebody at the top said "no more syntax sugar". Grammandos *adore* these types of proclamations because they give grammandos a line in the sand that they can defend at all costs. For example, in the US, we are taught that "ain't" is not an English word and should never be used. However, it has a long and storied history as an English word and has a specific use. But grammandos took their grammar teachers word as iron-clad law and have enforced it mercilessly, resulting in the death of a legitimate word. All because some British royalty didn't like it when the peasants started using the word 200 years ago. So far I have seen three arguments proffered for the ban syntax sugar. The first is "Walter/Andrei doesn't have the time." This is prima facie ridiculous as it presumes that Walter/Andrei must be the one to implement it. If this is the case then D dies in the same moment that Walter/Andrei does. Since that is obviously not the case, this argument can be safely invalidated by simply observing the environment in which D is created. Every time I talk to Walter in-person about these sorts of proclamations he routinely says something along the lines of "It means that I won't be doing the work, but if someone wants to shepherd it through the PR process I'd gladly accept it." This position is quite rational, Walter's job is to focus on the big problems of D, not adding syntax sugar. I know this because I've specifically asked Walter about ?? and ?. in the past and his response was "So go do it. I'll accept it." However, I think we've mistaken "I won't do it" for "It shall not be done." I say this because when these features do occasionally show up as PR's they are roundly criticized by the community grammandos for violating the Most Holy Laws of D. The PR author gives up, closes the PR, and Walter never has the chance to accept it. Indeed, I don't contribute to D because I have little interest in doing the required verbal judo with the community grammandos. If I absolutely had too, I would open a PR and email Walter directly so that he could intervene directly before the grammandos can react. What I would NOT do is talk about it on the forums until AFTER Walter had approved it. But I have the advantage of being able to leverage a personal relationship. Our newcomers do not. The second argument is "the language is already powerful enough to let you do that." This argument is specious. Yes, the language is powerful enough to do those things without syntax sugar. But syntax sugar isn't about power, it's about efficiency. So I certainly can write a function that does what ?. does but as we've already seen in this thread, there are multiple ways to name it. So far I've seen orElse and getOr. This creates a dialectic friction, whereby when moving to a new codebase I have to learn these new shibboleths. Those methods may function identically or they may have frustratingly subtle differences in implementation, and I have absolutely no way to know from reading the calling code. By adding syntax sugar we standardize these idiomatic shibboleths. This improves the overall code read/write efficiency by standardizing both the language construct and the implementation of the idiom. Of course you are still free to write the non-idiomatic methods you need. And indeed, by standardizing the common idiom, it becomes trivial to differentiate the standard idioms from the non-standard idioms. This is a two-stage win for the language. The third argument is: "syntax sugar makes the language more complicated." Again, specious. The correct answer is that the bad design and implementation of any language feature makes the language more complicated. A well done syntax sugar design and implementation significantly reduces code complexity for reasons stated in the second point. D suffers from poorly designed and implemented features, which, in order to use successfully, require a significant amount of "deep knowledge" or knowledge that goes beyond what is shown in the code. That deep knowledge turns what should be a straight forward feature, nogc for example, into book of unwritten knowledge about which language+library features allocate behind the scenes. Much of the design of these syntax sugars has already been done for us. We know how async/await is supposed to function. We know how ?? and ?. function. We also know that most of these sugars vastly reduce complexity (and errors resulting from said complexity) because they've been proven to do just than in other languages for many years (decades in some cases). Async/Await is the perfect example of sugar that eliminated entire classes of threading related errors due to reduced implementation complexity. Of course, you CAN implement Async methods in C# without Async/Await. C# is also powerful language with all the primitive tools required to do so. Indeed the compiler rewrites the await to IL that uses those tools. But why on earth would you? The code can be over 100 lines long per await and you will get something wrong. Syntax sugar is a key component of any Safe language. -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 20
next sibling parent bauss <jj_1337 live.dk> writes:
On Friday, 20 October 2017 at 22:25:20 UTC, Adam Wilson wrote:
 On 10/20/17 04:04, Jonathan M Davis wrote:
 On Friday, October 20, 2017 02:49:34 Adam Wilson via 
 Digitalmars-d wrote:
Preach
Oct 20
prev sibling next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Friday, October 20, 2017 15:25:20 Adam Wilson via Digitalmars-d wrote:
 So far I have seen three arguments proffered for the ban syntax sugar.

 The first is "Walter/Andrei doesn't have the time."
That actually has pretty much nothing to do with a feature request like syntactic sugar - especially if it's trivial to implement. Andrei in particular seems to feel strongly at this point that if something can be reasonably done with how the language is right now, then we don't need to add a feature for it. And if that's the case, then syntactic sugar stands pretty much no chance of getting in regardless of how easy it is to add. He even had some _removed_ after the work had already been done and merged - specifically using [$] in a static array declaration to infer the type, which we can't even fully do with a library right now thanks to https://issues.dlang.org/show_bug.cgi?id=16779.
 The second argument is "the language is already powerful enough to let
 you do that." This argument is specious. Yes, the language is powerful
 enough to do those things without syntax sugar. But syntax sugar isn't
 about power, it's about efficiency. So I certainly can write a function
 that does what ?. does but as we've already seen in this thread, there
 are multiple ways to name it. So far I've seen orElse and getOr. This
 creates a dialectic friction, whereby when moving to a new codebase I
 have to learn these new shibboleths. Those methods may function
 identically or they may have frustratingly subtle differences in
 implementation, and I have absolutely no way to know from reading the
 calling code.

 By adding syntax sugar we standardize these idiomatic shibboleths. This
 improves the overall code read/write efficiency by standardizing both
 the language construct and the implementation of the idiom. Of course
 you are still free to write the non-idiomatic methods you need. And
 indeed, by standardizing the common idiom, it becomes trivial to
 differentiate the standard idioms from the non-standard idioms. This is
 a two-stage win for the language.
Well, I think that you'd need to prove that the syntactic sugar objectively improved a lot of existing D code to stand much chance of convincing Andrei. My guess is that you have a better chance with Walter, but I don't know. Regardless, I think that it would need to be shown that the proposed syntax would be a significant improvement to a lot of the existing code out there. Andrei in particular seems to be becoming more insistent on that point and less likely to agree that something is worth adding to the language when it can be done with a library solution. Personally, I see little value in any of the suggested syntactic sugar involving ?; either we already have a library solution that works just fine (e.g. Nullable), or it's something that I do so rarely in my D code that, I'd likely never use it. There probably are a few places in Phobos where they could be used, but idiomatic D code simply doesn't do much with null. Structs are heavily used, whereas classes are rarely used, and dynamic arrays (strings included) are designed so that null and empty are mostly synonymous. And while pointers do get used some, the focus is generally on static allocations where possible, which significantly reduces the number of heap allocations in comparison to typical C# or Java code. Particularly, when doing a lot with ranges, null doesn't tend to enter into things much. I rarely find that I need to check for null. But anyone wanting such additions would need to convince Walter and Andrei, not me. - Jonathan M Davis
Oct 20
prev sibling parent Martin Nowak <code dawg.eu> writes:
On Friday, 20 October 2017 at 22:25:20 UTC, Adam Wilson wrote:
 For example, ?? and ?. are ridiculously common idioms that we 
 all perform every day in our D code. And as Mr. Ruppe rightly 
 pointed out, it'd probably take about an hour each to knock 
 together a complete PR for these features.
Well, ignoring communication doesn't make it unnecessary. It just means that the communication has to happen after throwing a drive-by PR at us. Would be great if we could adequately capture arguments to facilitate those discussions. Seems like there wasn't even an ER for that https://issues.dlang.org/show_bug.cgi?id=17924.
Oct 21
prev sibling parent reply Kagamin <spam here.lot> writes:
On Friday, 20 October 2017 at 09:49:34 UTC, Adam Wilson wrote:
 Others are less obvious, for example, async/await is syntax 
 sugar for a collection of Task-based idioms in C#.
Now I think it's doesn't fit D. async/await wasn't made for performance, but for conservation of thread resources, async calls are rather expensive, which doesn't fit in D if we prefer raw performance. Also I found another shortcoming: it doesn't interoperate well with cache: cache flip flops between synchronous and asynchronous operation: when you hit cache it's synchronous, when you miss it it performs IO.
Oct 23
next sibling parent reply Adam Wilson <flyboynw gmail.com> writes:
On 10/23/17 08:21, Kagamin wrote:
 On Friday, 20 October 2017 at 09:49:34 UTC, Adam Wilson wrote:
 Others are less obvious, for example, async/await is syntax sugar for
 a collection of Task-based idioms in C#.
Now I think it's doesn't fit D. async/await wasn't made for performance, but for conservation of thread resources, async calls are rather expensive, which doesn't fit in D if we prefer raw performance. Also I found another shortcoming: it doesn't interoperate well with cache: cache flip flops between synchronous and asynchronous operation: when you hit cache it's synchronous, when you miss it it performs IO.
Actually I think it fits perfectly with D, not for reason of performance, but for reason of flexibility. D is a polyglot language, with by far the most number of methodologies supported in a single language that I've ever encountered. Additionally, MSFT/C# fully recognizes that the benefits of Async/Await have never been and never were intended to be for performance. Async/Await trades raw performance for an ability to handle a truly massive number of simultaneous tasks. And it is easy to implement both blocking and non-blocking calls side-by-side (MSFT appends 'Async' to the blocking call name). Here is the thing. Many projects (particularly web-scale) are not all that sensitive to latency. Adding 10ms to the total call duration isn't going to effect the user experience much when you've got 500ms of IO calls to make. But blocking calls will lock up a thread for those 500ms. That can disastrous when you have thousands of calls coming in every second to each machine. On the flip side, if you're a financial service corp with millions to throw at hardware and an extreme latency sensitivity, you'll go for the blocking calls, because they absolutely do cost less in overall milliseconds. And you'll make up for the thread blockages by throwing an obscene amount of hardware at the problem. Because hey, you're a multi-billion dollar corp, you'll make back the few million you spent on over-provisioning hardware in a day or two. The point is that not everyone wants, or needs, maximum raw performance per individual task. In the spirit of flexibility, D needs to provide the other choice, because it's not our job to tell our users how to run their business. -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 23
next sibling parent reply Nathan S. <no.public.email example.com> writes:
On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
Additionally, MSFT/C# fully recognizes that the benefits of 
Async/Await have never been and never were intended to be for 
performance. Async/Await trades raw performance for an ability 
to handle a truly massive number of simultaneous tasks.
Could you clarify this? Do you mean it's not supposed to have better performance for small numbers of tasks, but there is supposed to be some high threshold of tasks/second at which either throughput or latency is better?
Oct 23
parent Adam Wilson <flyboynw gmail.com> writes:
On 10/23/17 16:47, Nathan S. wrote:
 On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 Additionally, MSFT/C# fully recognizes that the benefits of
 Async/Await have never been and never were intended to be for
 performance. Async/Await trades raw performance for an ability to
 handle a truly massive number of simultaneous tasks.
Could you clarify this? Do you mean it's not supposed to have better performance for small numbers of tasks, but there is supposed to be some high threshold of tasks/second at which either throughput or latency is better?
It's pretty complicated. In general, for a small number of tasks, it will take longer to execute those task with Async than without (Async has an overhead, about 10ms IIRC). So each individual call to an awaitable function will take longer than a call to a blocking function. In fact, MSFT recommends that if you are reasonably certain that most of the time it will take less than about 10ms to just use the blocking methods, as they have less total overhead. The main benefit of Async is in throughput. It allows the physical CPU to handle many incoming requests. So while each individual request may take longer, the overall utilization of the CPU is much higher. Async, has different benefits and drawbacks depending on where it's applied. For example, in UI apps, it allows the main program thread to keep responding to system events while waiting for long-wait IO (the thread is not suspended). Some background that may help understanding is that in blocking IO, what is really happening underneath your blocking call is that the runtime is creating a callback and then calling the OS's thread suspend method (e.g. ThreadSuspend in Windows), then when the callback is called, the thread is resumed and the data passed to into it via the callback. This means that the calling thread cannot execute anything while it's waiting. This is why UX apps appear to freeze when using blocking IO calls. The reason this is done is because the application has no way to say "I'm going to put this task off to the side and keep executing". The thread does not know to start some other processing while waiting. Async allows the app to put that task to the aside and do something else. At a low level the process in .NET it does this by: 1. Serializing the stack frame of the currently executing method to the heap (yes, Async is a GC feature, just like lambdas) at an await. 2. Pulling the next completed task from the heap. 3. Rebuilding the stack frame for that method on any available thread. 4. Continue execution of that stack. Obviously this makes a lot of sense for UI apps, where blocking the main thread can be disastrous, but why internet applications are inherently multi-threaded, so why do we care? The answer is thread context switching. A context switch is the most expensive common CPU operation by an order of magnitude, ranging from 2k-1m cycles. Whereas on modern CPUs a main RAM read is 100-150 cycles and a NUMA different socket read is 300-500 cycles. In .NET the TaskScheduler creates a predetermined number of threads (one per core IIRC) and begins scheduling tasks on those threads. Remembering that each task is really just a block on the heap, in the worst case that will take 500 cycles. Whereas if we had to switch to a different thread, it could be up to 1m cycles. That is a noticeable difference. Context switches are painfully expensive but in the traditional model it was all we had. Task based systems allow us to circumvent the task switch. But they're cumbersome to use without compiler support. For example, the Task Parallel Library was added in .NET 4.0 which includes Task and Task<T> and ALL of the constructs that are used in Async/Await, however, it was not until .NET 4.5 and the arrival of the Async/Await keywords (and the compiler lowerings that they enabled) that people started using Tasks in any significant way. (Source for access times: http://ithare.com/wp-content/uploads/part101_infographics_v08.png) -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 23
prev sibling next sibling parent reply flamencofantasy <flamencofantasy gmail.com> writes:
On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 On 10/23/17 08:21, Kagamin wrote:
 [...]
Actually I think it fits perfectly with D, not for reason of performance, but for reason of flexibility. D is a polyglot language, with by far the most number of methodologies supported in a single language that I've ever encountered. [...]
There is a lot of misunderstanding about async/await. It has nothing to do with "conservation of thread resources" or trading "raw performance for an ability
 to handle a truly massive number of simultaneous tasks". 
 Async/await is just 'syntactic sugar' where the compiler 
 re-writes your code into a state machine around APM 
 (Asynchronous programming model which was introduced in .NET 
 2.0 sometime around 2002 I believe). That's all there is to it, 
 it makes your asynchronous code look and feel synchronous.
Oct 23
parent reply Adam Wilson <flyboynw gmail.com> writes:
On 10/23/17 17:27, flamencofantasy wrote:
 On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 On 10/23/17 08:21, Kagamin wrote:
 [...]
Actually I think it fits perfectly with D, not for reason of performance, but for reason of flexibility. D is a polyglot language, with by far the most number of methodologies supported in a single language that I've ever encountered. [...]
There is a lot of misunderstanding about async/await. It has nothing to do with "conservation of thread resources" or trading "raw performance for an ability
 to handle a truly massive number of simultaneous tasks". Async/await
 is just 'syntactic sugar' where the compiler re-writes your code into
 a state machine around APM (Asynchronous programming model which was
 introduced in .NET 2.0 sometime around 2002 I believe). That's all
 there is to it, it makes your asynchronous code look and feel
 synchronous.
The only parts of Async/Await that have anything to do with APM are the interop stubs. C#'s Async/Await is built around the Task Asynchronous Programming model (e.g. Task and Task<T>) the compiler lowers to those, not APM. A common misunderstanding is that Task/Task<T> is based on APM, it's not, Task uses fundamentally different code underneath. On Linux/macOS it actually uses libuv (at the end of the day all of these programming models are callback based). Yes, C#'s async design does make code look and feel synchronous, and it was intentionally designed that way, but that is not *why* they did Async. That misunderstanding arises from an interview that Anders did in which he was asked why they held Async back for three years after announcing it at PDC08. In that same talk Anders specifically says that the purpose of the Async is to free up threads to continue execution, his example is a Windows Desktop Message Pump and fetching pictures from the internet (long-wait IO), but the principal applies to any thread. They held back async for three years because they needed to refine the language syntax to something that people could learn and apply in a reasonable amount of time. IIRC there is a Channel9 video where Anders explains the evolution of Async Await. Source: I was at Build 2011 and sat in on the Anders Hejlsberg (C# language designer) and Stephen Toub (Async/Await implementer) talks where they discussed Async in detail. I also work for MSFT, I can email them directly if you want further clarification on anything. :) -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 23
next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
 On 10/23/17 17:27, flamencofantasy wrote:
 On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 On 10/23/17 08:21, Kagamin wrote:
 [...]
Actually I think it fits perfectly with D, not for reason of performance, but for reason of flexibility. D is a polyglot language, with by far the most number of methodologies supported in a single language that I've ever encountered. [...]
There is a lot of misunderstanding about async/await. It has nothing to do with "conservation of thread resources" or trading "raw performance for an ability
 to handle a truly massive number of simultaneous tasks". 
 Async/await
 is just 'syntactic sugar' where the compiler re-writes your 
 code into
 a state machine around APM (Asynchronous programming model 
 which was
 introduced in .NET 2.0 sometime around 2002 I believe). 
 That's all
 there is to it, it makes your asynchronous code look and feel
 synchronous.
The only parts of Async/Await that have anything to do with APM are the interop stubs. C#'s Async/Await is built around the Task Asynchronous Programming model (e.g. Task and Task<T>) the compiler lowers to those, not APM. A common misunderstanding is that Task/Task<T> is based on APM, it's not, Task uses fundamentally different code underneath. On Linux/macOS it actually uses libuv (at the end of the day all of these programming models are callback based).
I’ll throw in my 2 rubbles. I actually worked on a VM that has async/await feature built-in (Dart language). It is a plain syntax sugar for Future/Promise explicit asynchrony where async automatically return Future[T] or Observable[T] (the latter is async stream). Async function with awaits is then re-written as a single call-back with a basic state machine, each state corresponds to the line where you did await. Example: async double calculateTax(){ double taxRate = await getTaxRates(); double income = await getIncome(); return taxRate * income; } Becomes roughly this (a bit more mechanical though): Future!double calculateTax(){ int state = 0; Promise!double __ret; double taxRate; double income; void cb() { if(state == 0) { state = 1; getTaxRates().andThen((double ret){ taxRate = ret; cb(); }); } else if (state == 1) { state = 2; getIncome().andThen((double ret){ income = ret; cb(); }); else if (state == 2){ __ret.resolve(taxRate*income); } } cb(); } It doesn’t matter what mechanics you use to complete promises - be it IO scheduler a-la libuv or something else. Async/await is agnostic to that. Still there is a fair amount of machinery to hide the rewrite from the user and in particular print stack trace as if it was normal sequential code.
 Yes, C#'s async design does make code look and feel 
 synchronous, and it was intentionally designed that way, but 
 that is not *why* they did Async. That misunderstanding arises 
 from an interview that Anders did in which he was asked why 
 they held Async back for three years after announcing it at 
 PDC08. In that same talk Anders specifically says that the 
 purpose of the Async is to free up threads to continue 
 execution, his example is a Windows Desktop Message Pump and 
 fetching pictures from the internet (long-wait IO), but the 
 principal applies to any thread. They held back async for three 
 years because they needed to refine the language syntax to 
 something that people could learn and apply in a reasonable 
 amount of time. IIRC there is a Channel9 video where Anders 
 explains the evolution of Async Await.
In other words - explicit asynchrony where a thread immediately returns with Future[T] and moves on to the next task. It’s just hidden by Async/Await.
Oct 23
next sibling parent Adam Wilson <flyboynw gmail.com> writes:
On 10/23/17 22:40, Dmitry Olshansky wrote:
 On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
 On 10/23/17 17:27, flamencofantasy wrote:
 On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 On 10/23/17 08:21, Kagamin wrote:
 [...]
Actually I think it fits perfectly with D, not for reason of performance, but for reason of flexibility. D is a polyglot language, with by far the most number of methodologies supported in a single language that I've ever encountered. [...]
There is a lot of misunderstanding about async/await. It has nothing to do with "conservation of thread resources" or trading "raw performance for an ability
 to handle a truly massive number of simultaneous tasks". Async/await
 is just 'syntactic sugar' where the compiler re-writes your code into
 a state machine around APM (Asynchronous programming model which was
 introduced in .NET 2.0 sometime around 2002 I believe). That's all
 there is to it, it makes your asynchronous code look and feel
 synchronous.
The only parts of Async/Await that have anything to do with APM are the interop stubs. C#'s Async/Await is built around the Task Asynchronous Programming model (e.g. Task and Task<T>) the compiler lowers to those, not APM. A common misunderstanding is that Task/Task<T> is based on APM, it's not, Task uses fundamentally different code underneath. On Linux/macOS it actually uses libuv (at the end of the day all of these programming models are callback based).
I’ll throw in my 2 rubbles. I actually worked on a VM that has async/await feature built-in (Dart language). It is a plain syntax sugar for Future/Promise explicit asynchrony where async automatically return Future[T] or Observable[T] (the latter is async stream). Async function with awaits is then re-written as a single call-back with a basic state machine, each state corresponds to the line where you did await. Example: async double calculateTax(){ double taxRate = await getTaxRates(); double income = await getIncome(); return taxRate * income; } Becomes roughly this (a bit more mechanical though): Future!double calculateTax(){ int state = 0; Promise!double __ret; double taxRate; double income; void cb() { if(state == 0) { state = 1; getTaxRates().andThen((double ret){ taxRate = ret; cb(); }); } else if (state == 1) { state = 2; getIncome().andThen((double ret){ income = ret; cb(); }); else if (state == 2){ __ret.resolve(taxRate*income); } } cb(); } It doesn’t matter what mechanics you use to complete promises - be it IO scheduler a-la libuv or something else. Async/await is agnostic to that.
That was actually my point. Windows and Linux/macOS .NET core do different things. It doesn't matter to the dev. You did a better job of illuminating it. :)
 Still there is a fair amount of machinery to hide the rewrite from the
 user and in particular print stack trace as if it was normal sequential
 code.
And that is the difficulty we face in D. :)
 Yes, C#'s async design does make code look and feel synchronous, and
 it was intentionally designed that way, but that is not *why* they did
 Async. That misunderstanding arises from an interview that Anders did
 in which he was asked why they held Async back for three years after
 announcing it at PDC08. In that same talk Anders specifically says
 that the purpose of the Async is to free up threads to continue
 execution, his example is a Windows Desktop Message Pump and fetching
 pictures from the internet (long-wait IO), but the principal applies
 to any thread. They held back async for three years because they
 needed to refine the language syntax to something that people could
 learn and apply in a reasonable amount of time. IIRC there is a
 Channel9 video where Anders explains the evolution of Async Await.
In other words - explicit asynchrony where a thread immediately returns with Future[T] and moves on to the next task. It’s just hidden by Async/Await.
Yup. -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 23
prev sibling parent reply flamencofantasy <flamencofantasy gmail.com> writes:
On Tuesday, 24 October 2017 at 05:40:06 UTC, Dmitry Olshansky 
wrote:
 On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
[...]
I’ll throw in my 2 rubbles. I actually worked on a VM that has async/await feature built-in (Dart language). It is a plain syntax sugar for Future/Promise explicit asynchrony where async automatically return Future[T] or Observable[T] (the latter is async stream). [...]
This is exactly what async/await in C# does. I saw this idea in Jeffry Richter's Power Threading library (https://github.com/Wintellect/PowerThreading) sometime in the mid/late 2000, where he used the C# 'yield' keyword to generate the state machine code. When async/await was added MSFT either took his idea directly or at the very least got inspired by it.
Oct 24
parent Paulo Pinto <pjmlp progtools.org> writes:
On Tuesday, 24 October 2017 at 16:02:56 UTC, flamencofantasy 
wrote:
 On Tuesday, 24 October 2017 at 05:40:06 UTC, Dmitry Olshansky 
 wrote:
 On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
[...]
I’ll throw in my 2 rubbles. I actually worked on a VM that has async/await feature built-in (Dart language). It is a plain syntax sugar for Future/Promise explicit asynchrony where async automatically return Future[T] or Observable[T] (the latter is async stream). [...]
This is exactly what async/await in C# does. I saw this idea in Jeffry Richter's Power Threading library (https://github.com/Wintellect/PowerThreading) sometime in the mid/late 2000, where he used the C# 'yield' keyword to generate the state machine code. When async/await was added MSFT either took his idea directly or at the very least got inspired by it.
Async/await was based on Midori's project related work. http://joeduffyblog.com/2015/11/19/asynchronous-everything/ -- Paulo
Oct 24
prev sibling parent Kagamin <spam here.lot> writes:
On Tuesday, 24 October 2017 at 04:26:42 UTC, Adam Wilson wrote:
 (at the end of the day all of these programming models are 
 callback based).
That's what APM is, no?
 Yes, C#'s async design does make code look and feel 
 synchronous, and it was intentionally designed that way, but 
 that is not *why* they did Async.
You can do APM in .net 4.0 with tasks and callbacks (we do it at work), the only purpose of async/await is to make it look nice and synchronous.
Oct 24
prev sibling parent Kagamin <spam here.lot> writes:
On Monday, 23 October 2017 at 22:22:55 UTC, Adam Wilson wrote:
 Async/Await trades raw performance for an ability to handle a 
 truly massive number of simultaneous tasks.
Vibe achieves the same without trading performance. Then async/await only amounts to easy creation of tasks not even for their main usage scenario at a pretty high price of async/await feature, such tradeoff doesn't sound good to me.
Oct 24
prev sibling parent reply Satoshi <satoshi rikarin.org> writes:
On Monday, 23 October 2017 at 15:21:02 UTC, Kagamin wrote:
 On Friday, 20 October 2017 at 09:49:34 UTC, Adam Wilson wrote:
 Others are less obvious, for example, async/await is syntax 
 sugar for a collection of Task-based idioms in C#.
Now I think it's doesn't fit D. async/await wasn't made for performance, but for conservation of thread resources, async calls are rather expensive, which doesn't fit in D if we prefer raw performance. Also I found another shortcoming: it doesn't interoperate well with cache: cache flip flops between synchronous and asynchronous operation: when you hit cache it's synchronous, when you miss it it performs IO.
Actually, async/await should be faster and safer than running same blocking code in another thread and then syncing between them. If we want to use D for GUI development we will need this feature anyway. It's the easiest solution how to run blocking functions in GUI callback without freezing, it reduces bugs and callback hell. Look at Javascript and Node.js (I think).
Oct 24
parent reply Kagamin <spam here.lot> writes:
On Tuesday, 24 October 2017 at 07:29:08 UTC, Satoshi wrote:
 If we want to use D for GUI development we will need this 
 feature anyway.
To not block UI you need non-blocking IO, and async/await is not required for it: vibe provides non-blocking IO with synchronous interface. And here we also have another shortcoming of async/await: it doesn't interact well with GUI that traditionally uses synchronous event handlers (mostly because it predates async/await).
Oct 24
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 24/10/2017 10:31 AM, Kagamin wrote:
 On Tuesday, 24 October 2017 at 07:29:08 UTC, Satoshi wrote:
 If we want to use D for GUI development we will need this feature anyway.
To not block UI you need non-blocking IO, and async/await is not required for it: vibe provides non-blocking IO with synchronous interface. And here we also have another shortcoming of async/await: it doesn't interact well with GUI that traditionally uses synchronous event handlers (mostly because it predates async/await).
Just a random idea, something to think about: ``` struct Task { void delegate() del; void* stack; Status status = Status.finished; void continue() { del(); } } () { size_t lastJump; if (lastJump == J1) { lastJump=J2; jmp J2; } else lastJump = J1; J1: ubyte[] gotRead = doRead(__task, "..."); yield; J2: gotRead /= 2; doWrite(__task, "...", gotRead); complete; // yield if wasn't done } ``` From: ``` ubyte[] doRead(string name) async { ... } void doWrite(string name, ubyte[] data) async { ... } void callback(...) { ubyte[] gotRead = doRead("..."); gotRead /= 2; doWrite("...", gotRead); } ``` scope+ref+out as arguments would be a no-no. Now if we could ditch registers usage crossing before/after yield, we wouldn't need to do 'patching' like fibers do.
Oct 24
parent Martin Nowak <code dawg.eu> writes:
On Tuesday, 24 October 2017 at 09:56:50 UTC, rikki cattermole 
wrote:
 scope+ref+out as arguments would be a no-no.
 Now if we could ditch registers usage crossing before/after 
 yield, we wouldn't need to do 'patching' like fibers do.
That's basically what asnyc/await does, some implementations as continuation (callback) some as jump rewrite.
Oct 24
prev sibling parent Martin Nowak <code dawg.eu> writes:
On Friday, 20 October 2017 at 08:09:59 UTC, Satoshi wrote:
 return foo ?? null; would be so much easier.
Definitely the Elvis operator is a small and sometimes useful addition. https://en.wikipedia.org/wiki/Elvis_operator Your best bet on getting it, is writing a small DIP, the organize consensus for the exact semantics to get it approved. https://github.com/dlang/DIPs/ It's seems far from being a high priority though. Actually quite a pity that of the many valid points you mentioned, the majority of the discussion focuses on this triviality. But as usual, when it's cheap to have an opinion, everyone affords one. Hence if you want to change sth. get your DIP approved. I'd even volunteer for the compiler implementation of `?:`.
Oct 20
prev sibling parent reply Random D user <no email.com> writes:
On Friday, 20 October 2017 at 02:20:31 UTC, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ?? null; would be so much easier.
return getOr(foo, null);
I guess with UFCS you could get: return foo.PP(null); // vs. return foo ?? null; :D
Oct 20
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Oct 20, 2017 at 06:20:52PM +0000, Random D user via Digitalmars-d wrote:
 On Friday, 20 October 2017 at 02:20:31 UTC, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 return foo ?? null; would be so much easier.
return getOr(foo, null);
I guess with UFCS you could get: return foo.PP(null); // vs. return foo ?? null; :D
You could have this today via a nicely-named UFCS function: T orElse(T t, lazy T defaultVal) { return t is null ? defaultVal : t; } class C {} C defaultC; C makeC() { ... } auto c = makeC().orElse(defaultC); You can even UFCS-chain it: auto c = makeC().orElse(makeCAnotherWay()) .orElse(makeCYetAnotherWay()) .orElse(defaultC); T -- Stop staring at me like that! It's offens... no, you'll hurt your eyes!
Oct 20
prev sibling next sibling parent Meta <jared771 gmail.com> writes:
On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 conditional dereferencing and stuff about that (same as in C#)
 foo?.bar;
 foo?[bar];
 return foo ?? null;
Tbh. these are some I really wish were in D, because it becomes tedious having to write something like this all the time: return foo ? foo : null; where return foo ?? null; would be so much easier. It especially becomes painful when you have something with multiple member accesses. Like: return foo ? foo.bar ? foo.bar.baz ? foo.bar.baz.something : null; Which could just be: return foo?.bar?.baz?.something;
 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 I want to create function returning Promise/Task and await 
 where I want to.
 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result
I don't think this is much necessary, because the fiber implementations already are able to let you write code close to this. The only difference is you have to import the modules, but it's such a small thing I don't think you really need this.
 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };



 Thanks for your time.
 - Satoshi
I really wish this was implemented for classes too! Currently it exist for structs and it completely baffles me why it has never been implemented for structs.
http://forum.dlang.org/post/mailman.2562.1403196857.2907.digitalmars-d puremagic.com From that thread: Here's a slightly improved version that collapses nested wrappers into a single wrapper, so that Maybe!(Maybe!(Maybe!...Maybe!T)...) == Maybe!T: /** * A safe-dereferencing wrapper resembling a Maybe monad. * * If the wrapped object is null, any further member dereferences will simply * return a wrapper around the .init value of the member's type. Since non-null * member dereferences will also return a wrapped value, any null value in the * middle of a chain of nested dereferences will simply cause the final result * to default to the .init value of the final member's type. */ template SafeDeref(T) { static if (is(T U == SafeDeref!V, V)) { // Merge SafeDeref!(SafeDeref!X) into just SafeDeref!X. alias SafeDeref = U; } else { struct SafeDeref { T t; // Make the wrapper as transparent as possible. alias t this; // This is the magic that makes it all work. auto opDispatch(string field)() if (is(typeof(__traits(getMember, t, field)))) { alias Memb = typeof(__traits(getMember, t, field)); // If T is comparable with null, then we do a null check. // Otherwise, we just dereference the member since it's // guaranteed to be safe of null dereferences. // // N.B.: we always return a wrapped type in case the return // type contains further nullable fields. static if (is(typeof(t is null))) { return safeDeref((t is null) ? Memb.init : __traits(getMember, t, field)); } else { return safeDeref(__traits(getMember, t, field)); } } } } } /** * Wraps an object in a safe dereferencing wrapper resembling a Maybe monad. * * If the object is null, then any further member dereferences will just return * a wrapper around the .init value of the wrapped type, instead of * dereferencing null. This applies recursively to any element in a chain of * dereferences. * * Params: t = data to wrap. * Returns: A wrapper around the given type, with "safe" member dereference * semantics. */ auto safeDeref(T)(T t) { return SafeDeref!T(t); } unittest { class Node { int val; Node left, right; this(int _val, Node _left=null, Node _right=null) { val = _val; left = _left; right = _right; } } auto tree = new Node(1, new Node(2), new Node(3, null, new Node(4) ) ); import std.stdio; writeln(safeDeref(tree).right.right.val); writeln(safeDeref(tree).left.right.left.right); writeln(safeDeref(tree).left.right.left.right.val); } // Static test of monadic composition of SafeDeref. unittest { { struct Test {} alias A = SafeDeref!Test; alias B = SafeDeref!A; static assert(is(B == SafeDeref!Test)); static assert(is(SafeDeref!B == SafeDeref!Test)); } // Timon Gehr's original test case { class C { auto foo = safeDeref(C.init); } C c = new C; //import std.stdio; //writeln(safeDeref(c).foo); // SafeDeref(SafeDeref(null)) import std.string; auto type = "%s".format(safeDeref(c).foo); assert(type == "SafeDeref!(C)(null)"); } }
Oct 20
prev sibling parent meppl <mephisto nordhoff-online.de> writes:
On Friday, 20 October 2017 at 00:26:19 UTC, bauss wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 conditional dereferencing and stuff about that (same as in C#)
 ...
...
 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };



 Thanks for your time.
 - Satoshi
I really wish this was implemented for classes too! Currently it exist for structs and it completely baffles me why it has never been implemented for structs.
maybe because of open questions. what is with private variables in a class? At the current time i can set private variables in a D-struct from a different module: // in amod.d struct S { private: immutable int a = 33; } // in bmod.d S x = { a:1}; // no error auto y = S( 1); // no error the D-documentation doesnt tell, if this is valid behaviour of the compiler, whatever, for now I just assume it is. maybe it is not a good thing to be able to do that. but at the same time the user should decide at object initialization what value _some_ private variables shall have. so, that's what the constructor usually is good for, too. let the user set only certain private variables one time at initialization. with the amod.d-code above there is no way to disallow resetting all private variables. And: If i can only set public variables, it is not a perfect solution either
Oct 25
prev sibling next sibling parent reply Martin Nowak <code dawg.eu> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 First, D started as a great new language with the best from all 
 languages. But now D seems more and more conservative. New 
 syntactic sugars aren't added just because they can be found in 
 phobos. (this was Walter's answer when I asked for maybe monad 
 syntactic sugar).

 OK, what I'm missing in D and what I think is wrong?

 syntactic sugar for:
 tuples
 maybe monad (why we cannot have same syntax as in C#?)
 conditional dereferencing and stuff about that (same as in C#)
 foo?.bar;
 foo?[bar];
 return foo ?? null;
With much stronger typing it's a bit trickier, most things in D are not classes/pointers, hence there is no universal null/nil.
 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 I want to create function returning Promise/Task and await 
 where I want to.
 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result

 I want to do this and not any ugly workaround about that.
It's not that hard to add full async/await support to the compiler. The code for capturing upvalues is already there to support foreach opApply callbacks. We still don't have nogc delegates, but that's also not too much of a hassle. While it could be implemented, priority isn't too high. At least for I/O-bound workloads, the performance gains over stack based async is rather small. Would be different for using async/await for parallel HPC (http://stellar-group.org/libraries/hpx/). If you want to run 2 async tasks concurrently with Fibers, just use e.g. http://vibed.org/api/vibe.core.core/runTask.
  trusted,  safe,  system - why we have 3 keywords instead of 
 one? And why it's so complicated to use?

 First, we should have one 'unsafe' keyword.
 Second, everything should be safe by default.
 3rd, if we want to declare  system func, use 'void foo() 
 unsafe;'
 if we want to declare  trusted func, use
 void foo() {
 unsafe {

 }
 }
Sounds easy and nice, but isn't compatible with separate compilation and headers, which in fact are key to good compile times.
 C# properties instead of existing ones.
 function and property should be two different things.
 Calling function without () or assigning to it by = is a ugly 
 behavior and should be avoided.
Different folks, different strokes. Lots of people seem to like optional parens, in particular for `arr.map!(e => e ^^ 2).each!writeln` chains. Maybe you just need to get used to them. Otherwise write a Linter that slaps you whenever you forget them.
 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };
 Reference counting when we cannot use GC...
WIP
 Commercial usage, shared libraries and stuff
 There isn't any handy tool to download, manage and publish 
 closed source stuff.
 dub is great for simple solutions but useless in big projects 
 with multiple targets, configurations, etc.
 Everything is primary focused on opensource development (but 
 everyone here wants to see D as a next successor of C++ in 
 commercial sphere).
Well, dub is a package manager to share code, so obviously OSS it the main target. You can easily `dub add-local` packages or run your private registry. And of course there are various other options like Make, CMake, Meson, or Raggae.
 Still cannot easily develop closed source dlls on Windows. On 
 Linux every symbol is public by default, but on Windows not so 
 it's needed to export them manually.
WIP (https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP45.md) Cannot is quite strong, it just requires a bit of work.
 Unable to publish closed source library without workaround and 
 ugly PIMPL design.
Why is that? For templates and inference the compiler needs to see stuff in order to compile them. This is the same contradiction as with you unsafe block suggestion above. If you know sth. really smart here, make sure to let us know :).
 Add dll/so usage without header files
 (export enums, templates and stuff right into dll/so and let D 
 compiler to import these stuff from it)

 like return ref parameters and return functions but is unable 
 to add some basic stuff.
We could do better on communicating our plans. Return ref and scope are part of a major effort to transition to manual memory management (RC et.al.) without buying into the associated memory corruptions (and security issues) that plague C/C++. ==================== As unfortunately with almost any OSS project, we're not that many people, and each of us is investing a huge amount of time into this. OTOH we're getting tons of requests, which are often hard to prioritize. Most of them are particular interests as well (you seem to have an edge for C#). Would be great if you could attach some estimated costs to each of your points, i.e. how much effort does this or that cause for you. Something I want to have for quite a while is a free-form poll for features, maybe running 2 weeks or so, to get a better understanding of community priorities. But again your best bet on getting sth. done is working on it, be it writing a DIP, organizing the discussion, or actually implementing it.
Oct 20
next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 October 2017 at 15:38:53 UTC, Martin Nowak wrote:
 Something I want to have for quite a while is a free-form poll 
 for features, maybe running 2 weeks or so, to get a better 
 understanding of community priorities.
Maybe once a quarter, ;) It might help to have some sense of how the main devs time on D is being used. Not in any kind of exact way, more hand-wavy. For instance, if w% of their time is on fixing bugs, x% on maintenance, y% on working towards safety, z% on other stuff they are already doing that I'm not included, then time spent on new features or syntax has to come from somewhere of that. What do you reduce your time on to implement them? That's where it gets tricky. Is elvis operator more important than improving safe/scope/nogc/etc, I think most would say no. This is the economic way of looking at things. Taking the number of devs and the hours they spend on D as given, how they spend that time is an allocation problem. Walter and Andrei and Martin have in their heads some ideas about what is the best approach. However, when you think of resources (dev D) as finite, then someone would need to be able to show that the new features or syntax are more important than the other things that they are already working on. That's why DIPs.
Oct 20
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Friday, 20 October 2017 at 16:36:28 UTC, jmh530 wrote:
 It might help to have some sense of how the main devs time on D 
 is being used.
Definitely, I currently have no clue what they are on.
 Is elvis operator more important than improving 
 safe/scope/nogc/etc, I think most would say no.
I would say yes. I think safe/scope/nogc/etc are useless given their bad design, and enormously difficult to get right given our current constraints. The elvis operator, while trivial and unnecessary, would be easy to implement correctly and give a nice little PR boost to show that we care about the people talking about it.
Oct 20
next sibling parent reply user1234 <user1234 12.nl> writes:
On Friday, 20 October 2017 at 18:11:50 UTC, Adam D. Ruppe wrote:
 [...] The elvis operator, while trivial and
 unnecessary, would be easy to implement correctly and give
 a nice little PR boost to show that we care about the people
 talking about it.
If you go by there, the safe navigation operator would probably even easier to implement than the elvis one.
Oct 20
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 October 2017 at 19:54:09 UTC, user1234 wrote:
 On Friday, 20 October 2017 at 18:11:50 UTC, Adam D. Ruppe wrote:
 [...] The elvis operator, while trivial and
 unnecessary, would be easy to implement correctly and give
 a nice little PR boost to show that we care about the people
 talking about it.
If you go by there, the safe navigation operator would probably even easier to implement than the elvis one.
How about somebody implements the functionality, such as with what H.S. Teoh describes, and gets it added into phobos, maybe std.typecons b/c that's where nullable is? If it's in phobos and people find themselves using it all the time, then it might make sense to push for it to get the syntax added.
Oct 20
parent user1234 <user1234 12.nl> writes:
On Friday, 20 October 2017 at 20:11:46 UTC, jmh530 wrote:
 On Friday, 20 October 2017 at 19:54:09 UTC, user1234 wrote:
 On Friday, 20 October 2017 at 18:11:50 UTC, Adam D. Ruppe 
 wrote:
 [...] The elvis operator, while trivial and
 unnecessary, would be easy to implement correctly and give
 a nice little PR boost to show that we care about the people
 talking about it.
If you go by there, the safe navigation operator would probably even easier to implement than the elvis one.
How about somebody implements the functionality, such as with what H.S. Teoh describes, and gets it added into phobos, maybe std.typecons b/c that's where nullable is?
No. Because of completion. Completion has to work after "?.", it's a postfix like the "." for aggregate members. I can already tell that i wouldn't widely use a library solution.
Oct 20
prev sibling next sibling parent reply Martin Nowak <code dawg.eu> writes:
On Friday, 20 October 2017 at 18:11:50 UTC, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 16:36:28 UTC, jmh530 wrote:
 It might help to have some sense of how the main devs time on 
 D is being used.
Definitely, I currently have no clue what they are on.
Tried that, didn't resonate that much, and is also quite some work. So we mostly stick to internal discussions atm. https://forum.dlang.org/post/o2g7mg$12oa$1 digitalmars.com Timelines and planning also don't work too well with volunteering.
Oct 21
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 10/21/17 9:47 AM, Martin Nowak wrote:
 On Friday, 20 October 2017 at 18:11:50 UTC, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 16:36:28 UTC, jmh530 wrote:
 It might help to have some sense of how the main devs time on D is 
 being used.
Definitely, I currently have no clue what they are on.
Tried that, didn't resonate that much, and is also quite some work. So we mostly stick to internal discussions atm. https://forum.dlang.org/post/o2g7mg$12oa$1 digitalmars.com Timelines and planning also don't work too well with volunteering.
Martin's levelheaded answers are much appreciated. (For what it's worth I've been traveling a fair amount recently which brings money in Foundation's coffers and more attention to the D language. I am coping with the unpleasant reality I haven't written real code in months.) The matter discussed in this thread seems to have been suddenly rendered political, which is why I find it opportune to intervene - in all likelihood, improving nothing :o). Sticking to technical points, some of the original points are easy to explain as misunderstandings (e.g. safe/system/trusted - yes all three are needed), whereas others can be converted productively into real steps forward for the language. Using the topic of the Elvis operator as a running example, a good DIP would contain motivation such as: * Present evidence of the successful use of ?: in other languages * Present evidence of workarounds being used in D such as orElse, lazyElse etc. * Present evidence of the usefulness of the ?: operator in gcc, see https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Conditionals.html * Show how production code fragments in dmd, phobos, or other codebases would be significantly improved by the use of the operator Yes, there's no guarantee that such a DIP would be approved. But the "need a relationship with the cabal to get things in" angle is very damaging to our community. So is the framing of the language enhancements topic as a fight against arbitrary prejudice. These kind of allegation discourage people from putting good work in, which is all that's needed. Andrei
Oct 21
parent reply user1234 <user1234 12.nl> writes:
On Saturday, 21 October 2017 at 19:39:31 UTC, Andrei Alexandrescu 
wrote:
 [...]
 Using the topic of the Elvis operator as a running example, a 
 good DIP would contain motivation such as:

 * Present evidence of the successful use of ?: in other 
 languages
I'm not sure that people talked much about the elvis operator (which was introduced in the topic by M.Nowak). In the first message were mentioned the null coalescence operator "??" and the safe navigation one "?." . The later was more discussed.
Oct 21
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Saturday, 21 October 2017 at 20:02:28 UTC, user1234 wrote:
 I'm not sure that people talked much about the elvis operator 
 (which was introduced in the topic by M.Nowak). In the first 
 message were mentioned the null coalescence operator "??"
What's the difference between `?:` and `??`? As far as I can tell, they'd do the same thing in most cases.
Oct 21
parent user1234 <user1234 12.nl> writes:
On Saturday, 21 October 2017 at 21:45:11 UTC, Adam D. Ruppe wrote:
 On Saturday, 21 October 2017 at 20:02:28 UTC, user1234 wrote:
 I'm not sure that people talked much about the elvis operator 
 (which was introduced in the topic by M.Nowak). In the first 
 message were mentioned the null coalescence operator "??"
What's the difference between `?:` and `??`? As far as I can tell, they'd do the same thing in most cases.
Elvis operator returns LHS if LHS is true, otherwise RHS Null coalescing operator returns LHS if LHS is not null, otherwise RHS But since in D nullable values can be interpreted as booleans you're right "?:" would do the same as "??" and even more. Actually "?:" is preferable (which i didn't realize in first place :/).
Oct 21
prev sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/20/2017 11:11 AM, Adam D. Ruppe wrote:
 On Friday, 20 October 2017 at 16:36:28 UTC, jmh530 wrote:
 It might help to have some sense of how the main devs time on D is being used.
Definitely, I currently have no clue what they are on.
Whiling away the hours, conferring with the flowers, consulting with the rain. My head I'm scratching while my thoughts are busy hatching.
Oct 21
prev sibling parent reply Laeeth Isharc <laeeth laeeth.com> writes:
On Friday, 20 October 2017 at 15:38:53 UTC, Martin Nowak wrote:
 Commercial usage, shared libraries and stuff
 There isn't any handy tool to download, manage and publish 
 closed source stuff.
 dub is great for simple solutions but useless in big projects 
 with multiple targets, configurations, etc.
 Everything is primary focused on opensource development (but 
 everyone here wants to see D as a next successor of C++ in 
 commercial sphere).
Well, dub is a package manager to share code, so obviously OSS it the main target. You can easily `dub add-local` packages or run your private registry.
https://github.com/dlang/dub/pull/985 "A common use-case (that I currently have) is a large project with many dub packages in it, which much be registered with dub, but don't have any purpose outside that project. It also allows any dependencies to be easily packaged inside a project in order to allow building an application without an internet connection, by just running dub upgrade --root=$APP_PROJECT_DIR --defaultRepoPath=$PROJECT_ROOT/deps/ on the dev machine, then dub build --root=$APP_PROJECT_DIR --defaultRepoPath=$PROJECT_ROOT/deps/ --skip-registry=all on the target machine." We've submitted a PR for our internal dub fork that we use to build a decent-sized project (not as big as Weka, but not much smaller). Sadly it required quite a few changes and was hard to break into bite-sized ones. If you're working on a big internal project, I'd say that it's worth thinking about things from a medium-term perspective. With D you have higher costs to get the build system etc right, but you gain and keep gaining from having more concise, clearer, more maintainable, and more plastic code. The costs are front-loaded though. If one's able to take a medium-term perspective and the changes you want to see in dub are not all that much, it may well be worth finding someone in the D community you can pay to help make those changes. A little money goes a long way because here you have strong programmers - who like programming! - from all over the world, and not everyone is in a situation that makes their opportunity cost as high as what it might be within the company (not just payroll, but overheads, co-ordination costs etc). And you may find other commercial users are willing to split the costs - that's something a large media company asked me about, and that we would be open to also if it's something that will fit with what we need.
 And of course there are various other options like Make, CMake, 
 Meson, or Raggae.
(Reggae). We use Reggae for building proprietary codebase. If there's a feature missing, please do say - maybe we would benefit from it, and since Atila works with us, it's something easy to consider when time.
 As unfortunately with almost any OSS project, we're not that 
 many people, and each of us is investing a huge amount of time 
 into this.
Also - for example with dub. Dub and vibe constitute an amazing achievement for one man. I don't mean to diminish the contribution of others, but I guess Sonke has been the creative spirit behind them and has done most of the work. There's one challenge that arises when you can benefit from the work of unusually productive people (of whom there seem to be many in the D community - I just take Sonke as one example), is that for that same reason they end up getting responsibility in the commercial parts of their lives, which might mean less time available to devote to open-source at certain points. There are 39 pull requests open on dub currently. It's not a super-complicated code base, but I guess the people responsible for dub have quite a lot on their plates. I don't know how others might be able to help, but maybe that is one area that would benefit the language ecosystem more generally. (I get the impression sometimes that people want to help, but they don't completely know how). There's no mention of dub here, for example: https://wiki.dlang.org/Get_involved Now there is.. (I just added it). https://wiki.dlang.org/Get_involved#Review_pull_requests
 But again your best bet on getting sth. done is working on it, 
 be it writing a DIP, organizing the discussion, or actually 
 implementing it.
Bountysource went quiet, though I started contributing to it. I wonder if there is a better way for commercial users to say what they might be willing to pay for and how much. I don't think that keeping patches private for a while really fits. It doesn't hurt me if some other D user benefits from work I sponsored. In fact it helps me if it is incorporated into the main codebase, because that means I don't need to worry about maintaining it. And that's in any case way too selfish a perspective - not smart commercially: if D flourishes, it helps us too. Laeeth.
Oct 23
parent reply Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 11:58:14 UTC, Laeeth Isharc wrote:
 Bountysource went quiet, though I started contributing to it.
 I wonder if there is a better way for commercial users to say 
 what they might be willing to pay for and how much.
At best talk to Andrei, maybe you have a good idea to do this over the Foundation.
Oct 24
parent Guillaume Piolat <contact spam.com> writes:
On Tuesday, 24 October 2017 at 18:55:13 UTC, Martin Nowak wrote:
 On Monday, 23 October 2017 at 11:58:14 UTC, Laeeth Isharc wrote:
 Bountysource went quiet, though I started contributing to it.
 I wonder if there is a better way for commercial users to say 
 what they might be willing to pay for and how much.
At best talk to Andrei, maybe you have a good idea to do this over the Foundation.
Makes sense. A clear, read-only view on what the D Foundation sponsors would be really helpful to incentivize sponsorship.
Oct 25
prev sibling next sibling parent reply Ecstatic Coder <ecstatic.coder gmail.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).


 First, D started as a great new language with the best from all 
 languages. But now D seems more and more conservative. New 
 syntactic sugars aren't added just because they can be found in 
 phobos. (this was Walter's answer when I asked for maybe monad 
 syntactic sugar).

 OK, what I'm missing in D and what I think is wrong?

 syntactic sugar for:
 tuples
 maybe monad (why we cannot have same syntax as in C#?)
 conditional dereferencing and stuff about that (same as in C#)
 foo?.bar;
 foo?[bar];
 return foo ?? null;

 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 I want to create function returning Promise/Task and await 
 where I want to.
 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result

 I want to do this and not any ugly workaround about that.


  trusted,  safe,  system - why we have 3 keywords instead of 
 one? And why it's so complicated to use?

 First, we should have one 'unsafe' keyword.
 Second, everything should be safe by default.
 3rd, if we want to declare  system func, use 'void foo() 
 unsafe;'
 if we want to declare  trusted func, use
 void foo() {
 unsafe {

 }
 }

 This fulfills the D's idiom in better way, because we should be 
 defining unsafe sections as small as possible.


 C# properties instead of existing ones.
 function and property should be two different things.
 Calling function without () or assigning to it by = is a ugly 
 behavior and should be avoided.

 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };


 Reference counting when we cannot use GC...


 Commercial usage, shared libraries and stuff
 There isn't any handy tool to download, manage and publish 
 closed source stuff.
 dub is great for simple solutions but useless in big projects 
 with multiple targets, configurations, etc.
 Everything is primary focused on opensource development (but 
 everyone here wants to see D as a next successor of C++ in 
 commercial sphere).


 Still cannot easily develop closed source dlls on Windows. On 
 Linux every symbol is public by default, but on Windows not so 
 it's needed to export them manually.


 Unable to publish closed source library without workaround and 
 ugly PIMPL design.

 Add dll/so usage without header files
 (export enums, templates and stuff right into dll/so and let D 
 compiler to import these stuff from it)



 For me, it seems like Walter is solving edge case problems like 
 return ref parameters and return functions but is unable to add 
 some basic stuff.


 Thanks for your time.
 - Satoshi
Interesting proposals, but IMHO, the only ESSENTIAL feature missing in D is the possibility to program in D using a built-in reference-counting based variant of the standard library. If D really sells itself as a C++ alternative, then it MUST be a true C++/Rust competitor. So using stuff like strings, slices, maps, reference classes should be made possible without GC. You just need a few qualifiers to say if a class instance is owned by a reference (behavior by default) or just pointed by a weak reference (i.e a pointer with automatic deferencing). That ALONE would make D a better competitor to C++ on its grounds. Add full binary compatibility at the linker level with C++ library and you may now have a real opportunity to "win" the war against C++ and Rust. Or you can just wait that C++ improves enough (modules, etc) so that D provides too few advantages to be an interesting alternative...
Oct 20
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Friday, 20 October 2017 at 19:18:15 UTC, Ecstatic Coder wrote:
 Interesting proposals, but IMHO, the only ESSENTIAL feature 
 missing in D is the possibility to program in D using a 
 built-in reference-counting based variant of the standard 
 library.
Look at the goals for H2 2017 https://wiki.dlang.org/Vision/2017H2 The top three things: 1) safety, 2) nogc, 3) betterC. Under #2, it specifically says safe reference counting. It's getting worked on...
Oct 20
parent Martin Nowak <code dawg.eu> writes:
On Friday, 20 October 2017 at 20:05:51 UTC, jmh530 wrote:
 Interesting proposals, but IMHO, the only ESSENTIAL feature 
 missing in D is the possibility to program in D using a 
 built-in reference-counting based variant of the standard 
 library.
Look at the goals for H2 2017 https://wiki.dlang.org/Vision/2017H2 The top three things: 1) safety, 2) nogc, 3) betterC. Under #2, it specifically says safe reference counting. It's getting worked on...
Yes, it's being worked on, but it's also a huge topic to come up with safe memory management approach. It's literally about eradicating one of the biggest security bug classes, use-after-free. Currently I'm working towards an ORM library starting at I/O (https://github.com/MartinNowak/io) to better inform the necessary design. We already found couple of interesting litmus tests, like the window in iopipe. auto window = iopipe.window; iopipe.extend(512); // invalidates window :/ window[0]; // use after-free Another thing that Walter previously found out is that exceptions are a major hassle for nogc. I don't like the RC Exception solution much though, as it's a fairly specific workaround (https://github.com/dlang/druntime/pull/1804). Towards that goal, making exception nesting optional and providing access to the current Exception in flight would allow to use the staticError approach in most places. https://github.com/dlang/druntime/blob/bc832b18430ce1c85bf2dded07bbcfe348ff0813/src/core/exception.d#L683 Recently I wondered why we cannot semantically transform exceptions to the equivalent of function calls. - throw Uniq!Exception; // ctor, some struct that's implicitly convertible to a Throwable - catch (scope Exception e) // handler 1 { throw e; // basically continue to unwind } - catch (scope Exception e) {} // handler 2 - done unwinding, destroy thrown value We still support gotos in catch handlers, but should be possible to call destructors in catch handlers anyhow. https://github.com/dlang/druntime/pull/1804/files#diff-f3953348bb302c27a8cea926c62c02e6R69
Oct 21
prev sibling next sibling parent Mark <smarksc gmail.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).

 [...]

 Thanks for your time.
 - Satoshi
I'm surprised that you didn't mention pattern matching. I really like it in Rust.
Oct 21
prev sibling next sibling parent reply bitwise <bitwise.pvt gmail.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 Reference counting when we cannot use GC...
If I understand correctly, both of these depend on implementation of 'scope' which is being worked on right now. I think reference counting needs 'scope' to be made safe. RC also benefits from scope in that many of the increments/decrements of the ref count can be elided. The performance gain can be significant, and even more so when you use atomic reference counting (like C++ shared_ptr) for thread safety. Async/Await needs to allocate state for the function's local variables. When it's detected that the function's state/enumerator won't escape it's current scope, it can be put on the stack, which is a pretty big optimization. I should also note that, RC has been formally acknowledged as a future goal of D, but as far as I know, async/await has not.
Oct 21
next sibling parent reply Adam Wilson <flyboynw gmail.com> writes:
On 10/21/17 11:52, bitwise wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 async/await (vibe.d is nice but useless in comparison to C# or js
 async/await idiom)
 Reference counting when we cannot use GC...
If I understand correctly, both of these depend on implementation of 'scope' which is being worked on right now. I think reference counting needs 'scope' to be made safe. RC also benefits from scope in that many of the increments/decrements of the ref count can be elided. The performance gain can be significant, and even more so when you use atomic reference counting (like C++ shared_ptr) for thread safety. Async/Await needs to allocate state for the function's local variables. When it's detected that the function's state/enumerator won't escape it's current scope, it can be put on the stack, which is a pretty big optimization. I should also note that, RC has been formally acknowledged as a future goal of D, but as far as I know, async/await has not.
Walter has stated numerous times both here and at conferences that Async/Await is definitely a goal. However, it's not as high a priority as the safe/ nogc work so it hasn't made it to any official vision statement. Also I just talked to him offline about it, and he would need some serious help with it. He doesn't know how to do the compiler rewrite, and there a number of tricky situations one has to deal with. As much as I like Async/Await, I agree that the current plan has higher priority. I'll probably start poking around Async/Await when I can clear the decks a bit of paid work. But that could be a while. :( -- Adam Wilson IRC: LightBender import quiet.dlang.dev;
Oct 21
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/21/2017 1:40 PM, Adam Wilson wrote:
 Walter has stated numerous times both here and at conferences that Async/Await 
 is definitely a goal. However, it's not as high a priority as the  safe/ nogc 
 work so it hasn't made it to any official vision statement. Also I just talked 
 to him offline about it, and he would need some serious help with it. He
doesn't 
 know how to do the compiler rewrite, and there a number of tricky situations
one 
 has to deal with. As much as I like Async/Await, I agree that the current plan 
 has higher priority.
 
 I'll probably start poking around Async/Await when I can clear the decks a bit 
 of paid work. But that could be a while. :(
Async/Await can be implemented by rewriting ("lowering") the code to simpler D code. Implementing it awaits (!) figuring out just what those rewrite rules are.
Oct 21
parent reply bitwise <bitwise.pvt gmail.com> writes:
On Saturday, 21 October 2017 at 21:31:45 UTC, Walter Bright wrote:
 On 10/21/2017 1:40 PM, Adam Wilson wrote:
 Walter has stated numerous times both here and at conferences 
 that Async/Await is definitely a goal.
Async/Await can be implemented by rewriting ("lowering") the code to simpler D code. Implementing it awaits (!) figuring out just what those rewrite rules are.
Wow - great news. I hope resumable functions for for generator/coroutine style usage are also part of the plan. Allocator support would be nice too.
Oct 22
parent Martin Nowak <code dawg.eu> writes:
On Sunday, 22 October 2017 at 22:00:19 UTC, bitwise wrote:
 I hope resumable functions for for generator/coroutine style 
 usage are also part of the plan. Allocator support would be 
 nice too.
Please see https://forum.dlang.org/post/pbnthucxpvbgzzuigtrq forum.dlang.org for how this could be implemented and why this is not much of a priority right now. If someone wants to pull this off, the effort would be very welcome.
Oct 23
prev sibling parent reply Martin Nowak <code dawg.eu> writes:
On Saturday, 21 October 2017 at 18:52:15 UTC, bitwise wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 Reference counting when we cannot use GC...
If I understand correctly, both of these depend on implementation of 'scope' which is being worked on right now.
Scope is about preventing pointer escaping, ref-counting also needs to make use-after-free safe which is currently in the early spec phase. Whether or not that is going to be a compile-time or runtime check has yet to be figured out. If you have a great idea that we should consider, let us know. The recent IOPipe window invalidation discussion was a good example of what such a mechanism would hopefully be able to handle (https://gist.github.com/MartinNowak/b406a6b7aa6d0964147c107771b64333#file-safety_dance-d-L43-L45).
 I think reference counting needs 'scope' to be made safe. RC 
 also benefits from scope in that many of the 
 increments/decrements of the ref count can be elided. The 
 performance gain can be significant, and even more so when you 
 use atomic reference counting (like C++ shared_ptr) for thread 
 safety.
Well, there can be RC and shared(RC), only the latter would need to do atomic ref-counting.
 Async/Await needs to allocate state for the function's local 
 variables. When it's detected that the function's 
 state/enumerator won't escape it's current scope, it can be put 
 on the stack, which is a pretty big optimization.
We should figure out how to allocate RC/unique delegate contexts. Not that with async/await you always escape the local context, as it's the callback in the returned Promise/Task.
Oct 23
parent bpr <brogoff gmail.com> writes:
On Monday, 23 October 2017 at 11:21:13 UTC, Martin Nowak wrote:
 On Saturday, 21 October 2017 at 18:52:15 UTC, bitwise wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 async/await (vibe.d is nice but useless in comparison to C# 
 or js async/await idiom)
 Reference counting when we cannot use GC...
If I understand correctly, both of these depend on implementation of 'scope' which is being worked on right now.
Scope is about preventing pointer escaping, ref-counting also needs to make use-after-free safe which is currently in the early spec phase.
FYI, in cousin (imperative, GC'ed, systems PL) language Nim, there's currently some similar discussion around how to make seq and string GC free: https://nim-lang.org/araq/destructors.html so these efforts in D are timely.
Oct 23
prev sibling next sibling parent reply EntangledQuanta <EQ universe.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).


 First, D started as a great new language with the best from all 
 languages. But now D seems more and more conservative. New 
 syntactic sugars aren't added just because they can be found in 
 phobos. (this was Walter's answer when I asked for maybe monad 
 syntactic sugar).

 OK, what I'm missing in D and what I think is wrong?

 syntactic sugar for:
 tuples
 maybe monad (why we cannot have same syntax as in C#?)
 conditional dereferencing and stuff about that (same as in C#)
 foo?.bar;
 foo?[bar];
 return foo ?? null;

 async/await (vibe.d is nice but useless in comparison to C# or 
 js async/await idiom)
 I want to create function returning Promise/Task and await 
 where I want to.
 e.g.
 auto result = device.start(foo, bar); // This is RPC to remote 
 server returning Task!Bar
 // do some important stuff
 return await result; // wait for RPC finish, then return it's 
 result

 I want to do this and not any ugly workaround about that.


  trusted,  safe,  system - why we have 3 keywords instead of 
 one? And why it's so complicated to use?

 First, we should have one 'unsafe' keyword.
 Second, everything should be safe by default.
 3rd, if we want to declare  system func, use 'void foo() 
 unsafe;'
 if we want to declare  trusted func, use
 void foo() {
 unsafe {

 }
 }

 This fulfills the D's idiom in better way, because we should be 
 defining unsafe sections as small as possible.


 C# properties instead of existing ones.
 function and property should be two different things.
 Calling function without () or assigning to it by = is a ugly 
 behavior and should be avoided.

 implement this thing from C# (just because it's cool)
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };


 Reference counting when we cannot use GC...


 Commercial usage, shared libraries and stuff
 There isn't any handy tool to download, manage and publish 
 closed source stuff.
 dub is great for simple solutions but useless in big projects 
 with multiple targets, configurations, etc.
 Everything is primary focused on opensource development (but 
 everyone here wants to see D as a next successor of C++ in 
 commercial sphere).


 Still cannot easily develop closed source dlls on Windows. On 
 Linux every symbol is public by default, but on Windows not so 
 it's needed to export them manually.


 Unable to publish closed source library without workaround and 
 ugly PIMPL design.

 Add dll/so usage without header files
 (export enums, templates and stuff right into dll/so and let D 
 compiler to import these stuff from it)



 For me, it seems like Walter is solving edge case problems like 
 return ref parameters and return functions but is unable to add 
 some basic stuff.
These guys are old now and don't have the drive they used to have. It happens, part of life. Unfortunately they do not realize this and do not want to pass the torch. I wouldn't expect anything major for D any more unless something significant changes in the management. D is stagnate, unfortunately and will almost surely never be a major player. It's unfortunate but D has a lot of problems. It is not commercially viable for the mass market. D is a hobby language and will remain that way for the majority of it's users. This is almost entirely due to the mind set you have. It's a lot of work to bring D up to par with the other languages and there seems very little interest in actually making that happen. Walter only see's what he wants. He looks at D and does not see the flaws like mother looking at her ugly baby. If one always looks at the pros and ignores the cons then anything looks good. D has a lot of great things but also a lot of bad things... until those bad things are fixed D won't go anywhere... it would be nice, at least, if the management would be objective about the bad things instead of sweeping them under the rug. Faking it until you make it is not an option here.
Oct 21
parent reply meppl <mephisto nordhoff-online.de> writes:
On Sunday, 22 October 2017 at 01:02:06 UTC, EntangledQuanta wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 ...
These guys are old now and don't have the drive they used to have. It happens, part of life. Unfortunately they do not realize this and do not want to pass the torch. I wouldn't expect anything major for D any more unless something significant changes in the management.
I thought the actual problem is just that dlang has not enough developer resources. Being young doesn't fix that. Wasn't the staff old already when D2 came out? ps, also i want something similar to this in D:
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };
it might solve things better than named parameters https://wiki.dlang.org/DIP88
Oct 22
parent bauss <jj_1337 live.dk> writes:
On Sunday, 22 October 2017 at 07:23:14 UTC, meppl wrote:
 On Sunday, 22 October 2017 at 01:02:06 UTC, EntangledQuanta 
 wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 ...
ps, also i want something similar to this in D:
 new Foo() {
   property1 = 42,
   property2 = "bar"
 };
it might solve things better than named parameters https://wiki.dlang.org/DIP88
Well the thing is. This already exist for structs and I have always wondered why it doesn't exist for classes. See: https://dlang.org/spec/struct.html#static_struct_init The example: ``` struct S { int a; int b; int c; int d = 7;} static S x = { a:1, b:2}; // c is set to 0, d to 7 static S z = { c:4, b:5, a:2 , d:5}; // z.a = 2, z.b = 5, z.c = 4, z.d = 5 ``` So it would make sense if classes supported it in the same way like: ``` class S { int a; int b; int c; int d = 7; } static S x = new { a:1, b:2 }; // static auto x = new S { a:1, b:2 }; static S z = new { c:4, b:5, a:2, d:5 }; // static auto z = new S { c:4, b:5, a:2, d:5 }; ```
Oct 22
prev sibling next sibling parent reply meppl <mephisto nordhoff-online.de> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 syntactic sugar for:
 tuples
as far as i know there was the will to implement tuples in the language, but there is still a deprecation in the way: https://dlang.org/deprecate.html#Using%20the%20result%20of%20a%20comma%20expression
Oct 22
parent meppl <mephisto nordhoff-online.de> writes:
On Sunday, 22 October 2017 at 15:07:10 UTC, meppl wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:

 syntactic sugar for:
 tuples
as far as i know there was the will to implement tuples in the language, but there is still a deprecation in the way: https://dlang.org/deprecate.html#Using%20the%20result%20of%20a%20comma%20expression
oh, i was wrong. after testing it i noticed "Using the result of a comma expression" doesnt work anymore.
Oct 22
prev sibling next sibling parent Arun Chandrasekaran <aruncxy gmail.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
The language for sure is huge and complicated and adding new features will only make it grow bigger. I'm not saying we shouldn't add any new features. It is important to have the right defaults to gain the critical mass for the momentum to reach the next level. I've been playing with D and most of the times I look for the idiomatic way of doing things in D rather than bringing my Java/C++ baggage with it. p0nce's d-idioms[1] is excellent, but is still not enough. We should have more like it (and better). Without the libraries like Boost and Qt, and ideas from books like Effective C++ series, Modern C++ design, etc it was once impossible for "humans" to write maintainable code in C++03. C++11/14 improved it a bit. D is brilliant in many ways: 1. has the best C++ interfacing 2. very easy to write and reason about Found this gem when reading Phobos ``` import std.algorithm, std.range, std.stdio; void main() { enum size = 500; writef("P5\n%d %d %d\n", size, size, ubyte.max); iota(-1, 3, 2.0/size).map!(y => iota(-1.5, 0.5, 2.0/size).map!(x => cast(ubyte)(1+ recurrence!((a, n) => x + y*1i + a[n-1]^^2)(0+0i) .take(ubyte.max) .countUntil!(z => z.re^^2 + z.im^^2 > 4)) ) ) .copy(stdout.lockingBinaryWriter); } ``` Such code should be on the front page to "market" 3. human readable std lib (unlike libstdc++) 4. Some features are very well thought and well designed, but some are not 5. TMP for humans The community lacks language theory expert (purist?). (Rust community has the maximum, if I'm correct).
Oct 23
prev sibling next sibling parent reply Satoshi <satoshi rikarin.org> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).

 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
Oct 23
next sibling parent Seb <seb wilzba.ch> writes:
On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).

 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
https://github.com/dlang/dmd/pull/6703 Requires someone to write this up as a DIP.
Oct 23
prev sibling next sibling parent Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).

 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
String interpolation could be done in a library. fmt!("Foo is ${foo} and bar is ${bar}", foo, bar) At the moment you'd just use format. format!"Foo is %1$s and bar is %2$s"(foo, bar); While both are a bit more verbose, it seems to me that interpolated strings aren't that big a deal. Collecting arguments and design ideas in a DIP would still be worthwhile and very welcome. Even if ends up not being approved, it would ensure a good decision base and avoid future discussions. Sth. like s"Foo is ${foo} and bar is ${bar ~ `bla`}" to be lowered to format!"Foo is %1$s and bar is %2$s"(foo, bar ~ `bla`). could be a feasible approach on a first thought.
Oct 23
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 Hi,
 I had been using D for almost 6 years and I want to share my 
 opinion with you.
 I don't want to blame anyone but I'll focus more on bad things 
 and possible improvements.
 And this is just how I see D from my perspective.
 (Sorry for my English, I'm too lazy to take the lessons).

 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Oct 23
next sibling parent reply bauss <jj_1337 live.dk> writes:
On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... } Guess sendAMessage("Foo is", foo, "and bar is", bar); won't work. However sendAMessage(`Foo is {foo} and bar is {bar}`); would have. Your example is a common "counter-answer" to string interpolation, but it's missing the key point that you don't always use it for printing stuff.
Oct 23
parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
Oct 23
next sibling parent reply Satoshi <satoshi rikarin.org> writes:
On Monday, 23 October 2017 at 21:42:03 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
boilerplate...
Oct 24
parent reply Atila Neves <atila.neves gmail.com> writes:
On Tuesday, 24 October 2017 at 07:17:08 UTC, Satoshi wrote:
 On Monday, 23 October 2017 at 21:42:03 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi 
 wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
boilerplate...
True, but in my opinion not enough to justify complicating the language. One could also always do: import std.conv: t = text; sendAMessage(t("Foo is ", foo, " and bar is ", bar")); If it were me I'd just make `sendAMessage` take a variadic template and call text internally. Atila
Oct 24
next sibling parent Satoshi <satoshi rikarin.org> writes:
On Tuesday, 24 October 2017 at 08:06:55 UTC, Atila Neves wrote:
 On Tuesday, 24 October 2017 at 07:17:08 UTC, Satoshi wrote:
 On Monday, 23 October 2017 at 21:42:03 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves 
 wrote:
 [...]
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
boilerplate...
True, but in my opinion not enough to justify complicating the language. One could also always do: import std.conv: t = text; sendAMessage(t("Foo is ", foo, " and bar is ", bar")); If it were me I'd just make `sendAMessage` take a variadic template and call text internally. Atila
so, we should complicate source code instead of the language? Actually, you provide one of the best examples why we should add this syntactic sugar.
Oct 24
prev sibling parent reply ecstatic.coder <ecstatic.coder gmail.com> writes:
On Tuesday, 24 October 2017 at 08:06:55 UTC, Atila Neves wrote:
 On Tuesday, 24 October 2017 at 07:17:08 UTC, Satoshi wrote:
 On Monday, 23 October 2017 at 21:42:03 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves 
 wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi 
 wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
boilerplate...
True, but in my opinion not enough to justify complicating the language. One could also always do: import std.conv: t = text; sendAMessage(t("Foo is ", foo, " and bar is ", bar")); If it were me I'd just make `sendAMessage` take a variadic template and call text internally. Atila
I agree. D MUST remain as simple as possible. For instance I'm against forcing D programmers to use annotations which won't be implicit anymore. Keep D's syntax as simple and concise as it is now, don't make it more complicated. And if you add synctactic sugar constructs to make it even more concise, first make sure that this won't make D more complicated to learn and to use...
Oct 25
parent reply bauss <jj_1337 live.dk> writes:
On Wednesday, 25 October 2017 at 16:07:21 UTC, ecstatic.coder 
wrote:
 On Tuesday, 24 October 2017 at 08:06:55 UTC, Atila Neves wrote:
 [...]
I agree. D MUST remain as simple as possible. For instance I'm against forcing D programmers to use annotations which won't be implicit anymore. Keep D's syntax as simple and concise as it is now, don't make it more complicated. And if you add synctactic sugar constructs to make it even more concise, first make sure that this won't make D more complicated to learn and to use...
Syntactic sugar is what makes a language easy to learn, because you don't have to memorize functions, their modules and whether you imported them or not, which modules imported which modules public, so you don't need to. Ex. the example above you have to remember which module the function is stored, what the name of the function is and the exact arguments of it. Now that may sound like "Oh it's not a big deal with such a thing", but it's still extra unnecessary work required to do something as simple as constructing a string. You must remember to import the module too and you must also know which modules have the module imported as public import, because in those cases you don't need to import it. That's another extra thought you need to have, that must be repeated for every module. I often tend to forget to important for format() and it's kinda tedious when you write multiple big modules and then forgot to do the correct imports and you have to go into all of them and fix it. Of course you could just assume no modules have public imports and you won't need to worry about which modules import what, but that defeats the whole purpose of public imports in the specific modules too, which makes the module system seem complicate and kinda useless, compared to how "complicated" a simple syntactic sugar addition like string interpolation, which btw. pretty much is a feature in most modern languages these days. String interpolation is a very handy feature to write bugless code, because it's much harder to end up writing errors in your code like Atila already showed in his example that was supposed to show why you shouldn't have the feature.
Oct 25
parent bauss <jj_1337 live.dk> writes:
On Wednesday, 25 October 2017 at 18:54:16 UTC, bauss wrote:
 On Wednesday, 25 October 2017 at 16:07:21 UTC, ecstatic.coder 
 wrote:
 [...]
Syntactic sugar is what makes a language easy to learn, because you don't have to memorize functions, their modules and whether you imported them or not, which modules imported which modules public, so you don't need to. [...]
Also to add on to this with having to modify the "sendAMessage()" function. What if the function is located in a 3rd party library? Then you can't do such things, where string interpolation would be the better upper-hand.
Oct 25
prev sibling parent bauss <jj_1337 live.dk> writes:
On Monday, 23 October 2017 at 21:42:03 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 21:14:18 UTC, bauss wrote:
 On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 [...]
Whats about this one? auto foo = 42; auto bar = "bar"; writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters. Atila
Okay, but what about now? void sendAMessage(string message) { .... }
sendAMessage(text(...)); Atila
But that goes against what you just said with "4 characters more" since text is 4 characters. It's also an extra import which you could avoid with string interpolation.
Oct 24
prev sibling parent Biotronic <simen.kjaras gmail.com> writes:
On Monday, 23 October 2017 at 12:48:33 UTC, Atila Neves wrote:
 On Monday, 23 October 2017 at 09:13:45 UTC, Satoshi wrote:
 writeln(`Foo is {foo} and bar is {bar}`);
writeln("Foo is ", foo, "and bar is ", bar"); Two more characters.
You have actually demonstrates exactly what I feel is the main benefit of the "{foo}" syntax: Your example is missing a space before 'and'. This type of error is very easy to overlook with the ", " syntax, and much more visible with the "{foo}" syntax. The "%s" syntax also solves this problem, but at the cost of moving the formatted value away from the point of formatting. -- Biotronic
Oct 24
prev sibling next sibling parent reply Guillaume Piolat <contact spam.com> writes:
On Wednesday, 18 October 2017 at 08:56:21 UTC, Satoshi wrote:
 dub is great for simple solutions but useless in big projects 
 with multiple targets, configurations, etc.
Works here. Closed source can be handled with path-based dependencies and private checkouts. Configurations are handled by... dub configurations. Targets? by dub targets.
 Still cannot easily develop closed source dlls on Windows. On 
 Linux every symbol is public by default, but on Windows not so 
 it's needed to export them manually.
Not anymore, you can use the "export" keyword for Windows (eg with LDC >= 1.2). Every-symbol-public-by-default in Posix is annoying though :)
 For me, it seems like Walter is solving edge case problems like 
 return ref parameters and return functions but is unable to add 
 some basic stuff.
Because **everyone has its own, different opinion of what the "basic stuff which is absolutely needed" is**, and adding all of that would be 3x the size of D and unpleasant. For starters, some of us would like stuff to be _removed_, not added. It's like a tradition: each new generation of D users ask for the additional, "must-have" features of the day.
Oct 23
parent reply Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 11:23:18 UTC, Guillaume Piolat 
wrote:
 Not anymore, you can use the "export" keyword for Windows (eg 
 with LDC >= 1.2).
With what semantic?
 Every-symbol-public-by-default in Posix is annoying though :)
We agreed on hidden visibility by default for everything that's not exported. This requires export to be fixed on non-Windows machines first. By any means, if someone wants to help here, get in touch with Benjamin Thaut and me. This has been lingering around for way to long, and Benjamin alone has a hard time pushing this.
Oct 23
parent reply Guillaume Piolat <contact spam.com> writes:
On Monday, 23 October 2017 at 11:39:58 UTC, Martin Nowak wrote:
 On Monday, 23 October 2017 at 11:23:18 UTC, Guillaume Piolat 
 wrote:
 Not anymore, you can use the "export" keyword for Windows (eg 
 with LDC >= 1.2).
With what semantic?
We used to require .def files, and now use "export" instead on Windows. Works on DMD (not sure since what version) and LDC since https://github.com/ldc-developers/ldc/pull/1856 Windows only and free functions only.
 Every-symbol-public-by-default in Posix is annoying though :)
We agreed on hidden visibility by default for everything that's not exported. This requires export to be fixed on non-Windows machines first.
This is especially interesting since hidden visibility for most symbols is required to make -dead_strip effective (strips most of the object code here).
 By any means, if someone wants to help here, get in touch with 
 Benjamin Thaut and me.
 This has been lingering around for way to long, and Benjamin 
 alone has a hard time pushing this.
Would Bountysource help be adequate?
Oct 23
next sibling parent reply Martin Nowak <code dawg.eu> writes:
On Monday, 23 October 2017 at 13:18:21 UTC, Guillaume Piolat 
wrote:
 By any means, if someone wants to help here, get in touch with 
 Benjamin Thaut and me.
 This has been lingering around for way to long, and Benjamin 
 alone has a hard time pushing this.
Would Bountysource help be adequate?
Not sure about Benjamin, but on my side it's time limited. I'd Bountysource didn't work out too well for us.
Oct 24
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Tuesday, October 24, 2017 18:53:49 Martin Nowak via Digitalmars-d wrote:
 On Monday, 23 October 2017 at 13:18:21 UTC, Guillaume Piolat

 wrote:
 By any means, if someone wants to help here, get in touch with
 Benjamin Thaut and me.
 This has been lingering around for way to long, and Benjamin
 alone has a hard time pushing this.
Would Bountysource help be adequate?
Not sure about Benjamin, but on my side it's time limited. I'd Bountysource didn't work out too well for us.
For it to work, it would likely either have to encourage developers who aren't involved to get involved or provide enough money that developers who are already involved could spend more time on D (e.g. because they're a contractor and the money from a bounty was able to temporarily function as their source of income). I don't think that either happened. Most of the bounties were pretty small, and most full-time employees who work with D in their free time are unlikely to be able to spend more time on D due to some extra money, because time is the concern, not money. Best case, I'd expect bountysource to encourage folks already working on D to work on something specific, because they'd get a bit of extra money for it, but that doesn't seem to have happened. I think that most of the folks contributing have forgotten about bountysource entirely. Anyone looking to help D grow via money is probably better off donating to the D foundation - though whether this particular item is high enough of the priority list for the D foundation to pay someone to work on it, I don't know, and I don't know if there's someone with the appropriate skillset who's available to be paid to work on it. The D Foundation is pretty new at this (but the fact that it exists at all is a huge step forward). There has been some interest in "improved DLL" support, which ties into improving export on Windows, but there doesn't seem to have been a lot of interest in actually working on it (at least not from folks with the time to). - Jonathan M Davis
Oct 24
prev sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Monday, October 23, 2017 13:18:21 Guillaume Piolat via Digitalmars-d 
wrote:
 On Monday, 23 October 2017 at 11:39:58 UTC, Martin Nowak wrote:
 Every-symbol-public-by-default in Posix is annoying though :)
We agreed on hidden visibility by default for everything that's not exported. This requires export to be fixed on non-Windows machines first.
This is especially interesting since hidden visibility for most symbols is required to make -dead_strip effective (strips most of the object code here).
There are good technical reasons for requiring export, but man do I hate having to deal with it when doing Windows development in C++. It is _so_ nice to not have to care when working on *nix codebases in C++ and so annoying to deal with it when I have to worry about Windows that I lean heavily towards not wanting export to be required in D even if there are some definite technical problems with it. I've never had good things to say about having to export stuff on Windows, no matter the language. - Jonathan M Davis
Oct 24
prev sibling parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/18/2017 1:56 AM, Satoshi wrote:
 Unable to publish closed source library without workaround and ugly PIMPL
design.
Consider this: ----------- file s.d ------------ struct S { int x; this(int x) { this.x = x; } int getX() { return x; } } ----------- file s.di ------------ struct S { this(int x); int getX(); } -------------------------- User code: import s; S s = S(3); writeln(s.getX()); Ta dah! Implementation is hidden, no PIMPL. Of course, inlining of the member functions won't work, but it won't work in C++, either, when this technique is used. I.e. you can use .di/.d files just like you'd use .h/.cpp in C++. The technique works with classes, too.
Oct 23
next sibling parent reply Satoshi <satoshi rikarin.org> writes:
On Monday, 23 October 2017 at 20:47:26 UTC, Walter Bright wrote:
 On 10/18/2017 1:56 AM, Satoshi wrote:
 Unable to publish closed source library without workaround and 
 ugly PIMPL design.
Consider this: ----------- file s.d ------------ struct S { int x; this(int x) { this.x = x; } int getX() { return x; } } ----------- file s.di ------------ struct S { this(int x); int getX(); } -------------------------- User code: import s; S s = S(3); writeln(s.getX()); Ta dah! Implementation is hidden, no PIMPL. Of course, inlining of the member functions won't work, but it won't work in C++, either, when this technique is used. I.e. you can use .di/.d files just like you'd use .h/.cpp in C++. The technique works with classes, too.
what about this: ---------- file.d class Foo { private int bar; private string text; void call() { } } ----------- file.di class Foo { call(); } and then I want to inherit from it (I have access to file.di only) class Bar : Foo { // I cannot due I have misleading information about size of Foo }
Oct 24
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2017 12:21 AM, Satoshi wrote:
 what about this:
 
 ---------- file.d
 class Foo {
    private int bar;
    private string text;
 
    void call() { }
 }
 
 ----------- file.di
 
 class Foo {
    call();
 }
 
 
 
 and then I want to inherit from it (I have access to file.di only)
 class Bar : Foo { // I cannot due I have misleading information about size of
Foo
 
 }
If you don't add data members to Bar, it will work. If you do add data members, then the compiler needs to know the data members in Foo. This is the same in C++ .h files. You could specify Foo as an interface, https://dlang.org/spec/interface.html and then Bar can inherit from Foo without needing any knowledge of Foo's data members.
Oct 24
parent reply Satoshi <satoshi rikarin.org> writes:
On Tuesday, 24 October 2017 at 07:55:49 UTC, Walter Bright wrote:
 On 10/24/2017 12:21 AM, Satoshi wrote:
 what about this:
 
 ---------- file.d
 class Foo {
    private int bar;
    private string text;
 
    void call() { }
 }
 
 ----------- file.di
 
 class Foo {
    call();
 }
 
 
 
 and then I want to inherit from it (I have access to file.di 
 only)
 class Bar : Foo { // I cannot due I have misleading 
 information about size of Foo
 
 }
If you don't add data members to Bar, it will work. If you do add data members, then the compiler needs to know the data members in Foo. This is the same in C++ .h files. You could specify Foo as an interface, https://dlang.org/spec/interface.html and then Bar can inherit from Foo without needing any knowledge of Foo's data members.
But it's quite useless to me. i.e. class View { } class Button : View { } I want to let users to inherit from View or Button and let them customize the elements. This can be done just by PIMPL. But doing PIMPL inheritance inside one library is pain in the a$$. -------------------- view.d ------------------ class View { private ViewData _; package class ViewData { int a, b, c; } this() { initData(); } protected void initData() { if (!_) _ = new ViewData; } void render() { } } ----------------------- button.d ----------- class Button : View { package class ButtonData : ViewData { string stuff; } protected override void initData() { if (!_) _ = new ButtonData; } void simulateClick() { } } and headers ------------- view.di ------------ class View { private void* _; this(); void render(); } ------------- button.di --------------- class Button : View { void simulateClick(); } But the worst part is that I need to hold di in sync to d files manually, so there is not any advantages over C++'s header files.
Oct 24
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2017 1:13 AM, Satoshi wrote:
 But it's quite useless to me.
That's what interfaces are for. Define your View and Button as interfaces. The implementations of interfaces are completely hidden from the derived class.
 But the worst part is that I need to hold di in sync to d files manually, so 
 there is not any advantages over C++'s header files.
dmd will generate the .di files for you with the -Hd switch. But I suggest using interfaces instead, which look ideal for your application.
Oct 24
parent reply Satoshi <satoshi rikarin.org> writes:
On Tuesday, 24 October 2017 at 10:20:43 UTC, Walter Bright wrote:
 On 10/24/2017 1:13 AM, Satoshi wrote:
 But it's quite useless to me.
That's what interfaces are for. Define your View and Button as interfaces. The implementations of interfaces are completely hidden from the derived class.
Can you provide an example?
Oct 24
parent reply Walter Bright <newshound2 digitalmars.com> writes:
On 10/24/2017 3:36 AM, Satoshi wrote:
 Can you provide an example?
I'd start with https://dlang.org/spec/interface.html You'll see the same thing with Windows COM programming, and using interfaces in Java. ---- view.di ---- interface View { void render(); } View createView(); ---- button.di ---- import view; interface Button : View { void simulateClick(); } Button createButton(); ---- closed_src_library.d ---- import view, button; private class LibraryView : View { int hidden_data; void render() { do something with hidden_data } } private class LibraryButton : Button { int hidden_data; void simulateClick() { .... } } View createView() { return new LibraryView(); } View createButton() { return new LibraryButton(); } --- my_extension.d --- import view, button; class ExtendView : View { View base; this() { base = createView(); } void render() { base.render(); ... do my rendering ... } }
Oct 24
parent reply Satoshi <satoshi rikarin.org> writes:
On Tuesday, 24 October 2017 at 20:36:47 UTC, Walter Bright wrote:
 On 10/24/2017 3:36 AM, Satoshi wrote:
 Can you provide an example?
I'd start with https://dlang.org/spec/interface.html You'll see the same thing with Windows COM programming, and using interfaces in Java. ---- view.di ---- interface View { void render(); } View createView(); ---- button.di ---- import view; interface Button : View { void simulateClick(); } Button createButton(); ---- closed_src_library.d ---- import view, button; private class LibraryView : View { int hidden_data; void render() { do something with hidden_data } } private class LibraryButton : Button { int hidden_data; void simulateClick() { .... } } View createView() { return new LibraryView(); } View createButton() { return new LibraryButton(); } --- my_extension.d --- import view, button; class ExtendView : View { View base; this() { base = createView(); } void render() { base.render(); ... do my rendering ... } }
Thanks, but I see there 3 problems: 1. this example enforce users to use composition instead of inheritance when they wants to create custom descendant. 2. multiple dispatch levels. Extending the ExtendView in another lib we get triple dispatch for each method. 3. 1:1 methods mapping is required? or can be there used some sort of aliasing? interface View { void render(); // another hundred methods } class ControlView : View { View parent; void render() { parent.render(); } } class ButtonView : View { ControlView parent; void render() { parent.render(); } // triple dispatch }
Oct 25
parent Walter Bright <newshound2 digitalmars.com> writes:
On 10/25/2017 12:39 AM, Satoshi wrote:
 Thanks, but I see there 3 problems:
 1. this example enforce users to use composition instead of inheritance when 
 they wants to create custom descendant.
I don't see an issue with that.
 2. multiple dispatch levels. Extending the ExtendView in another lib we get 
 triple dispatch for each method.
That's only if you want to hide the interface base class implementation, and only if you want to *also* call the base function. There's single dispatch if overriding, or not overriding, the base function. You can also inherit directly from LibraryView, and there'd be only one dispatch.
Oct 25
prev sibling parent Rainer Schuetze <r.sagitario gmx.de> writes:
On 23.10.2017 22:47, Walter Bright wrote:
 On 10/18/2017 1:56 AM, Satoshi wrote:
 Unable to publish closed source library without workaround and ugly 
 PIMPL design.
Consider this: ----------- file s.d ------------   struct S {     int x;     this(int x) { this.x = x; }     int getX() { return x; }   } ----------- file s.di ------------   struct S {     this(int x);     int getX();   } -------------------------- User code:     import s;     S s = S(3);     writeln(s.getX());
I doubt this reserves enough space on the stack for the copy.
 
 Ta dah! Implementation is hidden, no PIMPL. Of course, inlining of the 
 member functions won't work, but it won't work in C++, either, when this 
 technique is used.
 
 I.e. you can use .di/.d files just like you'd use .h/.cpp in C++. The 
 technique works with classes, too.
Oct 24