Basic Library Version: 9

GDL Style Guide 1.0

Index

1. Introduction

This document contains the GDL coding standard of Graphisoft, which mainly sets the formal requirements for writing source code. It also describes a few rules and recommendations for the content. You have to obey these rules; by default every declarative or imperative sentence is a rule, except where 'recommendation' (or avoidable, optional, etc.) is explicitly stated.

This document was created to establish a common format of GDL scripting. Since the GDL language is insensitive of the character case and much of the word and line spacing, lots of coding practices and standards exist. This gets intolerable, when such practices meet in the same project or organization. The following sections describe the Graphisoft company-standard, which remains purely a recommendation for non-Graphisoft related developers. The supposed format will not be included in the GDL language's constraints ever.

2. Naming conventions

2.1. Variable names

Variable and parameter names should be related with the function of the parameter.

Starts with a lowercase letter; every new word should also start with an uppercase letter.
E.g.:
size, bRotAngle180, upperLeftCorner

Don't use one or two letter variable names, no one will know what you meant.

You should use a prefix in generally used variable names to denote general categories. This can spare time when someone needs to find out the type of a variable or parameter. Don't forget to replace the prefix if you change the meaning of a variable.

Prefix Meaning Example
i general integer value / integer index iRiser
n integer value - amount of something nRiser
b Boolean value bHandrail
x X coordinate of a point xRailPos
y Y coordinate of a point yRailPos
pen Pen color penContour
lt Linetype ltContour
fill Fill type fillMainBody
mat Material type matCover

Using underscores (_) is not forbidden, but please avoid it if possible. It cannot be used as the first or last character of a name.

2.2. Capitalization

  • Commands should be written consistently lowercase or uppercase according to your taste
  • GDL global variables should be written uppercase
  • call and parameters keywords should be lowercase

3. Expressions

  • Space should be used in front of and behind the following binary operators:
    • arithmetical: *, /, % (mod), +, -, ^ (**)
    • logical: & (and), | (or), @ (exor), =, <> (#), <, <=, >, >=
    • assignment: =
    E.g.:
    a = (b + c % d) * e
  • No spaces are allowed in front of and behind the following unary operators:
    • subscripting: array[25]
    • logical not: not(x)
    • unary minus, unary plus: -x, +x
  • Function calls should have a space in front of the opening parenthesis of the parameter list, and behind every comma separating the parameters:
    abs (signedLength)
    minimum = min (a, 25 * b, c)
    
  • When comparing with constants (e.g. i = 5) the constant should be the second operand.
  • When assigning values to bool variables the logical expression should be parenthesized:
    bBoolValue = (i > j)
  • Do not use the bool result of logical negation. E.g. instead of not(iIntVal) please use iIntVal = 0. (Of course, bool variables and expressions can be negated, e.g. not(bBoolVal)).
  • Do not compare bool variables and expressions to true or false; use the value of bool or its negated value:
    bBoolVal = 1;
    if bBoolVal then         ! instead of: if bBoolVal = 1
        ...
    endif
    if not(bBoolVal) then    ! instead of: if bBoolVal = 0
        ...
    endif
    				
  • Complex expressions (e.g. where and and or are both present) should be parenthesized, so that the precedence should always be clear.
  • Put parentheses around rarely used operator combinations.
  • Logical expressions consisting of many parts should be placed on multiple lines, and you should also align the sub-expressions or the logical operators:
    bResult = (bValue1 & bValue3 & not(bValueWithLongerName)) | \
              (not(bValue1) & not(bValue3) & bValueWithLongerName) | \
              (not(bValuel2) & bValue3 & not(bValueWithLongerName)) | \
              (bValue2 & not(bValue3) & bValueWithLongerName)
    				

4. Control flow statements

4.1. if - else - endif

Avoid using the one line form of conditional expressions.

For tabulation of code blocks use the following examples as suggestion:

if condition1 then
	statement1
	...
	statementn
else
	statementn+1
	...
	statementn+m
endif

if condition2 then
	if condition3 then
		...
	else
		...
	endif
	if condition4 then
		...
	endif
else
	...
endif

4.2. for - next, do - while, while - endwhile, repeat - until

For tabulation of code blocks use the following examples as suggestion:

for i = initialValue to endValue
	statement1
	...
	statementn
next i

do
	...
	for i = initialValue to endValue
		statement1
		...
		statementn
	next i
	...
	bCondition = ...
	...
while bCondition

5. Subroutines

Style:

! ==============================================================================
!	Short description of the functionality
! ------------------------------------------------------------------------------
! Input Parameters:
!	par1:     short description (type)
!	par2:     short description (type)
!	...
! Output:
!	par1:     short description
!	...
! Remark:
!	Remarks for the caller
!	Description of key points of the implementation
! ==============================================================================

100:
	! body
	return
! =========================================================================
print
!	Short description of the functionality
! -------------------------------------------------------------------------
! Input Parameters:
!	par1:     short description (type)
!	par2:     short description (type)
!	...
! Output:
!	par1:     short description
!	...
! Remark:
!	Remarks for the caller
!	Description of key points of the implementation
! =========================================================================

100:
	! body
	return

You should write the body of the subroutine indented by one tabulator field to the right.

You should leave two empty lines behind the closing 'return' of the subroutine.

You should write one statement per line.

Subroutines shouldn't be longer than 1-2 screens (about 80 lines) if possible.

Check all incoming parameters for validity and/or declare the restriction in comment

The call and parameters keywords are lowercase.

6. Writing comments

The language of the comments should be English; avoid bad words. Do not use accented characters.

The initials of developers are registered and can be found in a separate file (not included here). You can freely choose yours when you register, but after that you should always write it the same way. The length of the initial should be minimum 2, maximum 6 characters (letter, space, dot or underscore).

You should use the following style for comments:

Script header

!<contact person initials>
! ==============================================================================
! =========================================================================
!	One sentence description of the purpose of the script
! ------------------------------------------------------------------------------
! -------------------------------------------------------------------------
! Input Parameters:
!	par1:    description of the parameter (integer)
!	par2:    description of the parameter (1 / -1)
!	par3:    description of the parameter (0 / 1)
!	...
! Output: (on the GDL stack in this order) [if a macro returns values]
!	[1]:     description of the value (type)
!	[2]:     description of the value (type)
!	[ ... NSP]: original stack elements
! Remark:
!	Longer description.
!	Note for the caller
! ==============================================================================
! =========================================================================

Any code can come only after this.

Section divide

! ==============================================================================
! Section name
! ==============================================================================
! =========================================================================
! Section name
! =========================================================================

The length of the full comment line is 80 characters.

For the subroutines you should always explain the meaning of non-trivial parameters and the return value. E.g. for indices always indicate the range (starts from 0 or 1, any special values, etc.). Example:

! ==============================================================================
!	Short description of the functionality
! ------------------------------------------------------------------------------
! Input Parameters:
!	par1:     short description (type)
!	par2:     short description (type)
!	...
! Output:
!	par1:     short description
!	...
! Remark:
!	Remarks for the caller
!	Description of key points of the implementation
! ==============================================================================

100:
	! body
	return
! =========================================================================
print
!	Short description of the functionality
! -------------------------------------------------------------------------
! Input Parameters:
!	par1:     short description (type)
!	par2:     short description (type)
!	...
! Output:
!	par1:     short description
!	...
! Remark:
!	Remarks for the caller
!	Description of key points of the implementation
! =========================================================================

100:
	! body
	return

You should always indicate with three exclamation marks if you leave something unfinished:
n = 5 !!! initials; it will be computed from the length

You can also put optional section descriptions in between the lines of the source code, beginning at the current tab depth. You can also add short explanations to the end of the source line by adding a tab at the end; or, if there are more of those, you can align them with tabs.

You should always add comments:

  • For unusual solutions
  • If it would take too long to understand the code for someone else without the comment.
  • If something is forbidden or not recommended for others.

Optional (others will be thankful) if it helps in any way.
Do not let the comments break the rhythm of the code, or the merits of the code.

Then commenting a coherent code block, you may use the following format:

! == code block name ===[
statement1
...
statementn
! ]=== code block name ===

This faciliates the isolation of the block by the look plus some editors support the search for the matching bracket by a shortcut (f.ex.: ctrl + ] in Microsoft Visual Studio)

