Computer Science Canada

[WIP] Draft of Style Guidelines

Author:  wtd [ Sun Nov 26, 2006 5:54 pm ]
Post subject:  [WIP] Draft of Style Guidelines

Turing Style Guidelines

Naming Conventions

Constants

Constants should be typed in all-caps, with underscores used to separate words. For instance:

code:
const FILE_PATH = "hello/world"


Unless they have some obvious mathematical meaning, very short names should not be used.

Variables, functions and procedures

Variable, function and procedure names should begin with a lower-case letter. Subsequent words should be separated either using an underscore, or by capitalization.

code:
this_is_ok
thisToo


Whichever style is chosen should be used consistently throughout a program. As with constants, short variable names should be eschewed in favor of expressive variable names.

Variable names should not be prefixed with any kind of indicator as to what type they are. For instance, if one is writing a program which asks the user for a name, the following is considered bad form.

code:
var sInput : string


As is:

code:
var strInput : string


Much better form would be something like:

code:
var usersName : string


Or:

code:
var inputName : string


Functions which return boolean values should indicate that in some way. Consider a function which tests if a string is empty.

Bad:

code:
function empty (s : string) : boolean
   result s = ""
end empty


The word "empty" in the English language can be used as a verb, yet we are not modifying the state of anything. Much more appropriate would be something like:

code:
function is_empty (s : string) : boolean
   result s = ""
end empty


You will note that the argument to the function "is_empty" had a one character name. Previously this was discouraged. However, it should be noted that functions are meant to act as "black boxes" about whose implementation we do not need information.

One of these pieces of information is the name of arguments. Normally this would not be sufficient argument for shortening the name. However, in this case the argument exists in a very small scope, and its purpose is not difficult to determine.

Types

The names of types should begin with a capital letter. All subsequent words should be capitalized.

code:
ThisIsGood
AsIsThis
But_this_is_bad
andThisToo


Comments

First and foremost, comments should not be used to specify facts about a program which can be determined by simply reading the code. Meaningful variable, function and procedure names should alleviate much of the need for comments.

Bad:

code:
var name : string % name to be input by user


Good:

code:
var nameInputByUser : string


When comments are employed, they should take a very specific format.

Comments should always precede the code to which they apply.

Bad:

code:
something () % blah, blah


Good:

code:
% blah, blah
something ()


Comments should always be indented to watch the indentation of the code they pertain to.

Bad:

code:
% blah, blah
   something ()
   
   % yada, yada
 something_else ()


Good:

code:
   % blah, blah
   something ()
   
 % yada, yada
 something_else ()


When commenting in this manner, it is best to separate the code to which the comment pertains from the rest of the code by a single blank line.

Bad:

code:
% blah, blah
something ()
something_else ()


Good:

code:
% blah, blah
something ()

something_else ()


Comments should be well-formed sentences. They should be capitalized correctly, and contain proper spelling and punctuation.

Comments should line-wrap as necessary to avoid the line they are on exceeding 80 columns wide.

Comments should contain a single space between the comment delineator and the beginning of the comment.

Bad:

code:
%foo


Good:

code:
% foo


Indentation

The contents of functions, procedures, record declarations, classes, loops, conditions, case statements, etc. should all be indented.

Indentation may be three spaces, four spaces, one tab, etc. Whatever you choose to use, use it consistently.

Bad:

code:
if someVariable = someOtherVariable then
 foo
 loop
 baz
 end loop
else
    bar
end if


Good:

code:
if someVariable = someOtherVariable then
   foo
   
   loop
      baz
   end loop
else
   bar
end if


Control Structures and Whitespace

It is immensely helpful to separate control structures (conditionals or loops) from surrounding code at the same levek of indentation with a single blank line.

Bad:

code:
foo
if bar then
   baz
end if
loop
   qux
end loop
wooble
ninja


Good:

code:
foo

if bar then
   baz
end if

loop
   qux
end loop

wooble
ninja


Variable Declarations and Whitespace

Multiple variable declarations may appear on adjacent lines. However, they should be separated from surrounding code at the same indentation level by a blank line.

Bad:

code:
var x : int
var y : string
get x
get y
put y ..
put x


Good:

code:
var x : int
var y : string

