4

I have an issue with the OCaml compiler I can't explain myself. The following code won't compile:

open Postgresql

let get_nodes conn =
  ignore (conn#exec "SELECT * FROM node_full")

let () =
  let c = new connection () in
  ignore (get_nodes c)

It gives the following error:

File "test.ml", line 8, characters 20-21:
Error: This expression has type Postgresql.connection
       but an expression was expected of type < exec : string -> 'a; .. >
       Types for method exec are incompatible

(Line 8 is the last line)

But the following piece of code compiles without error (and works as expected, in the full version of the code):

open Postgresql

let get_nodes (conn:connection) =
  ignore (conn#exec "SELECT * FROM node_full")

let () =
  let c = new connection () in
  ignore (get_nodes c)

The only difference is that I specified the type of the conn parameter in the get_nodes function.

Does someone understand what is going on here ? This is the first time I have to specify a type myself in order to make the code work, and I am a daily OCaml user ...

Additionnaly, I don't see, in the error message, why the types involved are not compatible, here is the type of the exec function:

method exec :
  ?expect:Postgresql.result_status list ->
  ?params:string array ->
  ?binary_params:bool array ->
  string -> Postgresql.result

and the type of the get_all function from Postgresql.result:

method get_all : string array array

Happy new year !

Fabian Pijcke
  • 2,920
  • 25
  • 29
  • possible duplicate : http://stackoverflow.com/questions/17224901/optional-argument-in-a-method-with-ocaml – nlucaroni Dec 31 '13 at 19:58

1 Answers1

3

Well, nlucaroni has pointed out that this has been answered in a simpler form at Optional argument in a method with ocaml, but here's a short description of what I got by reading that page.

Your call to exec gives it the inferred type string -> 'a. This isn't at all like the type of the exec method of a Postgresql connection, which has three optional parameters. One way to fix it is to do what you did: declare the type of the conn parameter. You could also just declare the optional parameters of the exec method, maybe something like this:

ignore (
    (conn#exec :
        ?expect: 'a ->
        ?params: 'b ->
        ?binary_params: 'c ->
        string -> 'd) "SELECT * FROM node_full"
 )
Community
  • 1
  • 1
Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • So this is the least information one has to give to the compiler so that it can infer the type ? I'm still surprised, in my opinion those types (with or withtout optional parameters) are compatible, and the compiler should accept it as such (cf. the compiler error message). Doesn't this make sense ? – Fabian Pijcke Jan 01 '14 at 21:31
  • I think the key is that the type `?myoption: 'a -> string -> 'b` isn't subsumed by `string -> 'b`. Just because you're not passing any of the optional parameters in your call doesn't mean the types work out. You could imagine a type system where your program is correct, but not in OCaml as it stands. (Note: I'm not a type theorist, just an avid practitioner.) – Jeffrey Scofield Jan 01 '14 at 21:54