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 [inherits parent_hashdecl] {
member_type member_name [= initialization_expression];
[...]
}
At least one member must be defined in the hashdecl or inherited from a parent; 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
hashdecl Container {
int i = 1;
}
auto ah1 = hash<Container>{};
auto ah2 = <Container>{};
auto ah3 = <Container>{"i": 2};
hash<Container> h1();
hash<Container> h2(("i": 2));
hash<Container> h3 = new hash<Container>();
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;
c.i = 2;
To address this, ensure that your typed hash lvalues are always initialized before assignment as in the following example:
- See also
-
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();
hash<Container2> c2 = cast<hash<Container2>>(cast<hash>(c1 - "str"));
hash h = ("i": 3, "other": "x");
hash<Container2> c3 = cast<hash<Container2>>(cast<hash>(h - "other"));
- See also
- cast<>
Hashdecl Inheritance
Type-safe hashes support single inheritance, allowing child hashdecls to inherit all members from a parent hashdecl. This is achieved using the inherits keyword.
- Example:
hashdecl BaseInfo {
string name;
int id;
}
hashdecl ExtendedInfo inherits BaseInfo {
date created;
*string description;
}
hash<ExtendedInfo> ext = <ExtendedInfo>{
"name": "test",
"id": 123,
"created": now(),
};
printf("name: %s, id: %d\n", ext.name, ext.id);
Inheritance Rules
- Single inheritance only: A hashdecl can inherit from at most one parent hashdecl
- All members public: All inherited members are public (hashdecls have no access modifiers)
- No member shadowing: Child hashdecls cannot declare a member with the same name as a parent member; this will result in a parse error
- Circular inheritance: Circular inheritance (A inherits B, B inherits A) is detected and reported as a parse error
- Member initialization: Parent members are initialized first, followed by child members
Inheritance Type Compatibility
Values of a derived hashdecl type can be assigned to variables of the parent hashdecl type:
hashdecl Parent { int x; }
hashdecl Child inherits Parent { int y; }
hash<Child> c = <Child>{"x": 1, "y": 2};
hash<Parent> p = c;
printf("x: %d\n", p.x);
- Note
- The reverse is not true: assigning a parent hashdecl value to a child hashdecl variable requires an explicit 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 support multiple inheritance, type-safe hashes support single inheritance only