get x
get y
put y ..
put x


Scope

Variables should be scoped as minimally as possible. If a variable is only used within a conditional structure or loop, then it should be scoped to that structure.

Bad:

code:
var x : int

if true then
   get x
   put x
end if


Good:

code:
if true then
   var x : int

   get x
   put x
end if


Miscellaneous Whitespace Issues

In a variable declaration, whitespace should always separate commas, colons and initialization.

Bad:

code:
var x,y:int


code:
var x:int:=0


Good:

code:
var x, y : int


code:
var x : int := 0


Operators should benefit from whitespace. Leaving whitespace out will not make your code magically faster.

Bad:

code:
x-y+z*4


Good:

code:
x - y + z * 4


Do not place whitespace directly inside parentheses.

Bad:

code:
( x - y + z ) * 4


Good:

code:
(x - y + z) * 4


Do use blank lines to separate functions, procedures, records and processes.

Bad:

code:
type A :
   record
      b : string
   end record
function foo : string
   result "foo"
end foo
procedure bar
   baz
end bar


Good:

code:
type A :
   record
      b : string
   end record

function foo : string
   result "foo"
end foo

procedure bar
   baz
end bar


The same rules that hold for variable declarations apply for function, procedure and process parameter lists.

Bad:

code:
function foo (bar:string) : string


Good:

code:
function foo (bar : string) : string


Similarly, the colon leading the return type in a function should be surrounded by whitespace.

Bad:

code:
function foo (bar : string):string


Good:

code:
function foo (bar : string) : string


In a call of a function, procedure or process, arguments should be separated by whitespace. Again, leaving out the whitespace does nothing to make code better, and does make it harder to read.

Bad:

code:
foo (42,27)


Good:

code:
foo (42, 27)


Code Organization

Turing, unlike many other statically, manifestly typed programming languages, does not have a designated entry point.

Code that can be executed is, in order, as it appears in the source code. This means such things can be interspersed with type, function, procedure and process definitions.

Despite the fact that this can be done, does not mean it should.

Bad:

code:
var userInputString : string

function getString : string
   var s : string
   
   get s ..
   result s
end getString

userInputString := getString

function reverseString (stringToReverse : string) : string
   var outputString : string := ""
   
   for decreasing characterIndex : length (stringToReverse) .. 1
      outputString += stringToReverse (characterIndex)
   end for
   
   result outputString
end reverseString

put reverseString (userInputString)


Good:

code:
function getString : string
   var s : string
   
   get s ..
   result s
end getString

function reverseString (stringToReverse : string) : string
   var outputString : string := ""
   
   for decreasing characterIndex : length (stringToReverse) .. 1
      outputString += stringToReverse (characterIndex)
   end for
   
   result outputString
end reverseString

var userInputString : string

userInputString := getString
put reverseString (userInputString)


Additionally, so that they are available to the rest of the code, type declarations should appear at the top of your code.

Functions vs. Procedures: Two Enter. One Leaves.

Procedures are probably what every Turing programmer is first introduced to in terms of organizing executable code. As it happens, they are also one of the first things that should, for the most part, be left behind.

Procedures typically act on some set of global variables.

code:
var foo : int := 0

procedure bar
   foo += 1
end bar


You may note that this directly contradicts the style promoted in the Code Organization section. There was good reason for the style advocated there. A variable declared after a procedure is not visible to that procedure's inner workings.

The following would result in an error.

code:
procedure bar
   foo += 1
end bar

var foo : int := 0


The problem with procedures is that they explicitly refer to some set of variables outside their own scope. They are tied down to using just those variables. They are also dependent on those variables for their internal behavior.

A function's implementation, on the other hand, is separate from its external environment. It communicates with the outside world via the arguments passed into it, and the value it returns.

Whenever possible, seek a solution which uses functions rather than procedures.

Conditionals and Redundancy

If, in the course of writing a conditional, you find that multiple branches have the exact same result, then you almost certainly should use "or".

Bad:

code:
if foo = "bar" then
   result 42
elsif foo = "baz" then
   result 42
else
   result 27
end if


Good:

code:
if foo = "bar" or foo = "baz" then
   result 42
else
   result 27
end if


