# Encapsulation and Includes

We mentioned above that you might wonder why we didn't write this simpler definition of of_list:

  let of_list lst = lst


The reason is that includes must obey encapsulation, just like the rest of the module system. ListSetDups was sealed with the module type Set, thus making 'a t abstract. So even ListSetDupsExtended is forbidden from knowing that 'a t and 'a list are synonyms.

A standard way to solve this problem is to rewrite the definitions as folllows:

module ListSetDupsImpl = struct
type 'a t   = 'a list
let empty   = []
let mem     = List.mem
let add x s = x::s
let elts s  = List.sort_uniq Stdlib.compare s
end

module ListSetDups : Set = ListSetDupsImpl

module ListSetDupsExtended = struct
include ListSetDupsImpl
let of_list lst = lst
end


The important change is that ListSetDupsImpl is not sealed, so its type 'a t is not abstract. When we include it in ListSetDupsExtended, we can therefore exploit the fact that it's a synonym for 'a list.

What we just did is effectively the same as what Java does to handle the visibility modifiers public, private, etc. The "private version" of a class is like the Impl version above: anyone who can see that version gets to see all the exposed "things" (fields in Java, types in OCaml), without any encapsulation. The "public version" of a class is like the sealed version above: anyone who can see that version is forced to treat the "things" (fields in Java, types in OCaml) as abstract, hence encapsulated.