Skip to main content

Introduction to Classes

This page introduces classes in InterSystems IRIS® data platform and shows how they can contain methods written in Python or ObjectScript. Class definitions are not formally part of either language; instead, the syntax used to define classes is called Class Definition Language.

Other method implementation languages are supported as well, primarily for migration purposes.

Class Names and Packages

Each InterSystems IRIS class has a name, which must be unique within the namespace where it is defined. A full class name is a string delimited by one or more periods, as in the following example: package.subpackage.subpackage.class. The short class name is the part after the final period within this string; the part preceding the final period is the package name.

The package name is simply a string, but if it contains periods, the InterSystems IRIS development tools treat each period-delimited piece as a subpackage. Your Integrated Development Environment (IDE) and other tools display these subpackages as a hierarchy of folders, for convenience.

Basic Contents of a Class Definition

An InterSystems IRIS class definition can include the following items, all known as class members:

  • Parameters — A parameter defines a constant value for use by this class. The value is set at compilation time.

  • Properties — A property contains data for an instance of the class.

  • Methods — There are two kinds of methods: instance methods and class methods (called static methods in other languages).

  • Class queries — A class query defines an SQL query that can be used by the class and specifies a class to use as a container for the query. See Defining and Using Class Queries.

  • XData blocks — An XData block is a unit of data (XML, JSON, or YAML), for use by the class. See Defining and Using XData Blocks.

  • Other kinds of class members that are relevant only for persistent classes.

A class definition can include keywords; these affect the behavior of the class compiler. You can specify some keywords for the entire class, and others for specific class members. These keywords affect the code that the class compiler generates and thus control the behavior of the class.

The following shows a simple class definition with methods written in ObjectScript and in Python:

Class MyApp.Main.SampleClass Extends %RegisteredObject
{

Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;

Property VariableMessage As %String [ InitialExpression = "How are you?"];

Property MessageCount As %Numeric [Required];

ClassMethod HelloWorld() As %String [ Language = objectscript ]
 {
    Set x=..#CONSTANTMESSAGE
    Return x
 }

Method WriteIt() [ Language = objectscript, ServerOnly = 1]
{
    Set count=..MessageCount
    For i=1:1:count {
        Write !,..#CONSTANTMESSAGE," ",..VariableMessage
        }
    }

}
Class MyApp.Main.SampleClass Extends %RegisteredObject
{

Parameter CONSTANTMESSAGE [Internal] = "Hello world!" ;

Property VariableMessage As %String [ InitialExpression = "How are you?"];

Property MessageCount As %Numeric [Required];

ClassMethod HelloWorld() As %String [ Language = python ]
 {
    import iris
    x = iris.MyApp.Main.SampleClass._GetParameter("CONSTANTMESSAGE")
    return x
 }

Method WriteIt() [ ServerOnly = 1, Language = python ]
{
    import iris
    count = self.MessageCount
    print()
    for i in range(count):
        print(iris.cls(__name__)._GetParameter("CONSTANTMESSAGE"), self.VariableMessage)
}

}

Note the following points:

  • The first line gives the name of the class. MyApp.Main.SampleClass is the full class name, MyApp.Main is the package name, and SampleClass is the short class name.

    Your IDE and other user interfaces treat each package as a folder.

  • Extends is a compiler keyword.

    The Extends keyword specifies that this class is a subclass of %RegisteredObjectOpens in a new tab, which is a system class provided for object support. This example class extends only one class, but it is possible to extend multiple other classes. Those classes, in turn, can extend other classes.

  • CONSTANTMESSAGE is a parameter. By convention, all parameters in InterSystems IRIS system classes have names in all capitals. This is a convenient convention, but you are not required to follow it.

    The Internal keyword is a compiler keyword. It marks this parameter as internal, which suppresses it from display in the class documentation. This parameter has a string value.

    To access class parameters via Python, use the built-in method %GetParameter() to return the value of the parameter. However, in Python the percent sign character is not permitted in identifier names, so you need to substitute an underscore, instead.

  • To refer to the current class in ObjectScript, use a dot (.).

  • To refer to the current class in Python, you can use self, iris.Package.Class, or iris.cls(__name__), depending on the context. The example shows all three syntax forms. Note that iris.cls(__name__) has two underscores before and after name. (For more details, see References to Other Class Members.)

  • VariableMessage and MessageCount are properties. The item after As indicates the types for these properties. InitialExpression and Required are compiler keywords.

    You can access an InterSystems IRIS class property directly from ObjectScript or Python, as in the example.

  • HelloWorld() is a class method and it returns a string; this is indicated by the item after As.

    This method uses the value of the class parameter.

  • WriteIt() is an instance method and it does not return a value.

    This method uses the value of the class parameter and values of two properties.

    The ServerOnly compiler keyword means that this method will not be projected to external clients.

