ocaml-ppx / ppx_deriving_yojson

A Yojson codec generator for OCaml.
MIT License
156 stars 46 forks source link

Possible name clash with String? #81

Closed jnfoster closed 2 years ago

jnfoster commented 5 years ago

If I put the following code in a file tester.p4,


module MyString = struct
  type t = string * int [@@deriving yojson]
end

module MySomething = struct
  type t = MyString.t * bool [@@deriving yojson]
end

let v1 : MyString.t = "hello", 42
let v2 : MySomething.t = v1, true

let () = print_endline (Yojson.Safe.to_string (MySomething.to_yojson v2))

and compile it in a directory with this Dune file,

(executable
 (name tester)
 (libraries ppx_deriving_yojson.runtime yojson)
 (preprocess (pps ppx_deriving_yojson)))

I get a binary that works as expected:

% dune build --profile release tester.exe
% _build/default/tester.exe 
[["hello",42],true]

However, if I rename the MyString module to String,

module String = struct
  type t = string * int [@@deriving yojson]
end

module MySomething = struct
  type t = String.t * bool [@@deriving yojson]
end

let v1 : String.t = "hello", 42
let v2 : MySomething.t = v1, true

let () = print_endline (Yojson.Safe.to_string (MySomething.to_yojson v2))

and recompile, I get an error:

File "_none_", line 1:
Error: Unbound value String.to_yojson

I understand that PPX-based rewriters often do something special with base types and other built-ins, but I'm surprised this doesn't work...

whitequark commented 5 years ago

This is because Pervasives and stdlib modules are injected explicitly into the rewritten code, so that the internal ppx rewriter operations (like printf or ==) would be hygienic. I think the rewritten code can be massaged to make your use case work, but I'm afraid I don't have time to do it myself.