Skip to main content

Introduction to InterSystems IRIS Programming

This page provides a high-level overview of the language elements you can use in InterSystems IRIS® server-side programs.

Introduction

InterSystems IRIS is a high-performance multi-model data platform with a built-in general-purpose programming language called ObjectScript, as well as built-in support for Python.

InterSystems IRIS supports multiple processes and provides concurrency control. Each process has direct, efficient access to the data.

In InterSystems IRIS, you can write classes, routines, or a mix of these, as suits your preferences. In all cases, stored data is ultimately contained in structures known as globals. InterSystems IRIS programming has the following features:

  • Classes and routines can be used interchangeably.

  • Classes and routines can call each other.

  • Classes provide object-oriented features.

  • Database storage is integrated into both ObjectScript and Python.

  • Classes can persist data in a way that simplifies programming. If you use persistent classes, data is simultaneously available as objects, SQL tables, and globals.

  • You can access globals directly from either classes or routines, which means that you have the flexibility to store and access data exactly how you want.

You can choose the approach that is appropriate for your needs.

Classes

InterSystems IRIS supports classes. You can use the system classes and you can define your own classes.

In InterSystems IRIS, a class can include familiar class elements such as properties, methods, and parameters (known as constants in other class languages). It can also include items not usually defined in classes, including triggers, queries, and indexes.

InterSystems IRIS class definitions use Class Definition Language (CDL) to specify the class and its members such as properties, methods, and parameters. You can use either Python or ObjectScript to write the executable code inside of methods. For each method, specify which language you will be writing the method in by using the Language keyword, as in the example below.

The following shows a class definition:

Class Sample.Employee Extends %Persistent
{

/// The employee's name.
Property Name As %String(MAXLEN = 50);

/// The employee's job title.
Property Title As %String(MAXLEN = 50);

/// The employee's current salary.
Property Salary As %Integer(MAXVAL = 100000, MINVAL = 0);

/// This method prints employee information using ObjectScript.
Method PrintEmployee() [ Language = objectscript] 
{
    Write !,"Name: ", ..Name, " Title: ", ..Title
}

}
Class Sample.Employee Extends %Persistent
{

/// The employee's name.
Property Name As %String(MAXLEN = 50);

/// The employee's job title.
Property Title As %String(MAXLEN = 50);

/// The employee's current salary.
Property Salary As %Integer(MAXVAL = 100000, MINVAL = 0);

/// This method prints employee information using Embedded Python.
Method PrintEmployee() [ Language = python ] 
{
    print("\nName:", self.Name, "Title:", self.Title)
}

}

If you do not specify which language a method uses, the compiler will assume that the method is written in ObjectScript.

Other articles discuss classes in InterSystems IRIS and the unique capabilities of persistent classes in InterSystems IRIS.

Routines

When you create routines in InterSystems IRIS, you use ObjectScript. The following shows part of a routine written in ObjectScript:

    SET text = ""
    FOR i=1:5:$LISTLENGTH(attrs)
    {
        IF ($ZCONVERT($LIST(attrs, (i + 1)), "U") = "XREFLABEL")
        {
            SET text = $LIST(attrs, (i + 4))
            QUIT
        }
    }
    
    IF (text = "")
    {
        QUIT $$$ERROR($$$GeneralError,$$$T("Missing xreflabel value"))
    }

Using Classes and Routines Together

In InterSystems IRIS, you can use classes from within routines. For example, the following shows part of a routine, in which we refer to the Sample.Employee class:

 //get details of random employee and print them
showemployee() public {
    set rand=$RANDOM(10)+1        ; rand is an integer in the range 1-10
    write "Your random number: "_rand
    set employee=##class(Sample.Employee).%OpenId(rand)  
    do employee.PrintEmployee()
    write !,"This employee's salary: "_employee.Salary
      
    }

Similarly, a method can invoke a label in a routine. For example, the following invokes the label ComputeRaise in the routine employeeutils:

Method RaiseSalary() As %Numeric
{
    set newsalary=$$ComputeRaise^employeeutils(..Salary)
    return newsalary
}
Method RaiseSalary() as %Numeric [ Language = python ]
{
    import iris
    newsalary=iris.routine("ComputeRaise^employeeutils", self.Salary)
    return newsalary
}

Introduction to Globals

InterSystems IRIS supports a special kind of variable that is not seen in other programming languages; this is a global variable, which is usually just called a global. In InterSystems IRIS, the term global indicates that this data is available to all processes accessing this database. This usage is different from other programming languages in which global means “available to all code in this module.”

The contents of a global are stored in an InterSystems IRIS database. For now, it is important just to know the following points:

  • A global is automatically stored in the database. When you assign a value to a node of a global variable, the data is written immediately to the database.

  • You can see the contents of a global programmatically or via the Management Portal.

Ways to Access Data

In InterSystems IRIS, a database contains globals and nothing else; even code is stored in globals, as described later in this book. At the lowest level, all access to data is done via direct global access — that is, by using commands and functions that work directly with globals.

