Description
So this is sort of a subtly weird thing that can trip you up if you're not careful.
Say you have a python fun like this:
def say_hi(self, to_whom=None, greeting='hi'):
if to_whom:
return(f'{self.name} says {greeting} to {to_whom.name}')
else:
return(f'{self.name} says {greeting}')
Given that to_whom
takes None
in the python, you decide to make it explicit in the OCaml binding.
val say_hi : t -> to_whom:t option -> greeting:string option -> unit -> string
However, this generates code that has the wrong signature
let say_hi t ~to_whom ~greeting () =
let callable = Py.Object.find_attr_string t "say_hi" in
let kwargs =
filter_opt
[
Some ("to_whom", to_pyobject to_whom);
Some
( "greeting",
(function Some x -> Py.String.of_string x | None -> Py.none)
greeting );
]
in
Py.String.to_string
@@ Py.Callable.to_function_with_keywords callable [||] kwargs
That sig is val say_hi : t -> to_whom:t -> greeting:string option -> unit -> string
.
To make that arg actually optional with t
, you would have to do this instead.
val say_hi2 : t -> ?to_whom:t -> greeting:string option -> unit -> string
Note that this problem is only there for t option
and custom option eg Doc.t option
.
Fixing it
It's not straightforward to fix as t option
as an argument passed to a python function and t option
as a return type of an OCaml function need to be treated differently (and that depends on the --of-pyo-ret-type
flag).
Short term fix is to document the weirdness and give an error when users try to use t option
in this way. Currently, the bindings will be generated and you won't know something is wrong until you try to build it.
Long term is to actually handle t option
properly as an arg and also properly as a return type.