It is bad practice to use multiple conditionals when the results are exclusive. That is, if only one of them will actually run, you should use a single conditional with multiple branches.

Bad:

code:
if foo = "bar" then
   bar := 42
end if

if foo = "baz" then
   bar := 27
end if


Good:

code:
if foo = "bar" then
   bar := 42
elsif foo = "baz" then
   bar := 27
end if


Conditionals and Control Flow

It is bad practice to use a conditional to break control flow and skip around the remainder of the function or procedure, if the same can be expressed as a conditional with multiple branches.

This practice technically works fine, but makes it more tedious to reason about the control flow, and yields no significant gain.

Bad:

code:
function foo (bar : int) : int
   if bar < 27 then
      result 3
   end if

   result 2
end if


Good:

code:
function foo (bar : int) : int
   if bar < 27 then
      result 3
   else
      result 2
   end if
end if


Please note that this practice may be used within a loop, to implement short-circuiting behavior.

Author:  Clayton [ Thu Nov 30, 2006 10:10 pm ]
Post subject: 

Good stuff wtd, far too many a time have I looked at code and shied away simply because it was so hard to read due to unconventional conventions. Perhaps this should be included in the Turing Walkthrough?

Author:  Cervantes [ Fri Dec 01, 2006 5:48 pm ]
Post subject: 

Freakman wrote:
Perhaps this should be included in the <a href="http://www.compsci.ca/v2/viewtopic.php?t=8808">Turing Walkthrough</a>?


Excellent idea. It's been done:
Walkthrough wrote:

This walkthrough is like a book, except it's pieced together from articles written by different people. As a result, writing and teaching styles will change; what's more, naming conventions may change from one article to the next. This is regrettable. The best thing you can do is to follow the conventions, yourself, even if you are from time to time reading some code that doesn't follow these conventions. So, while working through this walkthrough, keep the Style Guidelines handy and refer to it often.


Terrific job, wtd. This was much needed. Smile

Author:  uberwalla [ Fri Dec 01, 2006 6:45 pm ]
Post subject: 

im sorry if it was just said lol but i read this 5 min ago and randomly had a question. why is it so bad to have the first letter of a proc capital or w.e?

Author:  wtd [ Fri Dec 01, 2006 6:57 pm ]
Post subject: 

Consistent naming conventions make code more readable. But consistency alone doesn't aid in that. Using naming to differentiate names in a program is important.

Author:  uberwalla [ Fri Dec 01, 2006 7:13 pm ]
Post subject: 

ok i get it Very Happy
it was a little weird at first of why it mattered but now i see Cool

thx

Author:  ericfourfour [ Sat Dec 02, 2006 2:23 am ]
Post subject: 

I see where you are coming from uberwalla. My teacher (most likely ignorant of naming conventions) tells us to write our methods with capitals. However, this is the same teacher who recommended making every variable public and assigning their values in the main method. The way you are taught it is not always the correct way. It may however, be the easier way to teach it. This is one thing you have to look out for.

Author:  wtd [ Mon Dec 04, 2006 1:39 pm ]
Post subject: 

As these guidelines are updated, I strongly encourage others to provide constructive feedback. I will not feel comfortable removing the "Draft" bit until I get that feedback, and approval of the contents.

Author:  Clayton [ Mon Dec 04, 2006 3:49 pm ]
Post subject: 

So far so good wtd, the only thing I have to say is:

wtd wrote:

code:

type A : record
    b : string
end record



is not proper turing style, it should instead be:

code:

type A :
    record
        b : string
    end record


other than that, no complaints Very Happy

Author:  wtd [ Mon Dec 04, 2006 4:21 pm ]
Post subject: 

Good point. My goal is at least partly to create guidelines that don't force students to fight the editor's built-in formatting style.

Author:  [Gandalf] [ Mon Dec 04, 2006 6:17 pm ]
Post subject:  Re: [WIP] Draft of Style Guidelines

Well, if you insist...
wtd wrote:
Comments should always precede the code to which they apply.

Bad:
code:
something () % blah, blah


Good:
code:
% blah, blah
something ()

This is something I firmly disagree with. No reason in particular, but keeping things in as few lines as possible while still being neat is something I try to follow. It also makes it easier to associate the comment with the code, at least for me. Any particular reason you included this? Is it all that important?

