Student & Courses questions

I’m having difficulty understand the "self’ part in the solution of both student and course
How do we access a different class’s method without using subclass?

the solution is below and what exactly is self in student and course solutions?
class Student
attr_reader :courses, :first_name, :last_name

def initialize(first_name, last_name)
@first_name, @last_name = first_name.capitalize, last_name.capitalize
@courses = []
end

def name
“#{first_name} #{last_name}”
end

def enroll(course)
# ignore re-adding a course
return if courses.include?(course)
raise “course would cause conflict!” if has_conflict?(course)

self.courses << course
course.students << self

end

def course_load
load = Hash.new(0)
self.courses.each do |course|
load[course.department] += course.credits
end
load
end

def has_conflict?(new_course)
self.courses.any? do |enrolled_course|
new_course.conflicts_with?(enrolled_course)
end
end
end

Solution for Course:
class Course
attr_reader :department, :name, :credits, :time_block, :days, :students

def initialize(name, department, credits, days=nil, time_block=nil)
@name, @department, @credits, @days, @time_block =
name, department, credits, days, time_block
@students = []
end

def conflicts_with?(course2)
return false if self.time_block != course2.time_block

days.any? do |day|
  course2.days.include?(day)
end

end

def add_student(student)
student.enroll(self) #What is this self?
end
end

The meaning of ‘self’ changes depending on the scope that it exists in, inside your code. If ‘self’ is inside any of the methods inside your class, ‘self’ is referring to the Instance of the Class. If ‘self’ is on the top-level scope of your class, ‘self’ is referring to the Class itself.

Example:
class Animal
attr_accessor :species

    def initialize
      @species = “”
    end

    def self.speak #self refers to Class(blueprint)
      puts ‘Hello’
    end

    def change_species(type)
      @species = type
    end

    def inputType(type)
      self.change_species(type) #self refers to the instance of the Animal class
    end
end

#Creates the instance of the Animal Class
dog = Animal.new

#Will throw an error as this is a Class Method and you can’t invoke the class method on the instance of the Class

dog.speak
#Will print “Hello”
Animal.speak

#At this current moment, species will be empty string
dog.species

#We are invoking the instance method that belongs to the animal object
dog.inputType(“dog”)

#After invoking the instance method above, species will now be ‘dog’
dog.species
#the below will throw an error as inputType is an instance method
Animal.inputType(‘cat’)

You can use the above and paste it into a repl to help you understand ‘self’ more clearly and than apply that understanding to the Students and Courses solution.

Thank you! but in the solution code I included, it doesn’t have the prefix self. before the method enroll, and yet an entirely different class course is trying to access the enroll method in student class, while course is not a subclass of student, they are the same level and two separate classes. How is that they can call each other’s methods?

The ‘enroll’ method is an instance method, so whenever an instance of the Student class is created, that method is available to use as part of that instance. If you look carefully at the ‘add_student’ method, an instance of the Student class is being passed in, and the ‘enroll’ method is being invoked on that instance.