I have a question that can be explained with this example (and some variations later):
module M1 = struct
let () = print_endline "Before class"
class c =
let () = print_endline "Class init" in
object end
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
The manual currently specifies that the "Class init" line should be evaluated between the two other print statements, and nothing printed when evaluating o1 and o2 (see https://ocaml.org/manual/5.2/classes.html#sss:class-localdefs). The implementation mostly follows that.
However, the implementation is quite complex and in particular, adding a local open can trick it into believing that the let bindings are not toplevel anymore:
module M2 = struct
let () = print_endline "Before class"
class c =
let open Unit in
let () = print_endline "Class init" in
object end
let () = print_endline "After class"
let o1 = new c (* Prints here *)
let o2 = new c (* Prints here again *)
end
I will propose a PR that fixes this issue, but I'd like to know why we even bother with that corner case: making everything under the class definition evaluated at object creation time seems reasonable to me and easier to implement and specify.
In particular, in the following definitions M4 and M5 behave like M2 (printing pushed at object creation time) despite being mostly equivalent to M3 and M1 respectively (which both print at class creation time):
module M3 = struct
class with_param p = object end
let () = print_endline "Before class"
class c =
let () = print_endline "Class init" in
with_param ()
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
module M4 = struct
class with_param p = object end
let () = print_endline "Before class"
class c =
(let () = print_endline "Class init" in
with_param)
()
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
module M5 = struct
let () = print_endline "Before class"
class c =
(let () = print_endline "Class init" in
object end : object end)
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
Finally, the part in the manual about class application (https://ocaml.org/manual/5.2/classes.html#sss:class-app) is either wrong or misleading. The arguments passed to the class constructor are always evaluated at object creation time, not immediately, as can be seen on the following examples (in both cases, "Class param" is printed when creating the objects):
module M3_app = struct
class with_param p = object end
let () = print_endline "Before class"
class c =
let () = print_endline "Class init" in
with_param (print_endline "Class param")
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
module M4_app = struct
class with_param p = object end
let () = print_endline "Before class"
class c =
(let () = print_endline "Class init" in
with_param)
(print_endline "Class param")
let () = print_endline "After class"
let o1 = new c
let o2 = new c
end
Cc @garrigue, our main reference on objects and classes.
I have a question that can be explained with this example (and some variations later):
The manual currently specifies that the
"Class init"line should be evaluated between the two other print statements, and nothing printed when evaluatingo1ando2(see https://ocaml.org/manual/5.2/classes.html#sss:class-localdefs). The implementation mostly follows that.However, the implementation is quite complex and in particular, adding a local open can trick it into believing that the let bindings are not toplevel anymore:
I will propose a PR that fixes this issue, but I'd like to know why we even bother with that corner case: making everything under the class definition evaluated at object creation time seems reasonable to me and easier to implement and specify.
In particular, in the following definitions
M4andM5behave likeM2(printing pushed at object creation time) despite being mostly equivalent toM3andM1respectively (which both print at class creation time):Finally, the part in the manual about class application (https://ocaml.org/manual/5.2/classes.html#sss:class-app) is either wrong or misleading. The arguments passed to the class constructor are always evaluated at object creation time, not immediately, as can be seen on the following examples (in both cases,
"Class param"is printed when creating the objects):Cc @garrigue, our main reference on objects and classes.