The following Terminal session shows how we can use this class. Both terminal shells are valid for the ObjectScript and Python versions of the class.

TESTNAMESPACE>write ##class(MyApp.Main.SampleClass).HelloWorld()
Hello world!
TESTNAMESPACE>set x = ##class(MyApp.Main.SampleClass).%New()
 
TESTNAMESPACE>set x.MessageCount=3
 
TESTNAMESPACE>do x.WriteIt()
 
Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
>>> print(iris.MyApp.Main.SampleClass.HelloWorld())
Hello world!
>>> x = iris.MyApp.Main.SampleClass._New()
>>> x.MessageCount=3
>>> x.WriteIt()

Hello world! How are you?
Hello world! How are you?
Hello world! How are you?
Note:

Effective with InterSystems IRIS 2024.2, an optional shorter syntax for referring to an InterSystems IRIS class from Embedded Python has been introduced. Either the new form or the traditional form are permitted.

Class Parameters

A class parameter defines a value that is the same for all objects of a given class. With rare exceptions, this value is established when the class is compiled and cannot be altered at runtime. You use class parameters for the following purposes:

  • To define a value that cannot be changed at runtime.

  • To define user-specific information about a class definition. A class parameter is simply an arbitrary name-value pair; you can use it to store any information you like about a class.

  • To customize the behavior of the various data type classes (such as providing validation information) when used as properties; this is discussed in the next section.

  • To provide parameterized values for method generator methods to use.

You can define parameters in an InterSystems IRIS class that contains ObjectScript methods, Python methods, or a combination of the two. The following shows a class with several parameters:

Class GSOP.DivideWS Extends %SOAP.WebService
{

Parameter USECLASSNAMESPACES = 1;

///  Name of the Web service.
Parameter SERVICENAME = "Divide";

///  SOAP namespace for the Web service
Parameter NAMESPACE = "http://www.mynamespace.org";

/// let this Web service understand only SOAP 1.2
Parameter SOAPVERSION = "1.2";

 ///further details omitted
}
Note:

Class parameters can also be expressions, which can be evaluated either at compile time or runtime. For more information, see Defining and Referring to Class Parameters.

Properties

Object classes can have properties. Formally, there are two kinds of properties in InterSystems IRIS:

  • Attributes, which hold values. The value can be any of the following:

    • A single, literal value, usually based on a data type.

    • An object value (this includes collection objects and stream objects).

    • A multidimensional array. This is less common.

    The word property often refers just to properties that are attributes, rather than properties that hold associations.

  • Relationships, which hold associations between objects.

You can define properties in a class containing ObjectScript methods, Python methods, or a combination of the two. However, you cannot access relationships from Python methods. This section shows a sample class that contains property definitions that show some of these variations:

Class MyApp.Main.Patient Extends %Persistent
{

Property PatientID As %String [Required];

Property Gender As %String(DISPLAYLIST = ",Female,Male", VALUELIST = ",F,M");

Property BirthDate As %Date;

Property Age As %Numeric [Transient];

Property MyTempArray [MultiDimensional];

Property PrimaryCarePhysician As Doctor;

Property Allergies As list Of PatientAllergy;

Relationship Diagnoses As PatientDiagnosis [ Cardinality = children, Inverse = Patient ]; 
}

Note the following:

  • In each definition, the item after As is the type of the property. Each type is a class. The syntax As List Of is shorthand for a specific collection class.

    %StringOpens in a new tab, %DateOpens in a new tab, and %NumericOpens in a new tab are data type classes.

    %StringOpens in a new tab is the default type.

  • Diagnoses is a relationship property; the rest are attribute properties.

  • PatientID, Gender, BirthDate, and Age can contain only simple, literal values.

  • PatientID is required because it uses the Required keyword. This means that you cannot save an object of this class if you do not specify a value for this property.

  • Age is not saved to disk, unlike the other literal properties. This is because it uses the Transient keyword.

  • MyTempArray is a multidimensional property because it uses the MultiDimensional keyword. This property is not saved to disk by default.

  • PrimaryCarePhysician and Allergies are object-valued properties.

  • The Gender property definition includes values for property parameters. These are parameters in the data type class that this property uses.

    This property is restricted to the values M and F. When you view the display values (as in the Management Portal), you see Male and Female instead. Each data type class provides methods such as LogicalToDisplay().

