Take this for example:
class type u = object
val x : int
method y : int
end
let f (u : u) = u#x
It gives a type error, since x is not public. Since val
is not public, what is the use case of writing val here?
Thank you in advance.
Take this for example:
class type u = object
val x : int
method y : int
end
let f (u : u) = u#x
It gives a type error, since x is not public. Since val
is not public, what is the use case of writing val here?
Thank you in advance.
The object type is enclosed in angle brackets
< ... >
, containing just the types of the methods. Fields, likev
, are not part of the public interface of an object.
https://dev.realworldocaml.org/objects.html
In short, you need to add method get_x = x
and use the method to access variable fields.
If you ask why would it allows to write val
even it is not pairs of the class interface, it is because it can help constraints the type when otherwise not able to inference the type of a val
field.
It’s needed for inheritance I think:
class a : object
val x : int
method y : int
end = object
val x = 1
method y = x
end
class b = object
inherit a
method z = x
end
If I remove val x
from the class type, I get an error on method z
.
It’s not about inheritence. It’s about encapsulation of member data in the object. Consider the following transcript that contains no use of the inherit
keyword:
# class count = object
val number = 0
method get = number
method succ = {< number = succ number >}
end;;
class count :
object ('a) val number : int method get : int method succ : 'a end
# let c0 = new count;;
val c0 : count = <obj>
# c0#get;;
- : int = 0
# let c1 = c0#succ;;
val c1 : count = <obj>
# c1#get;;
- : int = 1
# c0#get;;
- : int = 0
You can use the mutable
keyword with val
and make the succ
method imperative rather than functional. Either way, the thing to notice about the val
keyword is that it encapsulates the value as member data for the object in a way that a class function parameter does not.
I get the same behavior without val number
in the class type:
# class count : object ('a)
method get : int
method succ : 'a
end = object
val number = 0
method get = number
method succ = {< number = succ number >}
end;;
class count : object ('a) method get : int method succ : 'a end
# let c0 = new count;;
val c0 : count = <obj>
# c0#get;;
- : int = 0
# let c1 = c0#succ;;
val c1 : count = <obj>
# c1#get;;
- : int = 1
# c0#get;;
- : int = 0
In the example I provided, number
is a data member in the class type that has visibility to subclasses that use inherit count
. What you are doing with this class type constraint is erasing the visibility of the number
field in subclasses, but the field is still a data member in the object.