Show/Hide Toolbars

XSharp

The STATIC modifier has a different meaning depending on whether it is used on a class or its members, on a FUNCTION/GLOBAL or on a LOCAL variable.

Static classes and members

Static members

The STATIC modifier on a member of a class (method, constructor, property, field, event) declares a member which belongs to the class itself, instead of to an instance of the class. Normal (instance) methods and other members can be called by using an instance of the class (for example through SELF, or a local variable holding such an instantiated object) with the colon (":") operator (also with the dot "." operator if the compiler option /allowdot is enabled), while static members can be accessed directly through the class itself, using the dot operator:

FUNCTION Start() AS VOID
  LOCAL oInstance AS TestClass
  oInstance := TestClass{}
 
  ? oInstance:instance_field
  ? oInstance:InstanceMethod()
  ? oInstance:InstanceProperty
 
  ? TestClass.static_field
  ? TestClass.StaticMethod()
  ? TestClass.StaticProperty

CLASS TestClass
  EXPORT instance_field := "instance field" AS STRING
  STATIC EXPORT static_field := "static field" AS STRING
 
  METHOD InstanceMethod() AS STRING
  RETURN "Instance method"
  PROPERTY InstanceProperty() AS STRING GET "Instance property"
     
  STATIC METHOD StaticMethod() AS STRING
  RETURN "Static method"
  STATIC PROPERTY StaticProperty() AS STRING GET "Instance property"
END CLASS

A static method is very similar to a common function and can be used in the same way, but it has the advantage that it is encapsulated within a class that may contain other related static or non-static members. Like functions, static methods cannot use instance members of the class with SELF; but they can access other static members. Methods with related functionality can be grouped together under the same class, offering much better intellisense support in the editor (typing a dot after a class name will show a list of all its static members) and makes the code more structured. For example, the System.Math class offers a lot of mathematical functions, all grouped together under a single class, making it easier to find and use, rather than having several standalone functions offering the same functionality. Similarly, a static field can be regarded as a GLOBAL, but again structured under a class. Any method of a class that is not using SELF in its body (so is not accessing any instance members) is a good candidate to be declared as static.

Static constructor

It is also possible to define a single static constructor per class, which is guaranteed to be called automatically just before any static member (method, field, etc.) of the class is accessed for the first time. A static constructor must have no parameters and cannot be overloaded. Typical use of a static constructor is to initialize static fields:

FUNCTION Start() AS VOID
  ? TestClass.static_field // adjusted by static constructor
 
CLASS TestClass
  STATIC EXPORT static_field := "initial value" AS STRING
 
  STATIC CONSTRUCTOR()
     ? TestClass.static_field // initial value
     TestClass.static_field := "adjusted by static constructor"
END CLASS

Note that it is not allowed to define a static destructor. If you need to clean up data stored inside a static class, it is recommended to register a ProcessExit event handler in the AppDomain class.This will be called when the application ends.

FUNCTION Start() AS VOID
 
CLASS TestClass
 
  STATIC CONSTRUCTOR()
     AppDomain.CurrentDomain:ProcessExit += EventHandler{CurrentDomain_ProcessExit}
 
static method CurrentDomain_ProcessExit(sender as object, e as EventArgs) as void
  // clean up
  return
END CLASS

Static class

When a class is designed to hold only static members, it can be declared as being static itself. Doing so allows the compiler to check every member of the class and ensure that none are accidentally declared as non-static:

STATIC CLASS StaticClass
  STATIC EXPORT static_field AS STRING
  EXPORT accidental_instance AS STRING // compiler error XS0708: cannot declare instance members in a static class
 
  STATIC METHOD Static_method() AS VOID
  METHOD Accidental_Instance_method() AS VOID // compiler error XS0708: cannot declare instance members in a static class
END CLASS

Static functions and globals

Declaring a function or global as static, restricts its visibility to the code file where it is declared only. This allows multiple files to declare functions and globals with the same name, with each being visible only within its respective file:

STATIC GLOBAL GlobalVisibleOnlyInThisFile AS INT
STATIC FUNCTION FunctionVisibleOnlyInThisFile() AS VOID

Static local

Declaring a LOCAL variable as STATIC, causes it to be initialized with a value only once, being the first time that the method, function or other entity where it is declared is called. The local variable retains its previous value on subsequent times the code is called:

FUNCTION Start() AS VOID
  ? TestStaticLocal() // 2
  ? TestStaticLocal() // 3
  ? TestStaticLocal() // 4
 
FUNCTION TestStaticLocal() AS INT
  STATIC LOCAL nStaticLocal := 1 AS INT // gets initialized to 1 only the first time the function is called
  nStaticLocal ++ // the current value will be retained the next time the function is called
RETURN nStaticLocal