Methods

There are two kinds of methods: instance methods and class methods (called static methods in other languages). Instance methods are available only in object classes.

In InterSystems IRIS, methods can be written in ObjectScript or Python. To specify which language you will write a method in, use the following syntax:

Method MyMethod() [ Language = objectscript ]
{
    // implementation details written in ObjectScript
}
Method MyMethod() [ Language = python ]
{
    # implementation details written in Python
}

If a method does not use the Language keyword the compiler will assume that the method is written in default language for the class.

You must write the method’s language in all lowercase letters, as in the example.

References to Other Class Members

Within a method, use the syntax shown here to refer to other class members:

  • To refer to a parameter, use an expression like this:

     ..#PARAMETERNAME
    
    # technique 1
    iris.Package.Class._GetParameter("PARAMETERNAME")
    
    # technique 2
    objectinstance._GetParameter("PARAMETERNAME")
    

    In classes provided by InterSystems, all parameters are defined in all capitals, by convention, but your code is not required to do this.

  • To refer to another instance method, use an expression like this:

     ..methodname(arguments)
    
    self.methodname(arguments)
    

    Note that you cannot use this syntax within a class method to refer to an instance method.

  • To refer to another class method, use the following syntax:

     ..classmethodname(arguments)
    
    # technique 1
    iris.Package.Class.classmethodname(arguments)
    
    # technique 2
    iris.cls(__name__).classmethodname(arguments)
    

    Note that you cannot use the Python self syntax to access a class method. Instead, you can use the __name__ property to obtain the name of the current class, as shown in the above example.

  • (Within an instance method only) To refer to a property of the instance, use an expression like this:

     ..PropertyName
    
    self.PropertyName
    
    

    Similarly, to refer to a property of an object-valued property, use an expression like this:

     ..PropertyNameA.PropertyNameB
    
    self.PropertyNameA.PropertyNameB
    

    The syntax used in the ObjectScript examples is known as dot syntax.

    Also, you can invoke an instance method or class method of an object-valued property. For example:

     Do ..PropertyName.MyMethod()
    self.PropertyName.MyMethod()
    

References to Methods of Other Classes

Within a method (or within a routine), use the syntax shown here to refer to a method in some other class:

  • To invoke a class method and access its return value, use an expression like the following:

     ##class(Package.Class).MethodName(arguments)
    
    iris.Package.Class.MethodName(arguments)
    
    

    For example:

     set x = ##class(Util.Utils).GetToday()
    x = iris.Util.Utils.GetToday()
    

    You can also invoke a class method without accessing its return value as follows:

     do ##class(Util.Utils).DumpValues()
    iris.Util.Utils.DumpValues()
    
    Note:

    ##class is not case-sensitive.

  • To invoke an instance method, create an instance and then use an expression like the following in either ObjectScript or Python to invoke the method and access its return value:

    instance.MethodName(arguments)
    

    For example:

     Set x=instance.GetName()
    x=instance.GetName()
    

    You can also invoke an instance method without accessing its return value by calling the method as follows:

     Do instance.InsertItem("abc")
    instance.InsertItem("abc")
    

Not all methods have return values, so choose the syntax appropriate for your case.

References to Current Instance

Within an instance method, sometimes it is necessary to refer to the current instance itself, rather than to a property or method of the instance. For example, you might need to pass the current instance as an argument when invoking some other code.

In ObjectScript, use the special variable $THIS to refer to the current instance. In Python, use the variable self to refer to the current instance.

For example:

 Set sc=header.ProcessService($this)
sc=header.ProcessService(self)

Method Arguments

A method can take positional arguments in a comma-separated list. For each argument, you can specify a type and the default value.

For instance, here is the partial definition of a method that takes three arguments. This is valid syntax for both ObjectScript and Python methods within InterSystems IRIS classes:

Method Calculate(count As %Integer, name, state As %String = "CA") as %Numeric
{
    // ...
}

Notice that two of the arguments have explicit types, and one has an default value. Generally it is a good idea to explicitly specify the type of each argument.

Note:

If a method is defined in Python and has any arguments with default values, then these arguments must be at the end of the argument list to avoid a compilation error.

