HyperWorks Scripting Style Guide

There are Tcl/Tk programming conventions are recommended by Altair Engineering. They make scripts portable, readable and easy to update for others.

File Extensions

All Tcl/Tk scripts should be named with the .tcl file extension.

File Headers

The following is a sample header that can be used at the top of each script. Fill in the given fields for your program.
#################################################################
# File      : <file>.tcl
# Date      : June 7, 2007
# Created by: John Smith
# Purpose   : Detailed purpose of the script.
#################################################################

Procedure and Namespace Headers

The following is a sample procedure including a header. Fill in the given fields for your program.
#################################################################
proc ::post::MyProc { args } {
    # Purpose:
    # Args:
    # Returns:
    # Notes:
}

Any of the fields can be multiple lines if required for clarity. This might be the case with Args, where describing one argument in one line can make it more readable.

Notes can be used to document any special information, assumption, or warning considered relevant to the use of this function.

Any fields other than Purpose which may not required (in a small function, for example) can be deleted.

Variable names

Name local variables using a mix of lowercase letters and underscores
For example, local_variable
Global variables should be prefixed with g_
For example, g_root_val
Namespaced variables should be prefixed with m_
For example, m_x_loc

Procedure Names

Capitalize the first letter of each word
For example, SweepCurve
Use upper case letters for abbreviations
For example, MBPress for Mouse Button Press

Namespace Names

Namespace names should be comprised of the client name or a module name in lower case, followed by the user-defined namespace name.

HyperView post client example
::post::MyNamespace
HyperWorks Desktop example
::hm::MyNamespace
General utility for creating a window example
::window::MyNamespace
To avoid conflicts with existing namespaces or commonly used names, use additional namespace levels when required.
HyperWorks Desktop Example
::hm::MyNamespace::MyNamespace1
Note:
  • Since Tcl does not have the ability to make variables or procedures read-only, you should limit creating and storing these in the global namespace ::
  • While Tcl does not have the concept of private members, procedures and variables may be prefixed with p_ to imply that they are private.

Semicolons

While semicolons are optional in Tcl/Tk to specify the end of a command, they should be used to enhance readability, and to allow for comments to be placed on the same line.
set p_my_var 10;    # Initialize my variable

Indentations Using Spaces

Indentions should be 4 spaces only. Most editors allow you to replace tabs with spaces, and to specify the number of spaces per tab press.
if { conditional expression } {  
    # 4 spaces before first statement
    # Code goes here
}
When expressions are long, they may be broken into multiple lines.

for { set i 0 } \
    { $i < $limit } \
    { incr i } {
    # 4 spaces before first statement
    # Code goes here
}

switch { $option } {
    # 4 spaces before the first case statement
    default {
        # 4 spaces before first statement
        # Code goes here
    }
}

Large Procedure Argument List

Procedures with a large number of arguments should be broken up to improve readability.

Long Command Syntax

Commands that are very long should be split up into multiple lines using the slash, or continuation, symbol \. The slash indicates to Tcl that the current command extends onto the next line. The semicolon then indicates when a command ends. Combined, these help to aid in code review and debugging by making the code easier to decipher visually.
set extremely_long_variable_name_for_pi [expr 2.0 * \
    asin(1.0)];

Procedure and Namespace Layout

When creating procedures or namespaces you should define any global and/or variable declarations at the top of the procedure or namespace, followed by the body.

Attempt to use an array to store variables of like types to increase readability and reduce the need for multiple global or variable calls. For example, if you are storing information on an entity, you could create an array called m_attributes as:
variable m_attributes;

array set m_attributes {
    color Black
    style Solid
    id 100
}
As opposed to using separate variables:
variable m_color;
variable m_style;
variable m_id;

set m_color Black;
set m_style Solid;
set m_id 100;

Example

The following example demonstrates the above recommendations for a script that creation and modification of a Tk window.
#################################################################
# File      : windowObj.tcl
# Date      : June 7, 2007
# Created by: John Smith
# Purpose   : Create a new window with options for moving it to a
#             user specified location.
#################################################################

#################################################################
namespace eval ::window:: {
    # Purpose:  Used to create and control a window.
    #

    variable m_window .toplevelWindow;
    variable m_geom;

    # Initialize the default values
    array set m_geom {
        width  300
        height 500
    }

    #############################################################
    proc Create {} {
        # Purpose:  Create the window.
        #

        variable m_window;

        catch {destroy $m_window};
        toplevel $m_window -class Toplevel;
    }

    #############################################################
    proc Show {} {
        # Purpose:  Display the window.
        #

        variable m_window;

        if { ! [winfo exist $m_window] } {
            tk_messageBox -message "No window exists.";
        } else {
            wm deiconify $m_window;
        }
    }

    #############################################################
    proc Reconfigure {} {
        # Purpose:  Resize the window.
        #

        variable m_geom;
        variable m_window;

        if {$m_window != ""} {
            wm geometry $m_window $m_geom(width)x$m_geom(height);
            focus $m_window;
        }
    }
}