Hashdecl: Type-Safe Hash Declarations

# Type-Safe Hashes Overview

The `hashdecl` keyword allows for type-safe hashes to be declared; they can then be instantiated with the new operator, the cast<> operator, or with variable implicit construction.

# hashdecl Declaration Syntax

`hashdecl` hashdecl_identifier `{`
member_type `` member_name `[=` initialization_expression `];`
[...]
`}`

At least one member must be defined; it's not possible to declare an empty type-safe hash.

Example
  hashdecl MyHash {
  int i = 1;
  string code = "other";
  }

Note
  - a `hashdecl` may not have the name `"auto"`, this name has a special meaning in complex types
  - Each Qore type has a "pseudo-class" associated with it; for hashes the type is <hash>; methods from the data type's "pseudo-class" can be run on any value of that type.

# Type-Safe Hash Creation

When type-safe hashes are created, the hash is automatically populated with the values given by the initialization expressions in the `hashdecl` declaration (if any).

It is possible to override these declarations by passing a hash to be used for initialization; this can be passed the single optional argument to the type-safe hash initialization as in the following examples:

Examples
  # type-safe hash declaration
  hashdecl Container {
  int i = 1;
  }
  # immediate value with implicit construction: default values are assigned from the declaration
  auto ah1 = hash<Container>{};
  # immediate value with implicit construction: default values are assigned from the declaration
  auto ah2 = <Container>{};
  # immediate value with implicit construction: overrides the "i" member's initial value
  auto ah3 = <Container>{"i": 2};
  # implicit construction: default values are assigned from the declaration
  hash<Container> h1();
  # implicit construction: overrides the "i" member's initial value
  hash<Container> h2(("i": 2));
  # "new" construction: default values are assigned from the declaration
  hash<Container> h3 = new hash<Container>();
  # "new" construction: overrides the "i" member's initial value
  hash<Container> h4 = new hash<Container>(("i": 2));

In such cases, the initialization expression for the members being overridden is never executed and the supplied value is used instead.

Note that it's illegal to assign a value to an unassigned lvalue declared as a typed hash; in such cases a `HASHDECL-IMPLICIT-CONSTRUCTION-ERROR` exception is thrown as in the following example:

hash<Container> c;
# the following line will result in a HASHDECL-IMPLICIT-CONSTRUCTION-ERROR exception being thrown
c.i = 2;

To address this, ensure that your typed hash lvlaues are always initialized before assignment as in the following example:

hash<Container> c();
c.i = 2;

See also
  - Variable Implicit Construction
  - New Value Operator (new)

# Type-Safe Hash Type Compatibility

Type-safe hashes can be assigned to any variable that accepts an untyped hash, however variables declared as a particular type-safe hash (ex: `hash<MyHash>`) can only be assigned values of the given type; use the cast<> operator to convert untyped hashes or type-safe hashes of another type to the target type for assignment.

Example:
  hashdecl Container1 {
  int i = 1;
  string str = "value";
  }
  hashdecl Container2 {
  int i = 2;
  bool check = False;
  }
  hash<Container1> c1();
  # afterwards c2 will be: {i: 1, check: False}
  hash<Container2> c2 = cast<hash<Container2>>(cast<hash>(c1 - "str"));
  hash h = ("i": 3, "other": "x");
  # afterwards c3 will be: {i: 3, check: False}
  hash<Container2> c3 = cast<hash<Container2>>(cast<hash>(h - "other"));

See also
  cast<>

# Comparison of Type-Safe Hashes and Objects

Type-safe hashes are similar to objects in that they have members, but there are some important differences as follows:

- type-safe hashes are always passed by value whereas objects are always passed by reference
- object classes can have methods, type-safe hashes cannot
- object classes allow for class members to have access restrictions; type-safe hashes are made up exclusively of public members
- object classes can participate in a hierarchy, type-safe hashes cannot