.. _jython-type-usage:

# Jython type usage

When you define a Python function that will be used by RiskScape, the
inputs (i.e. *argument-types*) and output (i.e. *return-type*) must be compatible
with the RiskScape type system.

.. warning::
    This page describes an old way of declaring types for a Jython function,
    and the content is only included for historic reference.
    We recommend following the :ref:`python-functions` examples to define function types
    within your INI file.

These function input and output types can either be
built-in RiskScape types (e.g. `Types.TEXT`), or more complex types you have
defined in an INI file.

Within the Python function itself, you can simply use the native Python
types and classes as local variables like normal. You only need to specify
RiskScape-compatible types so that RiskScape will know what type of arguments
the function expects, and what type of value will be returned.

## Simple cases

To use a built-in RiskScape simple type as an argument or return-type for a Python function,
you would use something like:

```python
from nz.org.riskscape.engine.types import Types

ARGUMENT_TYPES = [ Types.TEXT, Types.INTEGER, Types.BOOLEAN, Types.GEOMETRY ]
RETURN_TYPE = Types.FLOATING
```

When a function uses a user-defined type from an INI file, you can simply
refer to that type by name. For example:

```python
ARGUMENT_TYPES = ['my-custom-type']

RETURN_TYPE = 'some-other-type'
```

## Complex types

In most cases, you should be able to write versatile Python functions
by just using the simple RiskScape types.
When your functions use more complex types, it's generally easiest to
define them in an INI file (i.e. `types.ini`).

However, any complex types you can define in an INI file can also be defined
in Python code. This approach might be useful if you wanted to share your function
with other people, without them having to modify their INI files in order to use it.

### Structs

Defining a new Struct within your Python code will look something like:

```python
from nz.org.riskscape.engine.types import Types, Struct

MY_STRUCT_TYPE = Struct.of('key1', Types.TEXT) \
                 .and('key2', Types.INTEGER) \
                 .and('key3', Types.FLOATING)
```

### Enumerations

An example of declaring a new enumeration type within your Python code:

```python
from nz.org.riskscape.engine.types import Types, Enumeration

MY_ENUM_TYPE = Enumeration.oneBased("wood", "steel", "concrete")
```

### Lists

To declare a list of geometry items, use:

```python
from nz.org.riskscape.engine.types import Types, RSList

MY_TEXT_TYPE = RSList(Types.GEOMETRY)
```

### Nullable

To declare a type as nullable, you need to get the underlying type that's being wrapped.
You can use `typeset.getLinkedType()` to lookup a user-defined type.
If the underlying type is a built-in RiskScape simple type, then the lookup is unnecessary.

```python
from nz.org.riskscape.engine.types import Types, Nullable

MY_NULLABLE_TYPE = Nullable.of(typeset.getLinkedType('other-type'))
SIMPLE_NULLABLE_TYPE = Nullable.of(Types.FLOATING)
```

### Within range

Use the below example to specify that a number must be within a given range.
This is the equivalent of using `range()` in an INI file.

```python
from nz.org.riskscape.engine.types import Types, WithinRange

MY_RANGED_TYPE = WithinRange(Types.INTEGER, 0, 10)
```

### Within set

Use the below example to specify that a type must fall within a given set of values.
This is the equivalent of using `set()` in an INI file.

```python
from nz.org.riskscape.engine.types import Types, WithinSet

MY_SET_TYPE = WithinSet(Types.TEXT, {'option-1', 'option-2', 'option-n'})
```
