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
callandparameterskeywords 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: =
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
- subscripting:
-
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 useiIntVal = 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
andandorare 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 (italic texts should be replaced implicitly):
! ==============================================================================! ========================================================================= ! 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 ! ==============================================================================! ========================================================================= subrutine_title: ! 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.
From ArchiCAD 10 you should use text labels to increase transparency in coding.
6. Writing comments
The language of the comments should be English; avoid bad words.
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: [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 ! ==============================================================================! =========================================================================
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
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 at the start of the lines. In contrast, use spaces instead of tabs to adjust expressions to each other inside the lines.
The maximum length of the lines is 120 characters. Statements shouldn't even get close to this number.
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).
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).