Skipping Arguments

When invoking a method you can skip arguments if there are suitable defaults for them. ObjectScript and Python each have their own syntax to skip arguments.

In ObjectScript, you can skip over an argument by providing no value for that argument and maintaining the comma structure. For example, the following is valid:

 set myval=##class(mypackage.myclass).GetValue(,,,,,,4)

In an InterSystems IRIS class, a Python method’s signature must list the required arguments first, followed by any arguments with default values.

When calling the method, you must provide arguments in the order of the method’s signature. Therefore, once you skip an argument you must also skip all arguments following it. For example, the following is valid:

ClassMethod Skip(a1, a2 As %Integer = 2, a3 As %Integer = 3) [ Language = python ]
{
    print(a1, a2, a3)
}
TESTNAMESPACE>do ##class(mypackage.myclass).Skip(1)
1 2 3

Passing Variables by Value or by Reference

When you invoke a method, you can pass values of variables to that method either by value or by reference.

The signature of a method usually indicates whether you are intending to pass arguments by reference. For example:

Method MyMethod(argument1, ByRef argument2, Output argument3)

The ByRef keyword indicates that you should pass this argument by reference. The Output keyword indicates that you should pass this argument by reference and that the method ignores any value that you initially give to this argument.

Similarly, when you define a method, you use the ByRef and Output keywords in the method signature to inform other users of the method how it is meant to be used.

To pass an argument by reference in ObjectScript, place a period before the variable name when invoking the method. In Python, use iris.ref() on the value you want to pass and call the method on the reference. Both of these are shown in the following example:

 do MyMethod(arg1, .arg2, .arg3)
arg2 = iris.ref("peanut butter")
arg3 = iris.ref("jelly")
MyMethod(arg1,arg2,arg3)
Important:

The ByRef and Output keywords provide information for the benefit of anyone using the InterSystems Class Reference. They do not affect the behavior of the code. It is the responsibility of the writer of the method to enforce any rules about how the method is to be invoked.

Variable Numbers of Arguments

You can define a method so that it accepts a variable number of arguments. For example:

ClassMethod MultiArg(Arg1... As %List) [ Language = objectscript ]
{
 set args = $GET(Arg1, 0)
 write "Invocation has ",
     args,
     " element",
     $SELECT((args=1):"", 1:"s"), !
 for i = 1 : 1 : args
 {
     write "Argument[", i , "]: ", $GET(Arg1(i), "<NULL>"), !
 }
}
ClassMethod MultiArg(Arg1... As %List) [ Language = Python ]
{
    print("Invocation has", len(Arg1), "elements")
    for i in range(len(Arg1)):
        print("Argument[" + str(i+1) + "]: " + Arg1[i])
}

Specifying Default Values

To specify an argument’s default value in either an ObjectScript or a Python method, use the syntax as shown in the following example:

Method Test(flag As %Integer = 0)
{
 //method details
}

When a method is invoked, it uses its default values (if specified) for any missing arguments. If a method is written in Python, then any arguments with default values must be defined at the end of the argument list.

In ObjectScript, another option is to use the $GET function to set a default value. For example:

Method Test(flag As %Integer)
{
  set flag=$GET(flag,0)
 //method details
}

This technique, however, does not affect the class signature.

Shortcuts for Calling Class Methods

When calling class methods using ObjectScript, you can omit the package (or the higher level packages) in the following scenarios:

  • The reference is within a class, and the referenced class is in the same package or subpackage.

  • The reference is within a class, and the class uses the IMPORT directive to import the package or subpackage that contains the referenced class.

  • The reference is within a method, and the method uses the IMPORT directive to import the package or subpackage that contains the referenced class.

When calling class methods from ObjectScript, you can omit the package (or higher level packages) in the following scenarios:

  • You are referring to a class in the %Library package, which is specially handled. You can refer to the class %Library.ClassName as %ClassName. For example, you can refer to %Library.StringOpens in a new tab as %StringOpens in a new tab.

  • You are referring to a class in the User package, which is specially handled. For example, you can refer to User.MyClass as MyClass.

    InterSystems does not provide any classes in the User package, which is reserved for your use.

In all other cases, you must always use the full package and class name to call a class method.

When calling class methods from Python, you can omit the package (or higher level packages) if using the iris.cls() method, as in s = iris.cls('%String'). Use the longer form if using iris.Package.Class, as in s = iris._Library.String.

See Also

FeedbackOpens in a new tab