What's the use case of `val` field in class type?

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, like v , 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.

3 Likes

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.