Search code examples
ffireasonbucklescript

Accessors name conflict trying to create a binding


I'm trying to create a binding for an existing javascript library but I'm getting an error when I try to use the property access function.

[@bs.deriving abstract]
type objA = {
  prop1: string,
  prop2: string,
  prop3: string,
};

[@bs.deriving abstract]
type objB = {
  prop2: string,
  prop4: string,
};

[@bs.module "myLib"] external getObjA: (unit) => objA = "";
[@bs.module "myLib"] external getObjB: (unit) => objB = "";

let obj = getObjA();
prop2Get(obj) |> Js.log
// ------^^^
// Error: This expression has type objA but an expression was expected of type objB

I know that both objects have the same property name, so the generated function prop2Get(...) is being overridden. What is the solution for this case?


Solution

  • You need to namespace them. In OCaml/Reason the method of namespacing is to put them in separate modules. Specifically,

    module ObjA = {
      [@bs.deriving abstract] type t = {
        prop1: string,
        prop2: string,
        prop3: string,
      };
    
      [@bs.module "myLib"] external get: (unit) => t = "getObjA";
    };
    
    module ObjB = {
      [@bs.deriving abstract] type t = {
        prop2: string,
        prop4: string,
      };
    
      [@bs.module "myLib"] external get: (unit) => t = "getObjB";
    };
    

    Now, the accessors are also namespaced by their type's module:

    () |> ObjA.get |> ObjA.prop2Get |> Js.log;
    

    The nice thing is that since the module name is used as part of the overall name, you don't need to repeat things in the names, like getObjA, getObjB.