REVISED: Friday, October 3, 2025
OCAML OBJECT-ORIENTED PROGRAMMING (OOP)
(*
ocaml C:\AI2025\objective_1.ml
1. OBJECTIVE: Understand the basics of classes and objects in OCaml.
A 'class' is a blueprint for creating 'objects'. An object is an instance of a class, containing both data (instance variables) and behavior (methods).
*)
(* 'class' is the keyword to define a new class. 'simple_greeter' is the name of our class. *)
class simple_greeter =
object (self) (* 'object' begins the definition of the class's structure. 'self' is a common name for the object itself, allowing it to refer to its own members. *)
(* This is an instance variable. It holds data specific to each object. *)
(* It's initialized to "Hello" for every new object created from this class. *)
val greeting_message = "Hello"
(* 'method' defines a behavior for the object. This method is named 'greet'. *)
(* It takes no arguments and prints the greeting_message to the console. *)
method greet = print_endline greeting_message
end;; (* The 'end' keyword closes the class definition. The ';;' is used in OCaml to mark the end of a top-level phrase. *)
(* --- Creating and Using an Object --- *)
(* 'new' is the keyword used to create an instance (an object) of a class. *)
(* We are creating an object from the 'simple_greeter' class and naming it 'my_greeter_object'. *)
let my_greeter_object = new simple_greeter;;
(* Now, we call the 'greet' method on our newly created object. *)
(* The '#' symbol is used to invoke a method on an object. *)
(* This will execute the code inside the 'greet' method, printing "Hello". *)
my_greeter_object#greet;;
(* Let's define another class to show that objects have their own state. *)
class customizable_greeter (initial_message : string) =
object (self)
(* This is an instance variable, but its initial value is determined by the class constructor's parameter. *)
val mutable greeting_message = initial_message (* 'mutable' allows the value of this variable to be changed after initialization. *)
(* A method to print the current greeting. *)
method greet = print_endline greeting_message
(* A method to change the greeting message. It takes a new string as an argument. *)
method set_greeting new_message = greeting_message <- new_message (* The '<-' operator is used to assign a new value to a mutable variable. *)
end;;
(* Create an instance of customizable_greeter with an initial message. *)
let friendly_greeter = new customizable_greeter "Welcome!";;
(* Call the greet method. This will print "Welcome!". *)
friendly_greeter#greet;;
(* Now, let's change the message using the 'set_greeting' method. *)
friendly_greeter#set_greeting "It's nice to see you!";;
(* Call the greet method again. This will now print the new message: "It's nice to see you!". *)
friendly_greeter#greet;;
(* Create a different object from the same class. *)
let formal_greeter = new customizable_greeter "Good day.";;
(* This object has its own independent state. Calling its 'greet' method prints "Good day." *)
formal_greeter#greet;;
(*
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 1159ms.
PS C:\Users\User> ocaml C:\AI2025\objective_1.ml
Hello
Welcome!
It's nice to see you!
Good day.
PS C:\Users\User>
*)
(*
2. OBJECTIVE: Understand inheritance.
Inheritance allows a new class (a 'subclass' or 'derived class') to be based
on an existing class (a 'superclass' or 'base class'). The subclass inherits
the public methods and instance variables of the superclass, and can also
add new ones or modify existing ones.
*)
(* --- The Superclass (Base Class) --- *)
(* Let's define a general 'animal' class. *)
class animal (initial_name : string) =
object (self)
(* Instance variable to store the animal's name. *)
val name = initial_name
(* A method to get the animal's name. *)
method get_name = name
(* A general method for the sound an animal makes. *)
method speak = print_endline "The animal makes a sound."
end;;
(* --- The Subclass (Derived Class) --- *)
(* Now, we'll create a 'dog' class that inherits from 'animal'. *)
(* The 'inherit' keyword is used to specify the superclass. *)
(* We pass the 'initial_name' up to the 'animal' constructor. *)
class dog (initial_name : string) =
object (self)
(* This line establishes the inheritance relationship. *)
inherit animal initial_name
(* Overriding a method from the superclass. *)
(* The 'dog' class provides its own specific implementation for 'speak'. *)
(* When 'speak' is called on a 'dog' object, this version will be used. *)
method! speak = print_endline "Woof! Woof!" (* The '!' after method indicates we know we are overriding a parent method. *)
(* Adding a new method that only exists in the 'dog' class. *)
method wag_tail = Printf.printf "%s wags its tail.\n" name (* We can access 'name' because it was inherited from 'animal'. *)
end;;
(* --- Creating and Using Objects --- *)
(* Create an instance of the base class 'animal'. *)
let generic_animal = new animal "Creature";;
(* Call its methods. *)
Printf.printf "The animal's name is %s.\n" generic_animal#get_name;;
generic_animal#speak;; (* Outputs: "The animal makes a sound." *)
(* Create an instance of the subclass 'dog'. *)
let my_dog = new dog "Buddy";;
(* We can call methods inherited from 'animal'. *)
Printf.printf "The dog's name is %s.\n" my_dog#get_name;;
(* When we call 'speak', the dog's overridden version is executed. *)
my_dog#speak;; (* Outputs: "Woof! Woof!" *)
(* We can also call the new method defined only in the 'dog' class. *)
my_dog#wag_tail;; (* Outputs: "Buddy wags its tail." *)
(* The following line would cause a compile-time error because 'wag_tail' is not defined in the 'animal' class. *)
(* generic_animal#wag_tail;; *)
(*
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 1061ms.
PS C:\Users\User> ocaml C:\AI2025\objecttive_2.ml
The animal's name is Creature.
The animal makes a sound.
The dog's name is Buddy.
Woof! Woof!
Buddy wags its tail.
PS C:\Users\User>
*)
(*
3. OBJECTIVE: Understand polymorphism and virtual methods.
Polymorphism means "many forms". In OOP, it's the ability to present the same interface for differing underlying forms (data types). A function can process objects of different classes if they share a common superclass or interface.
A 'virtual' method is a method declared in a base class that can be
redefined (overridden) by its subclasses. In OCaml, methods are virtual by default.
*)
(* Let's define a 'shape' class. It's an abstract concept. *)
class virtual shape =
object (self)
(* A 'virtual' method is like a placeholder. It declares that subclasses
of 'shape' MUST provide their own implementation for this method. *)
(* A class containing a virtual method must itself be declared 'virtual',
and you cannot create a direct instance of it using 'new'. *)
method virtual area : float
(* A regular method that can be inherited directly. *)
method print_info = print_endline "This is a shape."
end;;
(* --- Subclasses Implementing the Virtual Method --- *)
(* A 'circle' class that inherits from 'shape'. *)
class circle (r : float) =
object (self)
inherit shape
val radius = r
(* We provide a concrete implementation for the 'area' method. *)
method area = 3.14159 *. radius *. radius
(* We can also override non-virtual methods. *)
method! print_info = print_endline "This is a circle."
end;;
(* A 'square' class that also inherits from 'shape'. *)
class square (s : float) =
object (self)
inherit shape
val side = s
(* We provide the required implementation for 'area' for a square. *)
method area = side *. side
method! print_info = print_endline "This is a square."
end;;
(* --- Polymorphism in Action --- *)
(* Create instances of our concrete shape classes. *)
let my_circle = new circle 10.0;;
let my_square = new square 5.0;;
(* We can create a list that holds objects of different types, as long
as they share a common parent class type ('shape' in this case). *)
(* Note the type annotation: 'shape list'. This tells OCaml to treat all
elements as 'shape' objects, even though their concrete types are
'circle' and 'square'. *)
let shapes : shape list = [ (my_circle :> shape); (my_square :> shape) ];;
(* The ':>' is a coercion operator. It explicitly tells the compiler to
"upcast" the object to its parent type. This is often needed when
creating collections of polymorphic objects. *)
(* Now, we can write a function that operates on any 'shape' object. *)
(* It doesn't need to know if it's a circle or a square. *)
(* It just needs to know that the object has an 'area' method. *)
let print_shape_area (s : shape) =
s#print_info; (* This will call the overridden version of print_info for each object. *)
Printf.printf "Its area is: %f\n" s#area;; (* The correct 'area' method is called at runtime. *)
(* Let's iterate through our list of shapes and apply the function. *)
(* This demonstrates polymorphism. The same function call 'print_shape_area s'
behaves differently depending on the actual type of 's' at runtime. *)
List.iter print_shape_area shapes;;
(*
Expected Output:
This is a circle.
Its area is: 314.159000
This is a square.
Its area is: 25.000000
*)
(*
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 3264ms.
PS C:\Users\User> ocaml C:\AI2025\objective_3.ml
This is a circle.
Its area is: 314.159000
This is a square.
Its area is: 25.000000
PS C:\Users\User>
*)
(*
4. OBJECTIVE: Understand encapsulation and access control (private members).
Encapsulation is the bundling of data with the methods that operate on that data. It's also about restricting direct access to some of an object's
components. This is a key principle for hiding implementation details.
In OCaml, we can define 'private' methods and instance variables. These can only be accessed from within the object itself, not from the outside.
*)
class bank_account (initial_balance : float) =
object (self)
(* This instance variable holds the account balance. *)
(* It's 'mutable' so it can be changed by deposit and withdraw operations. *)
val mutable balance = initial_balance
(* --- Private Method --- *)
(* 'method private' declares a method that can only be called by other
methods within this same object ('self'). It cannot be called using
the '#' operator from outside. *)
method private log_transaction (description : string) (amount : float) =
Printf.printf "LOG: %s of amount %f. New balance: %f\n" description amount balance;
(* This is an internal detail. The outside world doesn't need to know how we log things, only that transactions happen. *)
(* --- Public Methods (The Public API) --- *)
(* A method to get the current balance. This provides read-only access. *)
method get_balance = balance
(* A method to deposit money. *)
method deposit amount =
if amount > 0.0 then
begin
balance <- balance +. amount; (* Update the balance. *)
self#log_transaction "DEPOSIT" amount (* Call the private method to log. *)
end
else
print_endline "Error: Deposit amount must be positive."
(* A method to withdraw money. *)
method withdraw amount =
if amount <= 0.0 then
print_endline "Error: Withdrawal amount must be positive."
else if amount > balance then
print_endline "Error: Insufficient funds."
else
begin
balance <- balance -. amount; (* Update the balance. *)
self#log_transaction "WITHDRAWAL" amount (* Call the private method. *)
end
end;;
(* --- Using the Encapsulated Object --- *)
let my_account = new bank_account 100.0;;
(* We can call the public methods. *)
Printf.printf "Initial balance: %f\n" my_account#get_balance;;
my_account#deposit 50.0;;
my_account#withdraw 30.0;;
Printf.printf "Final balance: %f\n" my_account#get_balance;;
(* The following lines would cause COMPILE-TIME ERRORS because we are trying to access private members from outside the object. *)
(* ERROR: You cannot directly access the 'balance' instance variable. *)
(* let b = my_account#balance;; *)
(* ERROR: You cannot directly change the 'balance'. *)
(* my_account#balance <- 500.0;; *)
(* ERROR: 'log_transaction' is a private method and cannot be called from outside. *)
(* my_account#log_transaction "MANUAL EDIT" 10.0;; *)
(* By making the balance variable and the log_transaction method private, the class ensures that the account state can only be changed through the defined 'deposit' and 'withdraw' methods, maintaining its integrity. *)
(*
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 1064ms.
PS C:\Users\User> ocaml C:\AI2025\objective_4.ml
Initial balance: 100.000000
LOG: DEPOSIT of amount 50.000000. New balance: 150.000000
LOG: WITHDRAWAL of amount 30.000000. New balance: 120.000000
Final balance: 120.000000
PS C:\Users\User>
*)
(*
5. OBJECTIVE: Understand parameterized (or generic) classes.
Sometimes you want to create a class that works with different types of data without rewriting the entire class for each type. A parameterized class allows you to specify a type as a parameter when you create the class.
In OCaml, this is done using type variables, often denoted with a single
quote, like 'a, 'b, etc.
*)
(* We define a class 'container' that can hold a value of *any* type. *)
(* The 'a is a type parameter. It's a placeholder for a concrete type
(like int, string, float, etc.) that will be specified later. *)
class ['a] container (initial_value : 'a) =
object (self)
(* The instance variable 'content' will have the type 'a. *)
(* It is mutable so we can update the value stored in the container. *)
val mutable content = initial_value
(* This method returns the value stored in the container. *)
(* Its return type is 'a, which matches the type of the 'content'. *)
method get_value : 'a = content
(* This method takes a new value of type 'a and updates the content. *)
method set_value (new_value : 'a) =
content <- new_value
(* This method takes a function 'f' that transforms a value of type 'a
into a value of type 'b (another type parameter), and applies it. *)
method map (f : 'a -> 'b) : 'b =
f content
end;;
(* --- Using the Parameterized Class with Different Types --- *)
(* 1. Creating a container for an INTEGER. *)
(* Here, the type parameter 'a is instantiated as 'int'. *)
let int_box = new container 42;;
(* Get the integer value. *)
let num : int = int_box#get_value;;
Printf.printf "The integer box contains: %d\n" num;;
(* Update the value with another integer. *)
int_box#set_value 100;;
Printf.printf "The integer box now contains: %d\n" int_box#get_value;;
(* Use the 'map' method to convert the int to a string. *)
(* The function `string_of_int` has type `int -> string`. *)
(* So, 'a is int, and 'b is string. *)
let int_as_string : string = int_box#map string_of_int;;
Printf.printf "The integer as a string: '%s'\n\n" int_as_string;;
(* 2. Creating a container for a STRING. *)
(* This time, the type parameter 'a is instantiated as 'string'. *)
let string_box = new container "OCaml";;
(* Get the string value. *)
let text : string = string_box#get_value;;
Printf.printf "The string box contains: '%s'\n" text;;
(* Update the value. *)
string_box#set_value "is fun!";;
Printf.printf "The string box now contains: '%s'\n" string_box#get_value;;
(* Use the 'map' method to get the length of the string. *)
(* The function `String.length` has type `string -> int`. *)
(* So, 'a is string, and 'b is int. *)
let text_length : int = string_box#map String.length;;
Printf.printf "The length of the string is: %d\n" text_length;;
(*
Expected Output:
The integer box contains: 42
The integer box now contains: 100
The integer as a string (in new box): '100'
The string box contains: 'OCaml'
The string box now contains: 'is fun!'
The length of the string is: 7
*)
(*
6. CONCLUSION: A summary program bringing together all the OOP concepts.
(*
START
ocaml C:\AI2025\objective_7.ml
*)
(*
We will model a simple scenario: a small zoo with different animals.
This will use:
- Classes and Objects: To represent individual animals.
- Inheritance: To model the relationship between a general Animal and specific types like Lion and Parrot.
- Polymorphism: To treat all animals in a list uniformly, making them speak.
- Encapsulation: To protect the internal state of an animal (e.g., its hunger level).
- Parameterized Classes: To create a generic "Enclosure" that can hold any type of animal.
*)
(* --- Base Class: Animal (demonstrates Encapsulation) --- *)
class virtual animal (the_name : string) =
object (self)
val name = the_name
val mutable hunger_level = 5 (* Encapsulated state: private to the object *)
(* Public method to get the name *)
method get_name = name
(* A virtual method that subclasses MUST implement *)
method virtual speak : unit
(* A private method for internal logic *)
method private is_hungry = hunger_level > 3
(* Public method that uses private state and methods *)
method feed =
if self#is_hungry then
begin
print_endline (name ^ " eats the food happily.");
hunger_level <- 0
end
else
print_endline (name ^ " is not hungry right now.")
end;;
(* --- Subclasses: Lion and Parrot (demonstrates Inheritance) --- *)
class lion (the_name : string) =
object
inherit animal the_name
(* Implementing the required virtual method *)
method speak = print_endline "Roar!"
end;;
class parrot (the_name : string) (phrase : string) =
object
inherit animal the_name
val known_phrase = phrase
(* Implementing speak in a more specific way *)
method speak = print_endline (known_phrase ^ "!")
end;;
(* --- Generic Class: Enclosure (demonstrates Parameterized Classes) --- *)
(* This enclosure can hold any type of object, but we'll use it for animals. *)
class ['a] enclosure (initial_occupant : 'a) =
object
val mutable occupant = initial_occupant
method get_occupant = occupant
end;;
(* --- Main Program Logic --- *)
let () = (* The 'let () =' idiom is a standard way to start an executable block of code in OCaml. *)
print_endline "--- Welcome to the OCaml Zoo! ---";
(* 1. Creating Objects *)
(* A 'let' binding must be followed by 'in' to define the rest of the expression where the new variable is in scope. *)
let leo = new lion "Leo" in
(* Added 'in' to continue the chain of definitions, making 'polly' available in the following code. *)
let polly = new parrot "Polly" "Polly wants a cracker" in
(* 2. Demonstrating Polymorphism *)
print_endline "\n--- Let's hear from the animals (Polymorphism) ---";
(* Added 'in' to make 'all_animals' available to the subsequent expressions. *)
let all_animals : animal list = [ (leo :> animal); (polly :> animal) ] in
(* We iterate through the list and call the 'speak' method on each.
The correct, overridden method is called for each object. *)
(* Replaced the final ';' in the block with 'in' to connect it to the next part of the program. ';' is used to sequence unit-returning expressions within a block. *)
List.iter (fun an_animal ->
Printf.printf "%s says: " an_animal#get_name;
an_animal#speak
) all_animals;
(* 3. Demonstrating Encapsulation *)
print_endline "\n--- Feeding time (Encapsulation) ---";
(* The outside world doesn't know about 'hunger_level'. It just calls 'feed'. *)
leo#feed;
leo#feed;
(* 4. Demonstrating Parameterized Class *)
print_endline "\n--- Checking the enclosures (Parameterized Class) ---";
(* We can create an enclosure specifically for a 'lion'. *)
let lion_enclosure = new enclosure leo in
let resident_lion = lion_enclosure#get_occupant in
Printf.printf "The lion enclosure is occupied by %s.\n" resident_lion#get_name;
(* Or one for a 'parrot'. *)
let parrot_enclosure = new enclosure polly in
let resident_parrot = parrot_enclosure#get_occupant in
Printf.printf "The parrot enclosure is occupied by %s.\n" resident_parrot#get_name;
print_endline "\n--- End of Program ---";;
(*
END
ocaml C:\AI2025\objective_7.ml
*)
Windows PowerShell
Copyright (C) Microsoft Corporation. All rights reserved.
Install the latest PowerShell for new features and improvements! https://aka.ms/PSWindows
OCaml version: The OCaml toplevel, version 5.3.0
Coq-LSP version: 0.2.3
Loading personal and system profiles took 4389ms.
PS C:\Users\User> ocaml C:\AI2025\objective_7.ml
--- Welcome to the OCaml Zoo! ---
--- Let's hear from the animals (Polymorphism) ---
Leo says: Roar!
Polly says: Polly wants a cracker!
--- Feeding time (Encapsulation) ---
Leo eats the food happily.
Leo is not hungry right now.
--- Checking the enclosures (Parameterized Class) ---
The lion enclosure is occupied by Leo.
The parrot enclosure is occupied by Polly.
--- End of Program ---
PS C:\Users\User>
7. REFERENCES