Argentum Objects
got two methods: getHash
and equals
. They look much like Java, but there are multiple nuances.
Hash-codes
- The default
Object.getHash
simply returns hash-code based on the object's address. Since Argentum never moves object in memory (no GC) this hash-code is stable and unique for the duration of object's lifetime. And also they are crazy fast. So the actual reason to override thegetHash
method in your class is when your objects must be differentiated by content, not by instance address (best example is Strings). - Argentum objects can be frozen or mutable, and for frozen objects it is guaranteed, that their hash-codes never change. That's why Argentum runtime evaluates hash-code for such objects exactly once.
- The cached hash-value is stored inside the object's header. All mutable objects already have a field that holds the parent pointer. Since this field is not used for shared-frozen objects, it has got another role - hash-value cash). So this cash costs nothing.
- There is a function
sys_hash(*Object) int
that can be called only on frozen objects.- It checks if hash already cached, and if it is, returns it immediately.
- If not, it calls Object.getHash and stores its result in the object header for the future use.
- So do call it wherever you need a frozen object's hash. Usually it's as fast as a single memory read.
- You can directly call
Object.getHash
, and it's your only option for mutable objects, and this is totally reasonable, b/c these objects can be modified and as such their hash-codes must be recalculated every time.
Comparisons
- You don't need to manually call
equals
method, because Argentum has a built-in comparison operatora == b
. - For optional pointer types this operator handles null/empty values.
- For non-null pointers it compares pointers and immediately returns true if they point to the same object.
- For pointers to objects of different runtime types it immediately returns false.
- When called on shared-frozen objects, it checks for stored hash values and immediately returns false on their mismatch.
- So it actually calls the
Object.equals
method only:- for objects at different addresses,
- if they are non-nulls,
- and if they are of the same type,
- and:
- if they are mutable,
- or if they have no cached hash-values
- or if their hashes matched.
- In another words:
- you don't have to add these checks in your
equals
implementation, - the actual
equals
method is called not that frequently.
- you don't have to add these checks in your
- The default
Object.equals
always returnsfalse
, so by default objects get compared by addresses. And for most classes it's the best way of comparison. - Standard
String.equals
compares string bytes.
String literals
- Compiler combines the same string literals and stores them once, regardless of their module of origin.
- This reduces the executable size.
- This makes their comparisons as fast as a simple pointer-to pointer comparison.
- Compiler calculates hashes for all literal strings at compile time and stores them in the object image in the data segment. So all hash-related lookups by literal strings, all searches, and comparisons are performed at the maximum possible speed.