Otherwise, seems quite agreeable. Smile

Author:  wtd [ Mon Dec 04, 2006 7:31 pm ]
Post subject: 

Comments should explain only things which the code does not make apparent to those who know the language. Things like details of algorithms, especially those associated with specialty fields.

Good comments might also explain why a programmer felt a certain variable or function was important.

As such, I believe it important that the reader go into reading the actual code with some understanding of what the purpose of it is.

Author:  ericfourfour [ Mon Dec 04, 2006 7:47 pm ]
Post subject: 

Personally, I prefer the way wtd presented the comments but either the line before or the line of the code is acceptable.

Maybe the "/**/" comment can be added into the tutorial.

Author:  wtd [ Thu Dec 07, 2006 2:16 am ]
Post subject: 

A question, if I may.

Should naming conventions be simplified for variables, functions and the like? Upon further consideration, Turing style leads one to already include a lot of whitespace, and I fear that underscores might get lost in all of that. As a result, despite a personal preference for that type of name, I am beginning to suspect that camel-case might be the appropriate single guideline for naming such things.

Author:  zylum [ Thu Dec 07, 2006 2:58 am ]
Post subject: 

i always use camel case for variable names. i only use underscores for constants where the letters are allcaps and i dont really have any other choice. for me its just as easy to read and i find it more aesthetically pleasing than using underscores.

Author:  Clayton [ Thu Dec 07, 2006 12:13 pm ]
Post subject: 

I, on the other hand, find using this_kind_of name easier to read as it leaves some space in between seperate words (thereby making it easier to read), but, to each his own I suppose.

Author:  md [ Thu Dec 07, 2006 2:19 pm ]
Post subject: 

I use underscores for variables, and it makes things a lot easier to read. I use CamelCase for functions though, in part because they then stand out from variables, and in part because of habit.

Author:  TokenHerbz [ Fri Dec 08, 2006 7:23 am ]
Post subject: 

i use the underscores only in parameter variables...

as for comments, i do it on the same line as the code, with the expetion of a few things which i have to fully type out... like crazy collition crap.

code:

proc setUnitHealth (unitHealth_: string)  %% A comment like this for here
    unitHealth := unitHealth_
end setUnitHeath


preferences i suppose.

Author:  Clayton [ Fri Dec 08, 2006 9:53 am ]
Post subject: 

I find that if you need a comment that will still fit on the line of code that it is used for, you don't need it, becuase the code should be fairly well explained that it doesn't need that short of a comment. This of course is different when it comes to crazy algorithms and such, but then you just comment on the line above.

@TokenHerbz : thats "collision", you keep spelling it wrong.

Author:  Cervantes [ Fri Dec 08, 2006 10:16 am ]
Post subject: 

TokenHerbz wrote:
i use the underscores only in parameter variables...

I think this is a bad distinction to make. Parameters are so much like regular variables that I think they should have the same naming convention.

Also, your style uses both CamelCase and underscores. What's the purpose of the underscore at the end of the parameter name? Is it just to stand out and say, "I am a parameter"? Ideally, you should only be using parameters in your subroutines, so there should be no need for your parameters to stand out, since they would all stand out equally.

Author:  Clayton [ Fri Dec 08, 2006 12:30 pm ]
Post subject: 

I think he means whenever he is using a class or something and he has values that he wants to have the "same" name so he adds the underscore to the end of the name to distinguish the parameters and the class variables ie:

Turing:

class Foo
    export bar

    var baz, floo : int
   
    procedure bar (baz_, floo_ : int)
        baz := baz_
        floo := floo_
    end bar
end Foo


see? Wink

NOTE: I have seen you do this very thing in your classes tutorials Cervantes, just to show you what I mean.

Author:  Cervantes [ Fri Dec 08, 2006 2:14 pm ]
Post subject: 

Ah! Yeah, I could dig that.

Author:  wtd [ Fri Dec 08, 2006 2:26 pm ]
Post subject: 

How about "newBazValue" or "initialBazValue"?

Author:  Clayton [ Fri Dec 08, 2006 4:24 pm ]
Post subject: 