When you use persistent classes, discussed later in this book, you can create, modify, and delete stored data in the following ways:

  • In ObjectScript, using methods such as %New(), %Save(), %Open(), and %Delete().

  • In Python, using methods such as _New(), _Save(), _Open(), and _Delete().

  • In ObjectScript, using direct global access.

  • In Python, using the gref() method to provide direct global access.

  • By using InterSystems SQL.

Internally, the system always uses direct global access.

InterSystems SQL

InterSystems IRIS provides an implementation of SQL, known as InterSystems SQL. You can use InterSystems SQL within methods and within routines.

Using SQL from ObjectScript

You can execute SQL from ObjectScript using either or both of the following ways:

  • Dynamic SQL (the %SQL.StatementOpens in a new tab and %SQL.StatementResultOpens in a new tab classes), as in the following example:

     SET myquery = "SELECT TOP 5 Name, Title FROM Sample.Employee ORDER BY Salary"
     SET tStatement = ##class(%SQL.Statement).%New()
     SET tStatus = tStatement.%Prepare(myquery)
     SET rset = tStatement.%Execute()
     DO rset.%Display()
     WRITE !,"End of data"
    

    You can use dynamic SQL in ObjectScript methods and routines.

  • Embedded SQL, as in the following example:

     &sql(SELECT COUNT(*) INTO :myvar FROM Sample.Employee)
        IF SQLCODE<0 {WRITE "SQLCODE error ",SQLCODE," ",%msg  QUIT}
        ELSEIF SQLCODE=100 {WRITE "Query returns no results"  QUIT}
     WRITE myvar

    The first line is embedded SQL, which executes an InterSystems SQL query and writes a value into a host variable called myvar.

    The next line is ordinary ObjectScript; it simply writes the value of the variable myvar.

    You can use embedded SQL in ObjectScript methods and routines.

Using SQL from Python

Using SQL from Python is similar to using Dynamic SQL from ObjectScript. You can execute SQL from Python using either or both of the following ways:

  • You can execute the SQL query directly, as in the following example:

    import iris
    rset = iris.sql.exec("SELECT * FROM Sample.Employee ORDER BY Salary") 
    for row in rset:
        print(row)
    

    The second line executes an InterSystems SQL query and returns a result set stored in the variable rset.

  • You can also prepare the SQL query first, then execute it, as in the following example:

    import iris
    statement = iris.sql.prepare("SELECT * FROM Sample.Employee ORDER BY Salary")
    rset = statement.execute()
    for row in rset:
        print(row)
    

    In this example, the second line returns a SQL query which is executed on the third line to return a result set.

You can use either of these approaches to execute SQL queries in the Python terminal or in Python methods.

Macros

ObjectScript also supports macros, which define substitutions. The definition can either be a value, an entire line of code, or (with the ##Continue directive) multiple lines. You use macros to ensure consistency. For example:

 #define StringMacro "Hello, World!"

 write $$$StringMacro

For more information on using macros, see Using Macros and Include Files.

Include Files

You can define macros in a routine and use them later in the same routine. More commonly, you define them in a central place. To do this, you create and use include files. An include file defines macros and can include other include files.

For more information on how to use include files, see Using Macros and Include Files.

How These Code Elements Work Together

It is useful to understand how InterSystems IRIS uses the code elements introduced in this page.

The reason that you can use a mix of ObjectScript, Python, InterSystems SQL, class definitions, macros, routines, and so on is that InterSystems IRIS does not directly use the code that you write. Instead, when you compile your code, the system generates lower-level code that it uses. This is OBJ code for ObjectScript, used by the ObjectScript engine, and PYC code for Python, used by the Python engine.

There are multiple steps. It is not necessary to know the steps in detail, but the following points are good to remember:

  • The class compiler processes class definitions and ObjectScript code into INT code for all elements other than Python methods. Python code is processed into PY code.

    In some cases, the compiler generates and saves additional classes, which you should not edit. This occurs, for example, when you compile classes that define web services and web clients.

    The class compiler also generates the class descriptor for each class. The system code uses this at runtime.

  • For ObjectScript code, a preprocessor (sometimes called the macro preprocessor or MPP) uses the include files and replaces the macros. It also handles the embedded SQL in routines.

    These changes occur in a temporary work area, and your code is not changed.

  • Additional compilers create INT code for routines.

  • INT code and PY code are an intermediate layer in which access to data is handled via direct global access. This code is human-readable.

  • INT code is used to generate OBJ code, and PY code is used to generate PYC code. The InterSystems IRIS virtual machine uses this code. Once you have compiled your code into OBJ and PYC code, the INT and PY routines are no longer necessary for code execution.

  • After you compile your classes, you can put them into deployed mode. InterSystems IRIS has a utility that removes the class internals and the intermediate code for a given class; you can use this utility when you deploy your application.

    If you examine the InterSystems IRIS system classes, you might find that some classes cannot be seen because they are in deployed mode.

Note:

All class definitions and routines are stored in the same InterSystems IRIS databases as the generated code. This fact makes the code easier to manage. InterSystems IRIS provides a robust set of source control hooks that InterSystems developers have used for many years. You can use these hooks as well.

FeedbackOpens in a new tab