Comment the end of 'if' statements if there are many code lines between if and endif as follows:

if condition1 then
	...
	if condition2 then
		...
		! many statements
		...
	endif  ! if condition2

endif  ! if condition1

7. Script structure

Set your editor to use 4 character wide tabs. Don't replace them with spaces.

The maximum length of the lines is 120 characters. Statements shouldn't even get close to this number.

The maximum length of file names is 31 characters. File names are case sensitive, and use the extensions .xml and .gsm accordingly. The file names should be given case sensitive in all references (call).

Use end at the end of each script.

Values - which are used many times - are calculated directly before the block of use if the usage can be well localized or at the beginning of the script otherwise. There is no compromise. Calculate complex values only once to spare calculation time and store them in variables (but do not waste variables unnecessary) or in the transformation stack (add, rot, etc.).

The scripts of the object are of linear structure which makes them clearer. Subroutines are only used when a calculation or model generation segment is needed more than one time. For only one call no subroutine is needed, use comments for clarity. It is an important principle to avoid coding the same thing twice. Redundancy will make the later changes much more difficult. If you make big choice branches, you can't avoid this situation. Try to prepare the data for a calculation or generation command in smaller choices, where you can avoid redundancy easier.

Bad Solution

if onHomeStorey then
	line_type ltContour
	fill gs_fill_type
	poly2_b 5, 3, gs_fill_pen, gs_back_pen,
			left,	0,	1,
			left,	-depth,	1,
			right,	-depth,	1,
			right,	0,	0,
			left,	0,	-1
endif
if (onUpperStorey or onAboveUpper) and bDrawContBB then
	line_type ltBelow
	fill fillTypeBelow
	poly2_b 5, 3, fillPenBelow, fillBackBelow,
			left,	0,	1,
			left,	-depth,	1,
			right,	-depth,	1,
			right,	0,	0,
			left,	0,	-1
endif

The definition of geometry is duplicated! It could be even worse if the distance between the identical commands were bigger.

Good Solution

if onHomeStorey then
	bPolygon = 1
	line_type ltContour
	fill gs_fill_type
	fillPen = gs_fill_pen
	fillBGPen = gs_back_pen
endif
if (onUpperStorey or onAboveUpper) and bDrawContBB then
	bPolygon = 1
	line_type ltBelow
	fill fillTypeBelow
	fillPen = fillPenBelow
	fillBGPen = fillBackBelow
endif
if bPolygon then
	poly2_b 5, 3, fillPen, fillBGPen,
			left,	0,	1,
			left,	-depth,	1,
			right,	-depth,	1,
			right,	0,	0,
			left,	0,	-1
endif

Prepare your scripts for localization.
Use "asdf" for non-localized strings (f.ex. macro calls) and `adsf` for localized strings (f.ex. string constants, parameter values).

Copyright © 2004 - Graphisoft R&D Software Development Rt. All rights reserved worldwide.