www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Matter of style, and cast()

reply "bearophile" <bearophileHUGS lycos.com> writes:
Some small style rules for D user code:

1) All variables and functions arguments should be 
immutable/const (or enum), unless they have to mutate (or there 
is some other problem in Phobos, in the D type system, or in your 
other code).

2) The code should contain as few cast() as possible. [*]

3) Where possible it's better to use foreach() instead of for() 
loops.

4) for/foreach/while loops are not evil, but it's better to use 
map/filter/zip where possible and where performance allows them.

5) Functions/methods should be pure and nothrow where possible.

- - - - - - -

[*] The D type system (and Phobos) should be improved to help 
reduce their frequency. Some of the enhancement requests I have 
written on that:

http://d.puremagic.com/issues/show_bug.cgi?id=10018  (By Lionello 
Lunesu)
http://d.puremagic.com/issues/show_bug.cgi?id=10594
http://d.puremagic.com/issues/show_bug.cgi?id=10615
http://d.puremagic.com/issues/show_bug.cgi?id=10685
http://d.puremagic.com/issues/show_bug.cgi?id=10749
http://d.puremagic.com/issues/show_bug.cgi?id=10751

More not-too-much-hard-to-implement ideas are welcome.

Bye,
bearophile
Aug 05 2013
next sibling parent reply "Bosak" <bosak gmail.com> writes:
On Monday, 5 August 2013 at 13:01:19 UTC, bearophile wrote:
 Some small style rules for D user code:

 1) All variables and functions arguments should be 
 immutable/const (or enum), unless they have to mutate (or there 
 is some other problem in Phobos, in the D type system, or in 
 your other code).

 2) The code should contain as few cast() as possible. [*]

 3) Where possible it's better to use foreach() instead of for() 
 loops.

 4) for/foreach/while loops are not evil, but it's better to use 
 map/filter/zip where possible and where performance allows them.

 5) Functions/methods should be pure and nothrow where possible.

 - - - - - - -

 [*] The D type system (and Phobos) should be improved to help 
 reduce their frequency. Some of the enhancement requests I have 
 written on that:

 http://d.puremagic.com/issues/show_bug.cgi?id=10018  (By 
 Lionello Lunesu)
 http://d.puremagic.com/issues/show_bug.cgi?id=10594
 http://d.puremagic.com/issues/show_bug.cgi?id=10615
 http://d.puremagic.com/issues/show_bug.cgi?id=10685
 http://d.puremagic.com/issues/show_bug.cgi?id=10749
 http://d.puremagic.com/issues/show_bug.cgi?id=10751

 More not-too-much-hard-to-implement ideas are welcome.

 Bye,
 bearophile
Those tips are rather helpful to me as a developer who started learning D just before 1 month. I would really like to see more of those and it will be good to be put on the front page or somewhere visible so newcomers can see it. It will be just some text document full of small tips and conventions that define the D-style. Because D is very flexible language and it offers different types of syntax it will be good to define when to use one or another. For example, when you specify declaration attributes there are 3 different ways of doing it. Tips I want to add about module imports: 6) When declaring imports follow the following convention: 1. Specify the module name | module fancymodule.functions; 2. Import all std modules | import std.stdio; 3. Import all external library modules | import dsfml.system; 4. Import all modules part of your project | import fancymodule.actions; * Have a module named 'all' that only publicly imports all of your library's modules: module fancymodule.all; public { import fancymodule.functions; import fancymodule.actions; } * Others prefer to name that module the same name as the library | module fancymodule.fancymodule; * And others name it 'd' | module fancymodule.d; * Use scoped imports if you want to use only one or two functions from a module only in one 'scoped' place(in a function body etc.) in your module: void fun() { import std.stdio; writeln("fancy!"); } * Use version(unittest) imports to import modules that are used only in your unittests | version(unittest) import std.exception; * Use selective imports when you use only one or two members from a module | import std.stdio : write, writeln; * Use static imports when some of the module members have name conflicts with your module members or can be easily confused with some of your module logic: static import std.math; //or renamed: static import math = std.math; //some scope { auto sin = std.math.sin(std.math.PI); //will be confusing to have: auto sin = sin(PI); //} * For the above cases if you prefer to instead use renamed selective imports: import math = std.math : sine = sin; //some scope { auto sin = sine(math.PI); //PI is not in the selective import list of math so it has to be explicitly accessed. You can think of selective imports as static imports that allow some members not to be specified explicitly(Correct me if I'm wrong) //} * If you have a name conflict, then use static imports(or renamed module-only static imports if the module name is too long) instead of renamed imports. So that others who read your code don't get confused for the new name: static import io = std.stdio; //instead of: import std.stdio : puts = writeln void writeln(T...)(T args) { io.write(args); io.writeln("fancy endline"); }
Aug 05 2013
parent "Bosak" <bosak gmail.com> writes:
I made a markdown gist for the above module import tips:
https://gist.github.com/nikibobi/6156492
Aug 05 2013
prev sibling next sibling parent Joseph Rushton Wakeling <joseph.wakeling webdrake.net> writes:
On 08/05/2013 03:01 PM, bearophile wrote:
 2) The code should contain as few cast() as possible. [*]
What about to!() ... ? Is it possible to gain the performance of cast() while using to!() ... ?
 4) for/foreach/while loops are not evil, but it's better to use map/filter/zip
 where possible and where performance allows them.
Your remarks about performance here are apt. Maps, filters etc. make for very elegant code but as we discussed, there are serious performance issues.
Aug 05 2013
prev sibling next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, Aug 05, 2013 at 03:01:18PM +0200, bearophile wrote:
 Some small style rules for D user code:
[...] Note that in git HEAD, importing of packages as modules has been implemented via package.d: import my.path.module; will now also work with: /my /my/path /my/path/module /my/path/module/package.d /my/path/module/implementation1.d /my/path/module/implementation2.d This means the guideline on import a.b.c.all; will soon be obsolete. T -- Famous last words: I wonder what will happen if I do *this*...
Aug 05 2013
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, August 05, 2013 15:46:13 Joseph Rushton Wakeling wrote:
 On 08/05/2013 03:01 PM, bearophile wrote:
 2) The code should contain as few cast() as possible. [*]
What about to!() ... ? Is it possible to gain the performance of cast() while using to!() ... ?
That depends. In general, no. std.conv.to specifically checks stuff like integer overflow, whereas the built-in casts speficilally don't. So, in general, you'll incur a slight performance penalty when using std.conv.to (though exactly how expensive it is depends on what is being converted to what). For a lot of code though, that performance hit will be so negligible, that it won't matter. It _will_ be there though. - Jonathan M Davis
Aug 05 2013