Custom Iterators
Part of the Object Oriented Programming section of Coddy's GDScript journey. Lesson 33 of 65.
Python makes a class behave like a list with magic methods such as __len__, __getitem__, __contains__ and __iter__. Godot has virtual methods for only one of these jobs, the for loop. Three methods make for item in my_object: work:
_iter_init(iter)runs once, before the first round. It sets the starting position and returnstrueif there is a first element._iter_get(position)returns the element at the current position, and the loop variable gets that value._iter_next(iter)runs before each further round. It moves to the next position and returnsfalsewhen there are no more elements, which ends the loop.
# team.gd
class_name Team
extends RefCounted
var _members: Array[String] = []
func add(member: String) -> void:
_members.append(member)
func _iter_init(iter: Array) -> bool:
iter[0] = 0
return iter[0] < _members.size()
func _iter_next(iter: Array) -> bool:
iter[0] += 1
return iter[0] < _members.size()
func _iter_get(position):
return _members[position]iter is an Array with one slot that Godot creates for each loop. iter[0] holds that loop's position, and Godot passes its value to _iter_get(). A Team now works in a for loop:
var team := Team.new()
team.add("Ada")
team.add("Bo")
for member in team:
print(member) # Ada, then BoKeep the position in iter[0], not in a member variable such as _position. Every loop gets its own iter, so two loops over the same team, even one inside the other, do not disturb each other. With a member variable, the inner loop would move the outer loop's position.
The other list jobs have no virtual method: len(team) and team[0] are errors. Write ordinary methods named like Array's, such as size(), get_at(index) and has(member). Do not test membership with in: "Ada" in team checks whether Team has a property or method named Ada, so it is false.
Challenge
EasyWrite the Bookshelf class in bookshelf.gd. It keeps the titles in _titles and holds at most _capacity books:
add(title)appends the title and returnstrue, or returnsfalsewithout adding when the shelf is full or already has that title.size()returns the number of books, andhas(title)whether the title is on the shelf.get_at(index)returns the title at that index, or an empty string when the index is outside the shelf._iter_init(),_iter_next()and_iter_get()let aforloop go through the titles in the order they were added.
The supplied code reads the capacity, the number of titles and one title per line, and reports the titles it could not add. It prints the number of books, lists them with a for loop over the shelf, then reads one more title and prints whether the shelf has it, and the last book. For capacity 3, the titles Dune, Emma, Dune, Ulysses, Hamlet and the search Emma it prints:
Could not add: Dune
Could not add: Hamlet
Books: 3
1. Dune
2. Emma
3. Ulysses
Has Emma: true
Last: UlyssesYour code goes in bookshelf.gd. main.gd holds the supplied input/output code and cannot be edited.
Try it yourself
extends Node
func _ready():
# Supplied input/output code: keep it as it is
var shelf := Bookshelf.new(int(OS.read_string_from_stdin()))
var count := int(OS.read_string_from_stdin())
for i in count:
var title := OS.read_string_from_stdin()
if not shelf.add(title):
print("Could not add: " + title)
print("Books: %d" % shelf.size())
var number := 1
for title in shelf:
print("%d. %s" % [number, title])
number += 1
var query := OS.read_string_from_stdin()
print("Has %s: %s" % [query, shelf.has(query)])
print("Last: " + shelf.get_at(shelf.size() - 1))
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of OOP
External FilesIntroduction to OOPClasses vs ObjectsThe self KeywordMethodsPropertiesConstructor (_init)Recap - Simple Calculator4Polymorphism
Method Overriding RevisitedDuck TypingAbstract Classes and MethodsInterface DesignRecap - Shape Calculator2Class Properties
Instance vs Static VariablesStatic FunctionsProperty SettersProperty GettersPrivate by ConventionRecap - Bank Account Manager5Encapsulation
Public and Private MembersValidation with SettersInformation HidingRead-Only PropertiesRecap - Student Records System8Advanced OOP Concepts
Composition vs InheritanceInner ClassesNodes as ComponentsRefCounted vs NodeEnums in Classes11Project: Library Management
Project OverviewBook and User Classes3Inheritance
Basic InheritanceThe super KeywordMethod OverridingInheritance ChainsType Checks with isRecap - Employee Hierarchy6Special Methods
Virtual Methods IntroductionThe _to_string MethodCustom IteratorsRecap - Custom List9Design Patterns Part 1
Intro to Design PatternsSingleton PatternFactory PatternObserver PatternStrategy PatternPractice on your own: Online GDScript compiler