Yes, I suppose that could work too, but the underscore after parameters in classes, and only classes, is pretty much automatic for me, and possibly others as well. For me it keeps things organized, and I can easily tell what is what at first glance. Although, I also see what you mean wtd. I suppose either way works, just keep it constant.

Author:  [Gandalf] [ Sat Dec 09, 2006 12:26 am ]
Post subject: 

This is why I like the 'this' keyword, it makes the distinction between two variables with the same name much more obvious.

About the commenting, I see what you mean wtd, but I wouldn't go so far as saying this is always the case. Comments aren't always used to explain the code in question, they can also contain things like previously tested arguments, no?

Author:  wtd [ Sat Dec 09, 2006 11:00 am ]
Post subject: 

You're talking about commenting out test code?

Author:  Clayton [ Sat Dec 09, 2006 11:02 am ]
Post subject: 

Actually I think he is talking more about commenting about stuff that was tried, but failed, or is a work in progress (correct me if I'm wrong).

Author:  wtd [ Sat Dec 09, 2006 11:31 am ]
Post subject: 

I see nothing wrong with that, but it should be accompanied by a well-formed comment indicating that.

Author:  iamcow [ Mon Dec 18, 2006 9:14 pm ]
Post subject: 

I would like to add to the style guidelines:

Rand.Int is preferred over randint

A function that returns a value is preferred over a procedure that changes the parameters that it is given.

And from a very practical point of view:

scenario: drawing random circles

code:

loop
var x,y,xrad,yrad, cred,cgreen,cblue:=0
randint (x,0,maxx)
randint (y,0,maxy)
randint (xrad,1,200)
randint (yrad,1,200)
randint (cred,1,1000)
randint (cgreen,1,1000)
randint (cblue,1,1000)
drawfilloval (x,y,xrad,yrad,RGB.AddColor (cred/1000,cgreen/1000,cblue/1000))
end loop


Now with Rand.Int:

code:

loop
    drawfilloval (Rand.Int (0, maxx), Rand.Int (0, maxy), Rand.Int (5, 200), Rand.Int (5, 200), RGB.AddColor (Rand.Real, Rand.Real, Rand.Real))
end loop


we've both decreased the lines and the number of global variables

Also, efficiency runtime - wise

code:

for i : 1 .. 500
    var x, y, xrad, yrad, cred, cgreen, cblue := 0
    randint (x, 0, maxx)
    randint (y, 0, maxy)
    randint (xrad, 1, 200)
    randint (yrad, 1, 200)
    randint (cred, 1, 1000)
    randint (cgreen, 1, 1000)
    randint (cblue, 1, 1000)
    drawfilloval (x, y, xrad, yrad, RGB.AddColor (cred / 1000, cgreen / 1000, cblue / 1000))
end for
put Time.Elapsed


code:

for i: 1..500
    drawfilloval (Rand.Int (0, maxx), Rand.Int (0, maxy), Rand.Int (5, 200), Rand.Int (5, 200), RGB.AddColor (Rand.Real, Rand.Real, Rand.Real))
end for
put Time.Elapsed


After running both one concludes also that Rand.Int is faster. Perhaps not directly, but in the structure of the program when Rand.Int is used

Author:  ericfourfour [ Mon Dec 18, 2006 11:09 pm ]
Post subject: 

iamcow that is a common thing seen in many early Turing programs. Maybe wtd could add in a section about the downside of procedures that use var parameters.

Author:  NeonJack [ Mon Jun 25, 2018 12:04 pm ]
Post subject:  RE:[WIP] Draft of Style Guidelines

I use m_ for class instance variables so in the example

class Foo
export bar

var baz, floo : int

procedure bar (baz_, floo_ : int)
baz := baz_
floo := floo_
end bar
end Foo

this would be

class Foo
export bar

var m_baz, m_floo : int

procedure bar (baz, floo : int)
m_baz := baz
m_floo := floo
end bar
end Foo

I think trailing underscores look messy - C# has leading underscores which look equally bad IMHO.

Additionally I think comments are very important. Most professional programmers don't like them and won't put them in: they say you have to maintain them and they just add to the burden of getting the job done. I agree a comment should not describe the code it is annotating but a comment is needed for explaining the business logic - if you need to explain your class or method or procedure or function or, indeed, whole program to someone else, you need to comment it, so that vocal explanation is not required.


: