viewtopic.php?f=2&t=757
In this thread, the post by lispamour » Wed Jul 07, lispamour mentions an excerpt from an article or book of Paul Graham. Having read a number of Paul Graham articles (and part of my inspiration for trying to tack LISP... again) I have a few questions about how to accomplish some common coding patterns in a more LISPY way.
The excerpt from Paul Graham I'm referring to specifically is the following:
Further, Listening to "Uncle Bob" for any amount of time, it becomes clear that OO is not really about "polymorphism, encapsulation, abstraction" .In practical terms, object-oriented programming means organizing a program in terms of methods, classes, instances, and inheritance. Why would you want to organize programs this way? One of the claims of the object-oriented approach is that it makes programs easier to change...If the program was written carefully to begin with we can make all these types of modifications without even looking at the rest of the code. [Emphasis mine]
- - Closures create encapsulation
- Functional abstraction and inheritance (see below)
- Polymorphism in C, which is not OO (UNIX STDIN)
- Uncle Bob Explains https://www.youtube.com/watch?v=TMuno5RZNeE&t=1s
Getting to the question at hand:
I have been juggling a really simply program in lisp:A loop that sees a player and an enemy battling to the death.
There are character definitions, the player def prompts the player for a name
Code: Select all
(defun make-ent (hp atk name)
(list :name name :hp hp :atk atk))
(defun make-player (hp atk)
(make-ent hp atk (prompt-read "What is your name")))
Code: Select all
(defun game ()
(setf player (make-player 10 10))
(setf enemy (make-ent 10 10 "bad-guy")
(loop
do
(attack enemy player)
(attack player enemy)
while (and (is-alive player) (is-alive enemy))))
Code: Select all
(defun attack (attacker defender)
(take-damage defender (getf attacker :atk)))
Entity
Attack(Entity* Target)
IsAlive()
TakeDamage()
etc.
Player<Entity>
overrides entity functions and adds own properties
vector<Items> Inventory
playerRole CharacterClass
GetPlayerInput(vector<option> Options)
Enemy<Entity>
Goblin
overrides entity functions and adds own properties...
Dragon
overrides entity functions and adds own properties...
etc...
Perhaps the take-damage method for the Goblin and Damage are different, as the Goblin might have a cowardice check and flee, whereas the dragon will become enraged. And clearly the Player->Attack() method will be different than the Dragon->Attack() method. So polymorphic is in order, either overriding abstract methods, or simply implementing from a blank Interface.
Herein lies the question. If Paul Graham dislikes the CLOS and thinks object oriented design of code is less effective than "careful design", then how would one achieve this kind of polymorphic behavior without using defgeneric or something else from the CLOS? How would you define an attack method which performs a kind of dispatch mechanism to call the correct form of the attack method without some kind of giant cond expression?
Code: Select all
(cond
((eq attacker-type Player) (player-attack target))
((eq attacker-type Dragon) (dragon-attack target))
;;; etc
If you'd like more information about the code that I'm working on, simple game, can be run with CLISP.
https://github.com/carkat/game-lisp/blo ... /game.lisp
Originally asked by me on r/learnlisp
https://www.reddit.com/r/learnlisp/comm ... _the_clos/