Skip to content

TLDR: Types

This is a brief introduction to types in IDL.

Information

Types are, for now, built around documentation for your code. It is recommended to use format-on-save in VSCode with AutoDoc enabled for the extension. You can disable formatting apart from adding documentation if desired.

Using Types

With the help of AutoDoc, type details will be added to documentation for you to quickly change/update.

Here is an example showing functions, procedures, arguments, keywords, and properties in structure definitions (from "__define" procedures).

idl
;+
; :Arguments:
;   a: in, required, Array<Number>
;     First argument
;   b: in, required, List<Hash<Number>>
;     Second argument
;
;-
pro mypro, a, b
  compile_opt idl2
  c = a + b
end

;+
; :Returns: Long
;
; :Keywords:
;   kw1: in, optional, ENVIRaster
;     First keyword
;   kw2: out, optional, String
;     Second keyword
;
;-
function myFunc, kw1 = kw1, kw2 = kw2
  compile_opt idl2
  kw2 = 'string!'
  return, 1
end

;+
; :MyClass:
;   prop: Long
;     Favorite property
;   prop2: Array<String>
;     Second favorite property
;
;-
pro class__define
  compile_opt idl2

  !null = {MyClass, prop: 1, prop2: ptr_new()}
end

Basic Types

Basic types are data types in IDL that are standalone and don't require any additional information.

All aliases are mapped to the type in the left-most column and, when formatted, are replaced with that value

TypeRepresentsAliases (case insensitive)
anyLiterally anythingany
BigIntegerBig integersBigInteger, BigInteger
BooleanBinary values of true/falseBool, Boolean
ByteByte numberByte
ComplexNumberGeneric complex numberComplexNumber
ComplexFloat complex numberComplex, ComplexFloat, FloatComplex
DoubleComplexDouble complex numberDComplex, DoubleComplex, DoubleComplex
DoubleDouble-precision numberDouble, Float64
IntInteger numberInt, Integer
LongLong numberLong
Long6464-bit long numberLong64
NullNull values (i.e. !null)Null
NumberGeneric numberNumber
StringStringString
UIntUnsigned integer numberUInt, UnsignedInt, UnsignedInteger
ULongUnsigned long numberULong, UnsignedLong
ULong64Unsigned 64-bit long numberULong64, UnsignedLong64

Compound Types

Unlike basic types, compound types require additional information (known as a type argument) in order to be fully qualified. These type arguments typically contain basic types or other compound types.

Here are a few examples of how you create and use compound types:

  • An array of strings: Array<String>

  • An object array of lists that contain numbers: Array<List<Number>>

Why do we need a type argument? The type argument, wrapped in <TypeArg> indicates the return value when indexing or what the type contains. For example, if you index a data type that is an Array<String> you would get back a scalar String.

If you don't specify a type argument, it defaults "any", indicating it can contain any value

If you don't specify a type argument, when you next use AutoDoc, it will automatically have <any> added to the type

Do not create nested array types for multi-dimensional arrays. Dimensionality of arrays is not handled at this point in time.

TypeRepresentsAliases (case insensitive)Examples (case insensitive)
ArrayArrays of values (no dimensions)ArrayArray<String>, Array<Hash>
DictionaryDictionary and values withinDictionary, DictDictionary<List\<Hash>>
ENVITaskNamed ENVI TaskENVITaskENVITask<SubsetRaster>
HashHash and values withinHashHash<Number>, Hash<List>
IDLTaskNamed IDL TaskIDLTaskIDLTask<MyCustomTask>
ListList and values withinListList<Number | String>
PointerPointer what the pointer representsPointer, PtrPointer<Array<Number>>

Union Types

If a value can have more than one type, you can use a single pipe | to separate two IDL types.

For example:

  • If I can have a byte or long: Byte | Long

  • If I can have a hash or dictionary with numbers as values: Hash<Number> | Dictionary<Number>

Union types will, when interacted with, provide hover help and auto complete for each type.

Task Types

When using types for ENVI and IDL tasks, we have a shorthand notation that is easier to read.

It also has a special case where, to specify more thank one type of task, we use the "|" operator with another task.

Here's some examples

idl
;+
; :Arguments:
;   a: in, required, IDLTask<MyTask>
;     First argument
;   b: in, required, ENVITask<BuildMosaicRaster>
;     A single task
;   c: in, required, ENVITask<BuildMosaicRaster> | ENVITask<SubsetRaster>
;     More than one kind of task
;
;-
pro mypro, a, b, c
  compile_opt idl2
end

Custom Types

If you create your own object classes or structure definitions, you can use the name of the structure or class as the type. This allows you to have easy access to properties, methods, auto complete, and hover help.

For example:

  • If you want to represent a plot object, you would use Plot
  • If you wanted to represent a raster, you would use ENVIRaster

Advanced Function Return Types

This is a preview type and may change in the future

With IDL it is common that functions return different values based on their inputs.

For functions, when specifying the return type, we have two common approaches for specifying types that get returned:

TypeRepresentsAliases (case insensitive)Examples (case insensitive)
ArrayPromotion<type>If any function argument is an array, then return array of indicated typeNoneArrayPromotion<String>, ArrayPromotion<Int>
TypeOfArg<idx>Indicates the function returns the same type as the zero-based argumentNoneTypeOfArg<0>, TypeOfArg<1>

Here's some examples of how we use ArrayPromotion:

  • For file_basename() the return type is ArrayPromotion<String> because the function returns a scalar string for scalar input or an array of strings for an array of inputs

Here's some examples of how we use TypeOfArg:

  • For transpose() the return type is TypeOfArg<0> because the output type matches the same as the array we are transposing

Licensed under MIT.