How do I implement hash functions for arbitrary record types in ReScript? - reason

I'm exploring ReScript for the first time. I want to build a hashmap using a record type as my key type, and I'm looking for guidance on implementing the hash function.
Here's my ReScript code:
type pointer = { id: string, table: string, spaceId: option<string> }
module PointerHash = Belt.Id.MakeHashable({
type t = pointer
let hash = a => 0 /* How do I implement this? */
let eq = (a, b) =>
a.id == b.id &&
a.table == b.table &&
switch (a.spaceId, b.spaceId) {
| (Some(aid), Some(bid)) => aid == bid
| _ => false
}
})
I looked through the docs and searched online but didn't find any guidance about how to implement the hash function.
In other programming languages like eg Java that expect you to implement hashCode(), there are ubiquitous tools to support composing existing hash functions.
class Pointer {
public final id: String
public final table: String
public final #Nullable spaceId: String
/* omitting constructor, etc */
#Override
public int hashCode() {
// Standard helper for implementing hashCode()
return Objects.hash(this.id, this.table, this.spaceId);
}
}
I looked at the implementation of Belt.HashMapString to see if there were any hints, and it looks like HashMapString uses caml_hash_mix_string:
external caml_hash_mix_string : seed -> string -> seed = "caml_hash_mix_string"
external final_mix : seed -> seed = "caml_hash_final_mix"
let hash (s : key) =
final_mix (caml_hash_mix_string 0 s )
What is the most idiomatic way to access and compose "hash mix" functions? Are these available with a nice interface from ReScript?

There's a built-in polymorphic hash function in the Hashtbl module:
let hash: 'a => int
This comes from the OCaml standard library which ReScript inherits. You can find the documentation there: https://docs.ocaml.pro/html/LIBRARY.stdlib#ocaml-base-compiler.4.10.0/Stdlib/Hashtbl/index.html#val-hash

Related

Dynamic Type Casting in Dart/Flutter

I am in the middle of writing a library to dynamically serialise/deserialise any object in Dart/Flutter (Similar in idea to Pydantic for Python). However, I am finding it impossible to implement the last component, dynamic type casting. This is required in order convert types from JSON, such as List to List (or similar). The types are retrieved from objects using reflection.
The below is the desired implementation (though as far as I understand this is not possible in Dart).
Map<String, Type> dynamicTypes = {"key": int };
// Regular casting would be "1" as int
int value = "1" as dynamicTypes["key"];
Is there some workaround which makes this possible to implement? Or have I reached a dead end with this (hence no other dynamic serialisation/deserialisation package already exists).
Conducting more research into this issue, it seems in Dart's current implementation this is impossible due to runtime reflection being disabled as referenced here in the official docs.
There are ongoing discussions about the support for this and the associated package dart:mirrors here on GitHub, but so far though there is some desire for such functionality it is highly unlikely to ever be implemented.
As a result, the only options are:
Use code generation libraries to generate methods.
Manual serialisation/deserialisation methods.
Implement classes with complex types such as lists and maps to be dynamic, enabling (all be it limited) automatic serialisation/deserialisation.
Your question does not specify how exactly dynamicTypes is built, or how its key is derived. So there is perhaps a detail to this that is not clear to me.
But what about something like this?
class Caster<T> {
final T Function(String) fromString;
Caster(this.fromString);
}
void main() {
Map<String, Caster> dynamicTypes = { "key": Caster<int>((s) => int.parse(s)) };
int v = dynamicTypes['key']!.fromString('1');
print(v);
}
Or, if you have the value as a dynamic rather than a string:
class Caster<T> {
T cast(dynamic value) => value as T;
}
void main() {
Map<String, Caster> dynamicTypes = { "key": Caster<int>() };
dynamic a = 1;
int v = dynamicTypes['key']!.cast(a);
print(v);
}
Or even more succinctly:
void main() {
dynamic a = 1;
int v = a;
print(v);
}

Drools - extract value inside a map and assign - error : unable to resolve method using strict-mode

