> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superoffice.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Generic data type

Generic is the base type of all other intrinsic CRMScript data types. Any variable can be up-casted to Generic.

There's a close connection between Generic and [structs][1]:

* simpler iteration of variables (struct members)
* easier to access and set new variables in structs
* possible to change which variables are members without having to hard-code each field

By using this datatype, especially with structs, you can limit the amount of code. You won't have to create as many duplicate functions to handle different types - simply place all logic inside 1 function and let it act accordingly to the type.

<Note>
  You can create arrays of any data type to store more than one value at the same time like this: `String[] s1;`. For a given array, all items must be of the same type. Read more about [looping and accessing array items][1] in the fundamentals section.
</Note>

[1]: ../../fundamentals/arrays

## Type and value

### String getTypeName(Generic generic)

`getTypeName()` returns the type of a variable.

```crmscript! theme={null}
printLine(getTypeName(getCurrentDateTime()));
```

### Generic getGenericValue(String name)

`getGenericValue()` returns a variable from the run-time environment given its name and independent of its type.

```crmscript! theme={null}
Integer age = 42;
Generic g = getGenericValue("age");
printLine(GenericToInteger(g).toString());
```

<Note>
  If the variable name is unknown, an [exceptions][2] is thrown.
</Note>

## Down-casting

You can convert a Generic variable to these basic types.

* Bool GenericToBool(Generic generic)
* Integer GenericToInteger(Generic generic)
* Float GenericToFloat(Generic generic)
* String GenericToString(Generic generic)
* DateTime GenericToDateTime(Generic generic)
* Date GenericToDate(Generic generic)
* Time GenericToTime(Generic generic)
* TimeSpan GenericToTimeSpan(Generic generic)
* Byte GenericToByte(Generic generic)
* Generic\[] GenericToArray(Generic generic)

Together with `getTypeName()`, these methods can be used to create an explicit typed variable.

```crmscript theme={null}
Generic g = getCurrentDateTime();
if (getTypeName(g) == "DateTime") {
  DateTime dt = GenericToDateTime(g);
}

```

## Generic and arrays

### Integer getTypeDimensions(Generic generic)

`getTypeDimensions()` returns the number of array dimensions for a variable. The argument is automatically up-casted to a Generic.

```crmscript! theme={null}
Integer[][] i;
printLine(getTypeDimensions(i).toString());

```

<Note>
  This is the number of dimensions in, **not the length** of, the array!
</Note>

## Generic and structs

The following examples build on this Person struct:

```crmscript theme={null}
struct Person {
  String name;
  Integer age;
};
```

### Bool typeIsStruct(Generic generic)

`typeIsStruct()` checks whether a variable is a struct.

Check whether a variable is a struct or not. The argument is automatically up-casted to a Generic.

```crmscript! theme={null}
struct Person {
  String name;
  Integer age;
};

Person p;
if (typeIsStruct(p)) {
  printLine("10-4");
}
```

### String\[] getStructMembers(String name)

`getStructMembers()` returns the variable names of a struct given its name.

<Note>
  This is the names, **not the actual values**. To get those, call `getGenericValue()` using the member names.
</Note>

```crmscript! theme={null}
struct Person {
  String name;
  Integer age;
};

Person p;

String[] members = getStructMembers(getTypeName(p));

foreach (String s in members) {
  printLine(s);
}
```

### Generic getGenericValue(Generic struct, String name)

A variant of `getGenericValue()` that returns a variable from the run-time environment **inside a struct** given its name and independent of its type.

```crmscript theme={null}
Person p;
p.age = 42;
Generic g = getGenericValue(p, "age");

```

<Note>
  If the variable name is unknown or you're not referencing a struct, an [exceptions][2] is thrown.
</Note>

### String convertGenericToString(Generic generic)

`convertGenericToString()` returns the string representation of a variable.  The argument is automatically be up-casted to a Generic.

This works for all **basic** types. Complex types might can't be serialized as easy, and might not support this conversion. In that case, they'll return "\[complex]".

```crmscript! theme={null}
Integer age = 42;
String s = convertGenericToString(age);
printLine(s);
```

### Void setGenericFromString(Generic generic, String value)

`setGenericFromString()` sets the value of a variable from a string.

