View previous topic :: View next topic |
Author |
Message |
sean
Joined: 24 Jun 2004 Posts: 609 Location: Bay Area, CA
|
Posted: Thu Sep 09, 2004 11:49 am Post subject: Style and standards |
|
|
Per qbert's request, how about we hammer out some style and interface guidelines. Standard D syntax style is defined here:
http://www.digitalmars.com/d/dstyle.html
Basic rule is to always use mixed case, verbs (functions) have a leading lowercase letter while nouns (types) have a leading uppercase letter. Constants are in all caps. The guide leaves variable names open, and at the risk of inviting argument I suggest there be some qualifier for class member variables (and possibly a different one for static member variables). Some common prefixes are "m_" and "sm_" or "d_" and "s_" for standard and static members, respectively.
I would also suggest that all class variables be made non-public and that properties be used if direct variable manipulation is required. A suggested class definition layout would be to have all public members at the top, with members grouped by type: constructors, manipulators, etc.
All imports should be private, and anything declarations or functions not having to do with a module's external interface should be private as well.
I can't think of anything having to do with syntax offhand. Suggestions? And what about interface guidelines? |
|
Back to top |
|
|
teqdruid
Joined: 11 May 2004 Posts: 390 Location: UMD
|
Posted: Thu Sep 09, 2004 1:03 pm Post subject: Member variables |
|
|
I'm not a fan of underscores (_) in variables. If we want prefixes to member variables, I'd prefer something like myVariable. I think it looks nicer, and it's easier to type (at least for me). |
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Thu Sep 09, 2004 1:45 pm Post subject: |
|
|
I think we're mostly in agreement on using the d coding standard, and I'm for that.
As for the limited hungarian notation you suggested, that makes sense too. Personally, I'm not for excessive use of hungarian notation. Using prefixies for member and static are helpful, but I'm not sure if there's any value to be realized in having those in the spec. I'm welcome to be wrong of course.
The only other thing I can think of is requiring, at a minimum, documentation either in the code or submitted with documentation that can be added to a user's guide and/or library reference. Having this in the code is ideal, and may be the way to go, but we may have to settle on a documentation engine to back if that's to become useful.
What about tabification? 2 spaces, 4 spaces, /t as a standard? Or no standard here at all (hey, we can convert it later if we want to, right)?
Also D, exposes several different ways to declare public/private/protected: using brackets, a colon or no decoration at all (ala java). Should this be in the spec as well?
Anyway, here's where we are:
Code: | // example module for coding standards
private import std.stdio;
// simple class documentation here
class ExampleClass{
// simple method documentation here
public this();
public int getValue();
public void setValue(int); // should accessors/mutators use this syntax?
private int m_value;
private static int ms_value;
private void doSomething();
protected abstract void handleSomething();
}
|
_________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
sean
Joined: 24 Jun 2004 Posts: 609 Location: Bay Area, CA
|
Posted: Thu Sep 09, 2004 4:29 pm Post subject: |
|
|
pragma wrote: |
As for the limited hungarian notation you suggested, that makes sense too. Personally, I'm not for excessive use of hungarian notation. Using prefixies for member and static are helpful, but I'm not sure if there's any value to be realized in having those in the spec. I'm welcome to be wrong of course. |
I'd debated about that as well, but finally decided to include it because it's suggested in "Large Scale C++ Software Design" as an aid to maintainability. But I'm pretty indifferent on this score as it's implementation-level stuff.
Quote: |
What about tabification? 2 spaces, 4 spaces, /t as a standard? Or no standard here at all (hey, we can convert it later if we want to, right)? |
Good question. I prefer spaces over tabs as there's less of a chance of formatting problems, but beyond that I don't really care. I personally use 4 spaces though.
Quote: |
Also D, exposes several different ways to declare public/private/protected: using brackets, a colon or no decoration at all (ala java). Should this be in the spec as well? |
I don't think it's necessary, though I would say a good rule of thumb is to use the method that requires the least typing
As for accessors/mutators, I do it this way:
Code: |
class C
{
public:
int val() { return m_val; }
void val( int v ) { m_val = v; }
private:
int m_val;
}
|
ie. I don't use the get/set notation. To me, this seems to fit fairly well with the concept of properties anyway, as I prefer "c.val" to "c.getVal."
Sean |
|
Back to top |
|
|
regan
Joined: 21 Jun 2004 Posts: 23
|
Posted: Thu Sep 09, 2004 7:24 pm Post subject: Re: Style and standards |
|
|
sean wrote: |
I would also suggest that all class variables be made non-public and that properties be used if direct variable manipulation is required.
|
Why?
sean wrote: |
A suggested class definition layout would be to have all public members at the top, with members grouped by type: constructors, manipulators, etc.
|
I like it, something like:
class A {
//public: this is the default, so, do we need this line?
//constructors
this();
~this();
//manipulators?
opApply();
//normal members
fooBar();
private:
int m_val;
} |
|
Back to top |
|
|
sean
Joined: 24 Jun 2004 Posts: 609 Location: Bay Area, CA
|
Posted: Thu Sep 09, 2004 9:40 pm Post subject: Re: Style and standards |
|
|
regan wrote: | sean wrote: |
I would also suggest that all class variables be made non-public and that properties be used if direct variable manipulation is required.
|
Why?
|
Robustness, mostly. While a property behaves syntactically the same as a public variable (so in D you're really not stuck once you've made the choice), you need to go through a member to check class invariant rules (AFAIK), use DBC, etc. And as much as I'm indifferent to traditional OO programming methods, using properties just "feels right" in this case. |
|
Back to top |
|
|
larsivi Site Admin
Joined: 27 Mar 2004 Posts: 453 Location: Trondheim, Norway
|
Posted: Fri Sep 10, 2004 1:07 am Post subject: |
|
|
pragma wrote: | What about tabification? 2 spaces, 4 spaces, /t as a standard? Or no standard here at all (hey, we can convert it later if we want to, right)?
|
I want 2 spaces (at least no tabs!).
I agree with most of the other topics. |
|
Back to top |
|
|
andy
Joined: 15 Mar 2004 Posts: 71
|
Posted: Fri Sep 10, 2004 7:23 am Post subject: |
|
|
larsivi wrote: | I want 2 spaces (at least no tabs!). | This means war.
Personally, I don't think things like spacing and private attributes are all that important. They don't have any affect at all on code which is using the library, so it's not really all that important if they're inconsistent between modules.
(which reminds me: at one point, I was rolling around the idea of writing a refactoring tool for D using that ANTLR parser I started...)
sean wrote: | Robustness, mostly. While a property behaves syntactically the same as a public variable (so in D you're really not stuck once you've made the choice), you need to go through a member to check class invariant rules (AFAIK), use DBC, etc. And as much as I'm indifferent to traditional OO programming methods, using properties just "feels right" in this case. | Using properties instead of public fields is probably the way to go in the end because it offers the possibility of binary compatibility between library versions if Ares should be linked as a DLL. _________________ "Complacency is a far more dangerous attitude than outrage." - Naomi Littlebear |
|
Back to top |
|
|
larsivi Site Admin
Joined: 27 Mar 2004 Posts: 453 Location: Trondheim, Norway
|
Posted: Fri Sep 10, 2004 11:24 am Post subject: |
|
|
andy wrote: | larsivi wrote: | I want 2 spaces (at least no tabs!). | This means war.
Personally, I don't think things like spacing and private attributes are all that important. They don't have any affect at all on code which is using the library, so it's not really all that important if they're inconsistent between modules.
|
It's not really important of course, I can always change the 'offending' files to my liking. I just know that the source of todays Phobos is really chaotic in my VIM-setup, making it nearly unreadable.
Oh, and I'm all for properties instead of fields. |
|
Back to top |
|
|
regan
Joined: 21 Jun 2004 Posts: 23
|
Posted: Sun Sep 12, 2004 4:12 pm Post subject: |
|
|
andy wrote: | larsivi wrote: | I want 2 spaces (at least no tabs!). | This means war.
Personally, I don't think things like spacing and private attributes are all that important. They don't have any affect at all on code which is using the library, so it's not really all that important if they're inconsistent between modules.
(which reminds me: at one point, I was rolling around the idea of writing a refactoring tool for D using that ANTLR parser I started...)
|
I've always thought using tabs is best. 'most' editors will display tabs as any width of spaces you want, further, writing an app to reformat it to something else is simplest if they're all tabs, especially if you do what I do below..
I use spaces in certain places eg:
(a . is a space, a \ a tab)
enum.BOB.{
\ONE...=.1,
\TWO...=.2,
\THREE.=.3,
\FOUR..=.4,
}
in other words I use tabs where I simply mean to indent, and spaces to align things (which only works if you have fixed width fonts)
sean wrote: | Robustness, mostly. While a property behaves syntactically the same as a public variable (so in D you're really not stuck once you've made the choice), you need to go through a member to check class invariant rules (AFAIK), use DBC, etc.
|
What about in this case (a constant read-only variable - not using a get property)
class A {
const int b;
this()
{
b = 2;
}
}
void main()
{
A a = new A();
printf("?d",a.b);
}
granted, the above not only fails to compile but it crashes dmd (I'm posting a bug report now) and you can also do it like this..
class A {
enum {
b = 2
}
}
Don't get me wrong I'm, I think I agree with you, I just have to play 'devils advocate' in order to explore all the possibilities.
sean wrote: |
And as much as I'm indifferent to traditional OO programming methods, using properties just "feels right" in this case. |
I agree.
andy wrote: |
Using properties instead of public fields is probably the way to go in the end because it offers the possibility of binary compatibility between library versions if Ares should be linked as a DLL. |
I don't understand, if you have time to educate me, please explain.. |
|
Back to top |
|
|
larsivi Site Admin
Joined: 27 Mar 2004 Posts: 453 Location: Trondheim, Norway
|
Posted: Tue Sep 14, 2004 3:03 am Post subject: Code style draft suggestion |
|
|
I've made a codestyle draft (It's more or less copied from Coin (www.coin3d.org), but grafted onto D.
I try to use this in my own projects and find it clean and nice.
The draft don't discuss templates, mixins or documentation. There are possibly other things that should be mentioned also.
Code: |
Coding guidelines for Ares
First draft by Lars Ivar Igesund
Blatant copy from Coin (www.coin3d.org) where applicable to D
This revision: larsivi 20040914
0) If the code you write is not 100? complete;
- Leave a "FIXME" message if you believe the code is fairly
correct, but you are unsure and have not checked the correctness
yet, or if there are known deficiencies. This includes cases
like ambiguities in documentation that will require some
investigation to resolve, error-cases or places where one should
be more robust that haven't been fixed yet due to time
constraints, etc.
- Insert "AresStub();" statements if the code lacks certain
important functionality, so situations where unimplemented
features are used will be detected at run-time.
- Leave FIXMEs if you see obvious cases for performance
improvements which should be explored.
A FIXME-message must include a description of the problem, who
wrote the message, and when. Please include whatever you have
already found out about the problem in the FIXME text, so your
next of kin don't have to painstakingly re-do all the thought-work
you already have laid down. Example:
// FIXME: should be possible to create a good standard library.
// 20040914 larsivi.
or
// FIXME: this action seems completely bogus, as if something fails,
// all bets are off and we should simply terminate the import
// operation. (flushInput() continues to read and scans for a
// closing brace). Run with this code disabled for a while and axe
// it if nothing bad seems to come frome it. 20020531 mortene.
//
// if (!ret && flush) SoBase::flushInput(in);
This goes also for other keywords in comments (see below). It
makes it much easier when others try to fix code that doesn't
work. You will know who to ask if you don't understand the
problem, and the date could indicate among other things the
urgency of the problem.
1) If blocks of code are commented out (obsoleted) to make place for
new code, or because it has become superfluous, one should mark it
like the example below if it is a large block of code, if the new
code is very experimental, or if the new code is obfuscated
(e.g. because of optimizations).
version (None) { // OBSOLETE: <textual description>. <yyyymmdd userid>.
...old code...
}
else {// short description of new code
...new code...
}
See also the next rule.
2) Under *no* circumstances should developers leave any code which
has been commented out with the language constructs "// ..." or
"/* ... */" in anything you check into SVN, at least not without
commenting _why_ the code is still present.
It's often very time-consuming and just a bloody pain in the ass
and a waste of resources trying to figure out why commented-out
code is still present in a source file (is it new code which
*might* fix a bug, but which haven't been tested yet? is it old
code found to be buggy which have been removed? is it commented
out because it is a new feature which is yet to be completed? etc
etc etc).
Programmers who continues to sin against this rule after having
this pointed out to them should be taken out behind the barn to be
shot.
3) During debugging, write debug code like this:
debug {
// FIXME: Should we use some sort of standardized formatting for
// these cases? 20040914 larsivi
writefln(...);
}
If there is a chance that the debug information might be useful
later, keep it as is. If not, remove it before making a patch or
checking in.
If there are many debug statements in the same category, use a
debug identifier for that category (debug (identifier) )
UPDATE 2001-11-21 larsa: Actually, we now prefer that you use this
define as an if-condition instead, because of the cleaner look the
source code gets when it is not littered with preprocessing
directives. For permanent debugging code, write therefore source
code like this instead:
4) Do not under any circumstances use printf() / fprintf() / puts()
or related functions for output. writefln do the job perfectly.
5) Don't use any variablename, classname, define, functionname or any
other identifier that starts with double underscores. That namespace is
per the D specs fully reserved for the compiler
implementation.
6) Prefix with the "this" keyword for dynamic functions and member
variables, prefix with the classname for static functions and
variables.
The rationale for doing this extra typing is that it makes the
code immensely more easily readable when skimming it. If the
prefixes are missing, one has often to scroll back and forth to
find out if variables are input arguments to methods or stack
variables -- with "this." or "ClassName." prefixes there is
immediately no doubt where the variable comes from.
7) Expose all class fields using properties, hiding the fields themselves
in "private" blocks. This is considered good OOP practice in addition
to the fact that it might hinder binary compatibility problems in the
future.
8) Code formatting rules. The default is to use Kernighan and Ritchie style.
a) Braces: keep opening braces on the end of the line, and closing
braces at the start. Like this:
if (...) {
...
}
And not like this:
if (...)
{
...
}
The exception from this rule is functions, which should have the
opening brace on the next line.
b) Indentation: use 2 spaces extra for each level of nesting.
*Never* use tabulator characters (ie ASCII code 0x09), as
editors expands them differently. The code indentation will
therefore more often than not look like crap with the default
settings of any other editor than the one you happen to be using
yourself.
c) Spacing: use 1 space after commas and around operators (like +,
-, *, /, ==, &&, etc), but not after or before parentheses.
Like this:
if (val) { i = sqrt(a) * func(b, c); }
Not like this:
if ( val ) { i=sqrt(a)*func(b,c); }
d) Naming: class names should be uppercased for each word, function
names for each word except the first one, variable names should
be all lowercase, and defines, enums and constants should be all
uppercase. Example:
class MathClass {
float
calculateValue(float in)
{
const float FACTOR = 2.78;
...
...
}
FIXME: The note below make perfectly sense in C/C++, but possibly
not in all cases for D. I still vote for the below choice, though.
20040914 larsivi
NOTE: do *not* use Hungarian-style naming, ie prefixing names
with indicators about type. So don't for instance name classes
with a leading "c", or member variables with an "m", or integers
with an "i" and so on and so on. You're better off in the
readability-department by using the "this" prefix, as explained
above, and then the Hungarian naming style just obfuscates the
code.
e) Pointer types and references: use a space on each side of the
'*' and '&' operators, like this
SoNode * mynode = NULL;
not like this
SoNode *mynode = NULL;
because it makes it look like the '*' "belongs" to the variable
name (which of course is wrong -- it's part of the type), and
not like this either
SoNode* mynode = NULL;
because it's ugly and unusual. So for consistency, _please_
stick with the space-on-both-sides convention in Ares code.
f) Use
return x;
and not
return (x);
(Since "return" is not a function with arguments, the latter
just looks plain wrong.)
g) For the access modifiers "private", "protected" and "public" within
a class, always use ':'. There are more than enough braces to go
around in there anyway.
For the same modifiers outside a class, use blocks if they affect more
than one member. This should apply to all other modifiers that can
group using braces. The rationale is that members can be grouped
together with other similarly modified members, making hungarian
notation less necessary, e.g.:
static {
void foo();
int bar(int joe);
}
h) Fields should not be lined up neither on identifier nor '=' as the
addition of new fields might ruin the setup and make more work than
necessary. One space should be used everywhere, e.g.:
int var = 3;
|
|
|
Back to top |
|
|
pragma
Joined: 28 May 2004 Posts: 607 Location: Washington, DC
|
Posted: Tue Sep 14, 2004 8:45 am Post subject: |
|
|
Thanks Larsivi! That's a very solid start, and probably good enough to start coding now. Provided, of course, it meets with everyone's approval.
One tiny nitpick: it mentions puttnig the opening brace on the first line for everything except functions and methods. Is this correct? Why not just make everything consistent by having functions open on the first line as well?
I'd assume that try/catch would use this form:
Code: |
try{
/*...*/
}
catch(Exception e){
/*...*/
}
finally{
/*...*/
}
|
And templates would use something like this:
Code: |
template foobar(T1, T2, T3){
void foobar(T1 one, T2 two, T3 three){
/*...*/
}
}
class Foobar(T1, T2, T3){
/*...*/
}
|
Outside of that, I'd say this is the way to go. It covers all the bases that have been discussed so far. _________________ -- !Eric.t.Anderton at gmail |
|
Back to top |
|
|
larsivi Site Admin
Joined: 27 Mar 2004 Posts: 453 Location: Trondheim, Norway
|
Posted: Tue Sep 14, 2004 12:41 pm Post subject: |
|
|
pragma wrote: | One tiny nitpick: it mentions puttnig the opening brace on the first line for everything except functions and methods. Is this correct? Why not just make everything consistent by having functions open on the first line as well?
|
Well, it is consistent (sortof). Functions are units of code (just like classes, structs and templates, see below) that can be used elsewhere, whereas the other stuff is control structures and just part of other code.
pragma wrote: |
I'd assume that try/catch would use this form:
Code: |
try{
/*...*/
}
catch(Exception e){
/*...*/
}
finally{
/*...*/
}
|
|
Added to my file.
Templates and classes like below.
Code: |
template foobar(T1, T2, T3)
{
void foobar(T1 one, T2 two, T3 three)
{
/*...*/
}
}
class Foobar(T1, T2, T3)
{
/*...*/
}
class Foobar
{
}
struct Foobar
{
}
// Inherited classes
class Foo
: Bar, Iface
{
}
|
I've uploaded my file to
http://www.igesund.net/larsivar/ares/codestyle
In the future, it should be present in the SVN repository. |
|
Back to top |
|
|
regan
Joined: 21 Jun 2004 Posts: 23
|
Posted: Tue Sep 14, 2004 4:01 pm Post subject: Re: Code style draft suggestion |
|
|
larsivi wrote: | I've made a codestyle draft (It's more or less copied from Coin (www.coin3d.org), but grafted onto D.
I try to use this in my own projects and find it clean and nice.
The draft don't discuss templates, mixins or documentation. There are possibly other things that should be mentioned also.
|
Great work!
Code: |
UPDATE 2001-11-21 larsa: Actually, we now prefer that you use this
define as an if-condition instead, because of the cleaner look the
source code gets when it is not littered with preprocessing
directives. For permanent debugging code, write therefore source
code like this instead:
|
Is this part correct? we don't have pre-processor directives? debugging should be done with
debug (ident) {
}
right?
Code: |
e) Pointer types and references: use a space on each side of the
'*' and '&' operators, like this
SoNode * mynode = NULL;
not like this
SoNode *mynode = NULL;
because it makes it look like the '*' "belongs" to the variable
name (which of course is wrong -- it's part of the type), and
not like this either
SoNode* mynode = NULL;
because it's ugly and unusual. So for consistency, _please_
stick with the space-on-both-sides convention in Ares code.
|
I thought D style was:
SoNode* mynode = NULL;
Regan |
|
Back to top |
|
|
jcc7
Joined: 22 Feb 2004 Posts: 657 Location: Muskogee, OK, USA
|
Posted: Tue Sep 14, 2004 5:32 pm Post subject: Re: Code style draft suggestion |
|
|
regan wrote: | I thought D style was:
SoNode* mynode = NULL;
Regan | I agree. Better yet: Code: | SoNode* mynode = null; |
|
|
Back to top |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|