Thanks to #roddy for his answer to my query here
Copy pasting from earlier to set the context :
here is my data structure :
public class Premium{
private Map<String,Map<String,String>> valuesMap = new HashMap<String,Map<String,String>>();
public Map<String, Map<String, String>> getValuesMap() {
return valuesMap;
}
}
Sample values that will be present inside this 'valuesMap' :
Map<String,String> m1= new HashMap<String,String>();
m1.put("death","100");
m1.put("income","50");
valuesMap.put("Male",m1);
valuesMap.put("Female",m2);
....
Thanks to #Roddy now I can extract the map 'm1' embedded within 'valuesMap' for "Male"
rule "rule#7 testing me 001 "
when
// below line extracts 'valuesMap' from Premium object
$pr:Premium($masterMap:valuesMap)
// now have a handle to the embedded map for 'Male'
Map( $male: this["Male"] ) from $masterMap
// defining an object in which I want to populate the value from map obtained for male
$rulesResponse:RulesResponse();
then
System.out.println("rule#7 map " + $map);
// this is where in below code it is failing
$rulesResponse.abc = $innerMap.get("income");
end
when I am trying to extract the string from map against key 'income' and assign it to the 'RulesResponse' object it fails with :
[Error: unable to resolve method using strict-mode: java.lang.Object.get(java.lang.String)]
[Near : {... nse.abc = $innerMap.get("income"); ....}]
The response object is a simple POJO with getter and setter for attribute : abc
public class RulesResponse {
private String abc = "";
public String getAbc() {
return abc;
}
public void setAbc(String abc) {
this.abc = abc;
}
If I try and assign a hard coded value - it works and also reflects after the rule is executed
// this works
$rulesResponse.abc = "hard coded value";
When you get this["Male"] out of the map, it's an Object, not anything typed. It's basically due to type erasure -- Map<String, ?>.
You can get "income" out by doing Map( $income: this["income"]) from $male. Of course, now $income will too also be an Object so you'll need to cast it again. Could be as simple as a (String)$income on the right-hand side, or a $incomeStr: String() from $income on the left.
rule "Example"
when
$pr: Premium( $masterMap: valuesMap != null )
Map( $male: this["Male"] != null ) from $masterMap
Map( $income: this["income"] != null ) from $male
$rulesResponse: RulesResponse()
then
$rulesResponse.abc = (String)$income; // cast as necessary
end
We lose the nested type identity because of type erasure -- you've got a Map<String, ?> which becomes Map<String, Object> in practice.
Strongly suggest using a properly structured POJO instead of a Map as a rule input. Even if your actual code uses these nested maps (bad practice!), you should leverage a transform before calling the rules -- not only will your rules be a lot simpler and easier to work with, but they'll also be much more performant.
Even converting that inner map into an object will make things easier:
class GenderValues {
String death;
String income;
}
class Premium {
Map<String, GenderValues> valuesByGender;
}
Best practice would be to omit the Map entirely.

Using Class<T> as a Map key in Haxe

I'd like to store instances of models in a common provider using their classes or interfaces as a keys and then pop them up by class references. I have written some code:
class Provider {
public function new() { }
public function set<T:Any>(instance:T, ?type:Class<T>) {
if (type == null)
type = Type.getClass(instance);
if (type != null && instance != null)
map.set(type, instance);
}
public function get<T:Any>(type:Class<T>):Null<T> {
return cast map.get(type);
}
var map = new Map<Class<Any>, Any>();
}
...alas, it's even doesn't compile.
Probably I have to use qualified class name as a key rather than class/interface reference? But I'd like to keep neat get function design that takes type as argument and returns object just of type taken, without additional type casting.
Is it possible or should I change my approach to this problem?
The issue of using Class<T> as a Map key come up every so often, here is a related discussion. The naive approach of Map<Class<T>, T> fails to compile with something like this:
Abstract haxe.ds.Map has no #:to function that accepts haxe.IMap<Class<Main.T>, Main.T>`
There's several different approaches to this problem:
One can use Type reflection to obtain the fully qualified name of a class instance, and then use that as a key in a Map<String, T>:
var map = new Map<String, Any>();
var name = Type.getClassName(Main);
map[name] = value;
For convenience, you would probably want to have a wrapper that does this for you, such as this ClassMap implementation.
A simpler solution is to simply "trick" Haxe into compiling it by using an empty structure type ({}) as the key type. This causes ObjectMap to be chosen as the underlying map implementation.
var map = new Map<{}, Any>();
map[Main] = value;
However, that allows you to use things as keys that are not of type Class<T>, such as:
map[{foo: "bar"}] = value;
The type safety issues of the previous approach can be remedied by using this ClassKey abstract:
#:coreType abstract ClassKey from Class<Dynamic> to {} {}
This still uses ObjectMap as the underlying map implementation due to the to {} implicit cast. However, using a structure as a key now fails at compile time:
var map = new Map<ClassKey, Any>();
map[{foo: "bar"}] = value; // No #:arrayAccess function accepts arguments [...]

Invalid initialization of reference type 'Class&' from expression of type 'Class'

Ok guys , so I have a list of objects and I want to sort my list by a boolean function I created .
Function ->
bool funct(Student &s1,Student &s2)
{
return s1.calculMedie()<s2.calculMedie();
}
I got this list:
list<Student*> list;
list.push_back(sx[0]);
list.push_back(sx[1]);
list.push_back(sx[2]);
sx is comming from this declaration-> Student **sx=new Student*[3];
I created 3 objects of the type class Student.
I want to sort them by 'calculMedie()' which is a function that returns their average grade.
double Student::calculMedie()
{
int nr=0;
double s=0;
for(auto i : note)
{
nr++;
s=s+i;
}
return s/nr;}
^ thats how it looks.
And when I tried to do a list.sort(list.begin(),list.end(),funct) it gets me this error : " Invalid initialization of reference type 'Class&' from expression of type 'Class'"
It looks like you mixed std::sort algorithm with list<T>::sort method. List can be sorted only by using its sort method.
There are two overloads of list::sort:
void sort();
template< class Compare >
void sort( Compare comp ); // [2]
if you want to sort by comparator, write as follows:
list<Student*> list;
list.sort (funct);
because list stores pointers to Student, you need to modify signature of funct function, it must takes pointers not references:
bool funct(Student* s1,Student* s2)
{
return s1->calculMedie()<s2->calculMedie();
}
good practice is to pass s1,s2 as pointers to const object, when you change s1,s2 to be const Student* s1, const Student* s2 you need also to make calculMedie as const member function.

C++ std::map look for values but not keys

I have a std::map which maps a structure to a string:
struct st
{
std::string name;
int age;
}
std::map<st, std::string> m_SoundStructList;
Now I want to look in the map based on a string which is the name and get the structure.
std::string lName="Kate"
auto iter = m_SoundStructList.find(lName);
st lStruct=it->fisrt;
Now it is only possible for me to apply find on structure but the strings.
Any help would be appreciated.
You probably have to iterate through the map and use the matching element manually.
For C++11 it would be
for(const auto& p : m_SoundStructList) {
if (p.second.name == "Kate") {
// Do something
}
}