It supports only basic types. Attempting to set an array or a complex type will throw an exception.

The value **must be formatted** according to the constructor of that type. Specifically, Date, DateTime, and Time must be on the YYYY-MM-DD HH:MI:SS format.

<Tip>
  In combination with `getStructMembers()` and `getGenericValue()`, this function can be used to iterate a struct and set all its members programmatically instead of having to explicit hard-code each of them.
</Tip>

### Print contents of struct for extra table

In this scenario, we've created an extra table called **Building**. It has multiple extra fields of different types.

```crmscript theme={null}
Struct Building {
  Integer id;
  String name;
  String address;
  Date acquired;
  Date next_service;
  Integer floors;
  Bool has_janitor;
  Bool is_rented;
  Float value;
  Time opens;
  Time closes;
};
```

So instead of defining a `print()` method in the struct, with 1 printLine() for every member, and manually converting each value to a string like this:

```crmscript theme={null}
Void print() {
  printLine("id: " + this.id.toString());
  printLine("name: " + this.name);
  //...
  printLine("value: " + this.value.toString(2));
  //...
}
```

You can define a `printGeneric()` method and leverage the Generic struct methods:

```crmscript theme={null}
Void printGeneric() {
  String[] members = getStructMembers("Building");
  foreach(String field in members) {
    Generic g = getGenericValue(this, field);
    printLine(field + ": " + convertGenericToString(g));
  }
}
```

### Parse from Json to Struct

In this scenario, still using our **Building** extra table, we'd like to to parse from Json into a struct.

**Without Generic:**

```crmscript theme={null}
Building Building(String json) {
  Building b;
  XMLNode root = parseJSON(json);

  b.id = root.getValueFromPath("id").toInteger();
  b.name = root.getValueFromPath("name");
  //...
  b.is_rented = root.getValueFromPath("is_rented").toBool();
  b.value = root.getValueFromPath("id").toFloat();
  //...
  return b;
}
```

**With Generic:**

```crmscript theme={null}
Building BuildingGeneric(String json) {
  Building b;
  XMLNode root = parseJSON(json);

  String[] members = getStructMembers("Building");

  foreach(String field in members) {
    Generic g = getGenericValue(b, field);
    String value = root.getValueFromPath(field);
    setGenericFromString(g, value);
  }

  return b;
}
```

Notice how this method doesn't have to know anything about the Building table. No variable names, no data types, and not even how many there are.

### Load from database to Struct

In this scenario, still using our **Building** extra table, we'd like to load data from the database into a struct.

**Without Generic:**

```crmscript theme={null}
Building Building(Integer id) {
  Building b;

  SearchEngine se;
  se.addField("y_building.id");
  //...

  se.addCriteria("y_building.id", "Equals", id.toString());
  se.execute();

  if(!se.eof()) {
    b.id = se.getField("y_building.id").toInteger();
    //...
  }

  return b;
}
```

**With Generic:**

```crmscript theme={null}
Building BuildingGeneric(Integer id) {
  Building b;
  SearchEngine se;
  String[] members = getStructMembers("Building");

  foreach(String field in members) {
    se.addField("y_building." + extraFieldName(field));
    se.addCriteria("y_building.id", "Equals", id.toString());
    se.execute();
  }

  if(!se.eof()) {
    foreach(String field in members) {
      Generic g = getGenericValue(b, field);
      String value = se.getField("y_building." + extraFieldName(field));
      setGenericFromString(g, value);
    }
  }
  return b;
}
```

[1]: ../fundamentals/structs

[2]: ../fundamentals/try-catch


## Related topics

- [SuperOffice.WebApi.Data.DocTmplType](/en/api/reference/webapi/SuperOffice.WebApi.Data.DocTmplType.md)
- [SuperOffice.WebApi.Data.BlobLinkType](/en/api/reference/webapi/SuperOffice.WebApi.Data.BlobLinkType.md)
- [Generic](/en/automation/crmscript/reference/CRMScript.Native.Generic.md)
- [GenericSearch](/en/automation/crmscript/reference/CRMScript.Native.GenericSearch.md)
- [Namespace CRMScript.Native](/en/automation/crmscript/reference/CRMScript.Native.md)
- [Void](/en/automation/crmscript/reference/CRMScript.Global.Void.md)
