API design and naming guidelines

This is a living document that will be updated periodically when necessary.

Introduction

The purpose of this document is to provide guidelines for creating APIs and naming them such that new APIs are clear, easy to understand and most importantly, consistent with the rest of the Xojo framework.

The goal of consistency is to make it possible for a user to guess the API of a class with which they have never worked rather than have to learn each one every time. This also makes understanding existing code faster as well. However, consistency should not reduce readability.

Consistency

Before creating a new API, review the existing APIs to see if there's one that is similar to what you need for the new functionality.

Case

Class names are upper camel case.

Example: TextField

Class members are upper camel case.

Example: TextField.SelectedText

Parameters are camel case.

Example: FolderItem.FromSaveInfo(saveInfo As String) As FolderItem

Namespaces are upper camel case, when used.

Example: Xojo.Core

General naming

Names should provide the most intuitive identification not necessarily the most accurate. They should choose clarity over brevity. The name should make it immediately obvious what the item is for even if that name is not entirely accurate. For example, previously the name of the event that is called when a button is clicked was called Action rather than Clicked or Pressed because it can be triggered without clicking/pressing the button. That makes Action more accurate but it's also not at all intuitive. In API 2.0, Action has been renamed Pressed which, while less accurate, is far more intuitive. It's obvious what the event is for and the exceptions (such as the fact that a button can be triggered without pressing it - via accessibility features for example) are easy enough to understand. Another example is the Volume class in the context of FolderItems. Most people have to learn what this means. In the API 2.0 we use Drive instead since most volumes are Hard Drives, Flash Drives or Solid State Drives (SSD). Volume is more accurate but not as intuitive since it also has a meaning relating to sound volume.

Names should not use abbreviations or truncations unless they are so common that they are spoken that way. For example, Info is acceptable. Sel (for Selection) is not. Abbreviated Min and Max are not acceptable as part of compound framework terms. This does not apply to standard math functions, such as for Min and Max, which will will not change.

Class names should be a noun. For the case when there are two classes, one that can be modified and one that cannot, use the Editable prefix for the one that can be modified and no prefix for the one that cannot be modified. For example, Image and EditableImage.

Method names should start with a verb. Follow with a noun for clarification, but do not include a noun if it is redundant. For example Refresh or SetFocus.

Functions (methods that return a value) should be named or prefixed with what they return. DesktopFolder is acceptable. GetDesktopFolder is not.

Event names should be past tense if the event itself has already taken place when the user's code is called. Example: TextField.TextChanged is acceptable because the TextField's value has already been changed.

Event names should be in the form noun verb. For example SelectionChanged.

Most controls should have a Pressed event. Controls whose primary form of user interaction involves the user clicking or tapping the control should have a Pressed event that is passed a parameter when necessary to indicate what was pressed.

Properties (and Constants) in most cases, should be nouns and named after what they contain.

Enumeration names should always be plural. Name of members of type enumeration should always be singular. For example, the Timer class has RunModes as an enumeration and RunMode as a member of type RunModes.

Omit needless words. For example, System.GetNetworkInterface should just be NetworkInterface (and also because functions should be named what they return). TextField has both TextChanged and SelectionChanged.

Group associated members. When possible, if members are associated with each other, use a common prefix so they are listed together alphabetically. For example, DragEntered and DragExited. However, do this only when other API guidelines can also be satisfied.

When a class member is specific to a particular platform, it should be prefixed with the name of the platform. The following are the designated prefixes: Mac, Windows, Linux, iOS, Android, Web and Mobile.

Boolean properties

These prefixes are used with UI-related Boolean properties for situations when it is unclear how the UI may be changed.

Name

Description

Example

Allow

Makes a change to the behavior or interface possible but not necessarily immediately.

AllowFocusRing

Has

Makes an immediate visual change to an element of the user interface of the object.

HasCloseButton

Is

Optionally used for read-only Boolean properties (and functions) when needed for clarity.

IsRectangle

If Allow or Has results in awkward names, use something that is better.

Otherwise Boolean properties do not have a prefix and are named after what they indicate. For example, Enabled or DarkModeIsSupported.

Lists

List items are accessed via a value from the list or a 0-based index. When an index is used, the preposition “At” is added which differentiates it from a method that looks up by value. Classes that provide access to a list should implement the following standard set of members. For non-generic methods, a noun should be included to help clarify the purpose of the method (as specified using <Item> below). For example, AddRow, AddButton, AddMenu, AddSegment, etc.

List classes should also always implement the Iterable and Iterator interfaces to allow looping with For Each...Next statements.

For two dimensional lists (probably only for multi-column listboxes), the <Item>At method should take row and column indexes as parameters and could return the entire item (as an array of the appropriate type) if no column index is passed.

For list-type containers that have multiple things that are counts (row count, column count, for example) then be specific for all the types of count: RowCount, ColumnCount.

For user interface controls that are list-oriented (ListBox, PopupMenu, TabPanel, Toolbar, SegmentedControl, etc.) where the user can select an item from the list, the following members should be implemented:

Name

Description

Example

Selected<Item>

Returns the item currently selected. If no item is selected, an OutOfBoundsException is raised.

Var value As String = Me.SelectedRow

Selected<Item>Index

Allows you to get or set the selected item. If you call this as a function and nothing is selected, an OutOfBoundsException is raised.

Var index As Integer = Me.SelectedRowIndex

Me.SelectedIndex = 5

Selected<Item>Count

Returns the number of items selected.

If Me.SelectedSegmentCount > 0 Then

Avoid hidden functionality: Avoid negative indexes for special behaviors. Instead add methods that provide the functionality. For example, Listbox.CellTextAt(-1, -1) is bad as it should really raise an OutOfBoundsException. Instead, a Listbox.Contents method that returns a two-dimensional array would be better. With no parameters this is the entire ListBox, with one parameter this is the specific row.

Errors

Errors should raise exceptions rather than return error codes. However, the exceptions raised can have members that provide error codes. Methods should not return booleans to indicate that they succeeded or not as that boolean value is really a simple error code. Instead, the function should throw an exception if it fails.

Enumeration usage

Use enumerations in place of integer constants when the value is unimportant and they are not used as part of a calculation. For example, bit flags would need to be constants because they are used to calculate actual Integer values.