Until recently I used to think that it was preferred to reference objects by pointers or references than to keep objects in some sort of a central, authoritative array or dictionary and only keep indices or keys of members of such an array.
However, recently I started reading something opposite. I started reading that it was preferred to rather avoid pointers/references and stick to the latter appproach because it (a) allows painless serialization / deserialization of data; (b) is the only reasonable approach if the functional paradigm is followed (and FP is praised nowadays); (c) others?
Is what I wrote so far correct?
My problem with keeping only ids of objects rather than references to object is that at least for me this leads to either unreadable or cluttered code.
Let me show an example. This is a piece of code I wrote for the turn-based game I'm trying to make as a hobby:
for (let i = 0; i < monsAndMoves.mons[monname].moves.length; i++) {
for (let j = 0; j < monsAndMoves.moves[monsAndMoves.mons[monname].moves[i]].prerequisites.length; j++) {
g.setEdge(monsAndMoves.moves[monsAndMoves.mons[monname].moves[i]].prerequisites[j], monsAndMoves.mons[monname].moves[i], {
/*...*/
})
}
}
What happened here?
monsAndMoves
- an object storing informations about monster species and moves monsters can perform.monsAndMoves.moves
- An array that stores informations about moves. (Should be a dictionary whose keys should be move names to keep consistency with the below)monsAndMoves.mons
- a dictionary mapping monster species names to informations about these species.monname
- should be calledcurrentMon.speciesName
- id of the species of the current monsterprerequisites
- indices of moves a monster must know to learn the given move
The above piece of code is unreadable.
We can make it readable at the cost of cluttering it:
const currentSpecies = monsAndMoves.mons[currentMon]
const moves = currentSpecies.moves
for (const moveName in moves) {
const move = moves[moveName]
for (const prereqName in move.prerequisites) {
g.setEdge(moveName, prereqName, {
/* ... */
})
}
}
Problem is, given this approach, we will have to repeat stuff like const currentSpecies = monsAndMoves.mons[currentMon]
at the beginning of almost every function. And if we stick to the general advice that functions should be as short as possible ("do one thing and one thing only") then we will have very many functions to clutter in this way. This seems to me annoying and very boilerplate-ish.
And this is how this piece of code would look like if references were kept instead of ids:
for (const move of currentMon.species.moves) {
for (const prereq of move.prerequisites) {
g.setEdge(prereq.name, move.name, {
/* ... */
})
}
}
Looks to me both readable and boilerplate free.
Thus, let me ask you:
- Is it correct that for the reasons I outlined above avoiding references and embracing ids of objects is considered the preferred approach?
- If yes, is there any way to reap the benefits of keeping ids vs references while at the same time avoiding the pains of this approach, namely writing either cluttered or unreadable code?