Wizards and warriors, part one

A common problem I see in object-oriented design is:

  • A wizard is a kind of player.
  • A warrior is a kind of player.
  • A staff is a kind of weapon.
  • A sword is a kind of weapon.
  • A player has a weapon.

But before we get into the details, I just want to point out that I am not really talking about anything specific to the fantasy RPG genre here. Everything in this series applies equally well to Papers and Paychecks, but wizards and warriors are more fun to write about, so there you go.

OK, great, we have five bullet points so let’s write some classes without thinking about it! What could possibly go wrong?

abstract class Weapon { }
sealed class Staff : Weapon { }
sealed class Sword : Weapon { }
abstract class Player 
{ 
  public Weapon Weapon { get; set; }
}
sealed class Wizard : Player { }
sealed class Warrior : Player { }

Designing good class hierarchies is all about capturing the semantics of the business domain in the type system, right? And we’ve done a great job here. If there is behavior common to all players, that goes in the abstract base class. If there is behavior unique to wizards or warriors, that can go in the derived classes. Clearly we’re on track for success here.

Right until we add…

  • A warrior can only use a sword.
  • A wizard can only use a staff.

What an unexpected development!

(As I have often pointed out, foreshadowing is the sign of a quality blog.)

Now what do we do? Readers familiar with type theory will know that the highfalutin name for the problem is that we’re in violation of the Liskov Substitution Principle. But we don’t need to understand the underlying type theory to see what’s going horribly wrong. All we have to do is try to modify the code to support these new criteria.

Attempt #1

abstract class Player 
{ 
  public abstract Weapon Weapon { get; set; }
}
sealed class Wizard : Player
{
  public override Staff Weapon { get; set; }
}

Nope, that’s illegal in C#. An overriding member must match the signature (and return type) of the overridden member.

Attempt #2

abstract class Player 
{ 
  public abstract Weapon { get; set; }
}
sealed class Wizard : Player
{
  private Staff weapon;
  public override Weapon Weapon 
  {
     get { return weapon; }
     set { weapon = (Staff) value; }
  } 
}

Now we’ve turned violations of the rule into runtime exceptions. This is incredibly error-prone; a caller could easily have a Wizard in hand and assign a Sword to Weapon. The whole point of capturing this thing in the type system is that the violation gets discovered at compile time.

Next time on FAIC: what other techniques do we have to try to represent this rule in the type system?

Advertisements

97 thoughts on “Wizards and warriors, part one

  1. This issue is really so common in OOD, I’m actually surprised it’s not well covered in various books / articles . I’ve seen a ton of different workarounds:

    1) generics (can easily become unnecessarily complex in some scenarios, when you look at resulting hierarchy with ridiculous number of generics and their constraints you start asking yourself – really? to avoid redeclaration of few properties? sometimes it can actually work though)
    2) hiding (so wrong and error prone)
    3) ‘casting’ members (same as 2)
    4) explicit interface implementation + redefinition (slightly better but still a work around)

    In a good number of situations It can be avoided by just removing this property from base type and converting to composition.

    • There has been interest in this feature for many, many years. It is always high on the interest list, but it has been deliberately ignored for a long time for pretty good reasons. It creates really nasty brittle base class issues, for instance. And it is not well supported by the CLR type system, so you end up having to generate lots of little helper methods behind the scenes; if you’re going to do that then hey, why not just make the user write those little helper methods; it’s not that hard and it makes it more clear what is going on.

    • But covariant return types are not enough, you need covariant argument types to change the current weapon, and they violate LSP.

  2. Well, waiting to “next time in FAIC” won’t satisfy my curiosity (unless that next time is about now… But I won’t hold my breathe).

    I would say that setting an arbitrary weapon is not part of the player’s contract….
    Moreover, I can’t see a justification for player to be an actual class.

    If it supposed to be an interface, that’s simple, and all you have to do is explicitly implement the interface.
    If it really supposed to be a class, I think the sane way to implement it would be read only property that calls a virtual/abstract method (this is a problem which I’ve encountered in C#. If you have a non-read-write property that might needed to be extended, you cannot override it, and add the missing getter/setter. You have to hide it (with read-write prop), and override its behaviour by overriding the method used by the base prop).

    Or… Why not just have read-write props of ‘ Sword’ and ‘ Staff’, and read only prop ‘ Weapon’ in the base class/interface?

  3. Hmmm…
    I think it might be a good idea to make a future post on why it’s a bad idea to create a virtual/abstract non-read-write properties in C#…

    • Right; I don’t address that specific concern in this series, but it is a good one. Your example illustrates one of the moral lessons I’m going to draw in this series: you only get one shot at encoding facts into the type system, and once you do, you’re stuck with them, so don’t try to encode too much, and make sure you choose what really is *fundamental* about your business domain to encode in the system.

    • Or how about a warrior who picks up an amulet of power which makes it possible for any character to use a staff to cast level 1-3 spells with some probability of success? For the RPG scenario, I would think the most natural approach would be to say that any character can opt to “wield” anything as a weapon, but under normal circumstances a warrior who tries to use a staff as a non-thrown weapon at an object more than 6 feet away should have a 0% probability of hitting anything with it, and a wizard who tries to use a sword as a weapon would have a -7 dexterity modifier applied to the attack.

      IMHO, the pattern of defining action requests such that almost any object of a general category can satisfy them, though not necessarily with useful effect, is under-appreciated [e.g. one could give all characters have a cast-spell method; because probability of the attempt succeeding may range from 0% to 100% depending upon character attributes and other factors (e.g. lingering effects from a “Confuse” spell), one could combine it with a method to estimate the probability of successfully casting a given spell]. While it may be useful to have derived interfaces whose implementation contract requires that certain members actually be useful, to my mind the question of whether a class should implement a member which will be useful for at least some subtypes should not be whether the member is useful for all subtypes, but rather whether it could be given a consistent meaning for all of them.

      • We had many of these problems when designing the “Symbol” hierarchy in Roslyn; is a symbol something with a name? With a source code location? With a metadata location? Or just something that has “identity” within the compiler? We ended up with a situation where many symbol kinds have methods and properties that make little sense for the specific cases, but it was too difficult to pull them out into the derived classes which needed them.

        There were few actually “heated” debates in the Roslyn design, but this one certainly took a long time and left I think everyone unhappy, which is maybe the sign of a good compromise. Still, when one of my coworkers encountered Roslyn for the first time and asked me “can you explain to me exactly what C# language concept the symbol base type represents? I can’t figure it out.” I was like I KNOW, RIGHT?!?

        • Is a “Symbol” perhaps something which would generally get associated with a name by the Symbol Table? If so, perhaps a symbol would be the base type for things that would generally be identifiable by name [recognizing that there may be some “synthetic” Symbol objects of various derived types that aren’t identifiable by name, but would be passed to code that would process things of the derived types, most of which are identifiable by name]?

          • Yes, you are getting at some of the many issues that were raised in this debate. Consider for example a partial generic class, C<T>. There are, let’s say two distinct source code locations because it is partial. There is one generic type, and that thing is a member of a namespace that can be looked up by name. And then there are all the constructed types, like C<int>, that in a sense do not have names — we do not look up C<int> in any namespace, we look up C-with-one-type-argument in a namespace. Nor do those things have locations. So of those three things — declarations with locations, the logical generic type that spans those locations, and the constructions of the generic type, only one is looked up by name. So, is a “symbol” something that can be looked up by name? Or is it something that has one or more locations? Or is it something that has identity which we can do some processing on in the compiler? What is the compelling scenario in which we must treat *all* of these things polymorphically? This is how the debate went on, for a long time.

  4. How about adding “Bool CanUseWeapon(Weapon weapon)” function to the Player class? Or add a “Weapon[] AcceptableWeapons {get;}” property to the Player class?

    • Right, this gets into the problem of “suppose we decide to throw an exception when the rule is violated; how do we NOT require that the caller catch the exception every time?” (What I call a “vexing exception”.) And the solution is you end up having auxiliary methods as you describe so that you can ask “OK if I do this?” before you do it. It becomes clunky. The “Try” pattern (int.TryParse, dictionary.TryGetValue, and so on) is also a common pattern here. We’ll discuss this a bit more in an upcoming episode.

        • Why are you pathologically avoiding try/throw/catch and re-implementing it as an if statement, if you’re going to throw anyway?

          Why are you avoiding it even if you’re not going to throw? The semantic of an exception is “you can’t do that; it would violate an invariant or something similar” – which is exactly the semantics you want! Just use an exception already. It’s exactly what you want.

      • The rule that wizards can use staves and daggers and robes but cannot use swords and plate mail comes from first edition Dungeons and Dragons, which I played as a teenager. To answer your question from a game design perspective, the idea is to produce some “balance” between the different character classes in the game. If a wizard can do everything a warrior can do — can use the same weapons and armor — and also cast spells, then why would anyone ever choose to play a warrior? (Note that this question implicitly assumes that the player seeks to maximize their in-game abilities, which is not true of all players.) The idea is to produce a system where each kind of character has unique strengths and weaknesses; this is then a basis for constructing a more well-thought-out individual character.

        To answer your question for my purposes in this series of articles, remember that wizards and warriors intend to represent any sort of business domain; wizards and warriors are just more fun than papers and paychecks. I could just as easily have said FlyingBusinessClass is a kind of Expense, a VicePresident is a kind of Manager, an Expense must be approved by a Manager, and only a VicePresident can approve FlyingBusinessClass, and we’re in the same situation, just SO BORING.

        • Thank you for your very comprehensive answer.
          I meant primarily that the wizard can build muscle he needs to bear a sword, but at the moment of becoming a wizard they (big muscles) do not exist (he has a low strength). And warrior can also use basic spells but he has very low levels of mana.
          On BORING (I fully understand your objection about using them) examples: VicePresident could talk by phone like normal Worker – maybe he has less knowledge about PhoneSpells than HotlineWorker.

          • I think the bigger point is, why are you trying to create an argument where there is none? It’s an abstract example, please use your brain.

  5. Error #1 of OOP : Not designing your object to abstract behavior. There is no behavior in your requirements, so there is no need for OOP.

    • Indeed, I have simply left out a huge amount of information about the desired behavior of the system. Some of that we can fill in using our intuitions about what the business domain is going to be: there are going to be wizards and warriors fighting vampires and werewolves, and we need some way to consistently encapsulate the behaviors of these various entities as they interact. (Or, in a non-RPG business domain, we have TPS reports and auditors and whatnot, and rules for how they all interact.)

      Like most of the other commenters you are anticipating somewhat my conclusion: that by naively choosing the wrong set of business concepts to impose our OOP design upon, we end up putting the behavior code in the wrong place.

  6. I would argue that with the given wording of the requirements, the most problematic part of the naive implementation is the setter of Weapon. If that were just a getter, Wizard would be free to implement a (setable) property Staff in addition to the readonly Weapon and Warrior could implement Sword in a similar fashion.

    Of course, all of this is very much a “if the only tool you have is a hammer” kind of problem. Inheritance trees are usually the first thing many people think about when modelling things in OO programs; they feel so idiomatically OO. Composition and switches are often (wrongly IHMO) regarded as non-idiomatic.

    I am looking forward to the rest of the series! I would also enjoy it if you would add a few side remarks on how other, not-(primarily)-OO languages would deal with this problem, like e.g. Haskell.

    • Indeed, it seems like that setter is pretty vexing, though we’ll see that it is far from the only problem.

      This series is pretty much going to concentrate on the OO side of things; I agree that it would be interesting to see what happens in a language that does not emphasize either inheritance or mutation, but we probably won’t cover it in this series. That’s a great idea for a future series.

  7. Worse is when you start seeing this class structure plus an ISwordWielder, IStaffWielder, and a type check in the Player class. Shoot me now please 😞

  8. I agree with the first comment. I felt the answer should be along the lines of favor composition over inheritance because inheritance sort of “ties you up”. I still can’t fully imagine how this might work and be flexible at the same time though because I keep asking my self what if the requirements change to let a certain player hold more than one type of weapon, wouldn’t that lead to a bloat of interfaces ?

  9. If Weapon setter isn’t common, it shouldn’t be at Player class.

    If the RPG rules says that some players can’t have some kinds of weapons, you need a method: TryEquipe

    It handles cases where you have a Warrior+Wizard. Or require a minimum level

  10. The other approach is just to make everything data driven with no need for a per-class, uh, class. That way, many years into the future of FaicRogueLike you can have 3,000 character classes that are pretty much just a mix of whatever attributes you like, just configure them in your database/xml/whatever and away you go. You might not even need to recompile.

    Add a bunch of attributes to your Weapon class like IsEdged, IsBlunt, IsRanged, IsTwoHanded, IsHeavy, IsWhatever. Then your PC class can have matching attributes like CanUseEdged, CanUsedBlunt, CanUseRanged, CanUseHeavy etc.

    In the real world I once worked on a very complicated search screen that was made up of hundreds classes (three or four per field)… I trashed all that and made it data driven. It’s not a cool technique, but it can be effective.

  11. I think everyone has slammed face-first into a similar problem once in a while. Subclassing players into wizards and warriors should not be done, since I don’t think even Idris or F* will be able to encode all the game rules in a type system.
    Do we really want to implement them in a type system, anyway? I want to be able to drag the sword icon onto the weapon slot of my wizard and get a meaningful reply, so this should be a runtime check. An exception is unsuitable here, since it’s a normal reaction of the system we’re building.
    Ideally I would have something like an entity-component model where the Equipment component model is responsible for handling all Equip methods of the entity and returns an Either where the consumer has to call Accept() or Cancel() on the GameResult for it to have any effect (now you cannot simply discard the result). GameError would include all kinds of errors that can happen: cannot wield anything at all – is a toaster, hands bound, hands missing, wrong slot, can’t unwield current item – cursed, weapon too heavy, class restriction, alignment restriction, can’t take any action – asleep and so on.

    • Exactly this. There can be a Player class as a Weapon class, but there should be no Wizard or Sword classes. You should add a PlayerClass class, with several instances constructed at runtime from configuration files, and have a PlayerClass property on the Player class (say that three times fast). Alternately, make PlayerClass an enum if you really want them to be fixed at compile-time. Java’s rich enums are helpful here for attaching different behaviors to each PlayerClass.

  12. Pingback: The Morning Brew - Chris Alcock » The Morning Brew #1849

  13. Pingback: Dew Drop – April 26, 2015 (#2002) | Morning Dew

  14. Something in this direction?

    The Wizard is not the Player but Character.
    The Player has one Character.

    abstract class Weapon { }
    sealed class Staff : Weapon { }
    sealed class Sword : Weapon { }
    
    class Player {
     public ICharacter Character {get;set;}
     public Weapon Weapon { get { return Character.Weapon; } } 
    }
    
    public interface ICharacter {
      Weapon Weapon { get; }
    }
    abstract class Character<TWeapon: ICharacter where TWeapon: Weapon
    {
    public TWeapon Weapon { get; set;}
    public Weapon ICharacter.Weapon {get {return Weapon; }}
    }
    
    class Wizard : Character<Staff{}
    class Warrior: Character<Sword{}
    
  15. Glad to see you’re back in action on the blogging front, I like these kind of posts that present a fairly simple problem that in turn spurs a lot of thinking/discussion. Disclaimer: I also like the long in depth code ones as well =D

  16. This is really just showing why OOD is empirically wrong for most problems. Very few problems are actually related to OOD. Now OOD has some amazing capabilities for libraries and frameworks, but it is almost never needed for problem solving.

    These restrictions are arbitrary and meaningless. The correct solution is let any class, equip any weapon. Make the weapon actually define properties about it, like weight or strength required. A wizard can most certainly pick up a broad sword but will likely die with it because they can’t swing it effectively.

    Then you can embed all of the logic for determining the hit penalties / hit bonuses for using a specific weapon entirely internal to the Wizard class. Or you could put all of the logic in a single “Combat Engine”, this is likely the superior design anyway as this logic is likely highly similar and could be reused much easier than if it’s coupled 100% to an individual class.

  17. It’s strange to me that everyone is suggesting variations of “maybe the wizard really can use a sword in some way after all”. Sure, in any great and well developed game, it’s likely that wizards will be able to interact with swords in some way. But it seems like the premise here is that they can’t. It’s reasonable to expect that something could change in the future, and so those flexible decisions shouldn’t be “baked into” the types like this (but instead be in an equally variable means of storing those policies). What I don’t get is why people see that the game rules don’t work well with the way the coding the game” and decide to change the game rules instead of just the mechanisms.

    • Your point is well taken, but remember, I’m using wizards and warriors as a fun example of a business domain. In the wizards and warriors domain we say “a player has a weapon, a wizard is a kind of player, a staff is a kind of weapon, a wizard can only use a staff”. In the papers and paychecks domain we say “a report has an approver, a TPS report is a kind of report, a vice president is a kind of approver, a TPS report can only be approved by a vice president”.

      We cannot just “decide to change the rules” if the rules are imposed. by an external regulating body.

      • Yes, but we still have all kinds of approvers interact with TPS reports at the UI level. At the very least we want to implement the use case “show the user only those reports they can approve when they click on ‘approve pending reports'”, and if all the reports are stored somewhere in IEnumerable[Report] (no angle brackets in the comments 😦 ), then we have to dip into the type system at runtime in any case, or we have to duplicate our logic in code, e.g.:
        if (user is Approver) {
        if (user is VicePresident) {
        return Reports.PendingApproval();
        } else {
        return Reports.PendingApproval().Where(r => !(r is TpsReport));
        }
        } else {
        return Enumerable.Empty;
        }

      • That’s what I’m saying, though. I see answers proposing things like “The correct solution is let any class, equip any weapon.” and don’t understand. I don’t see why people “decide to change the [game] rules” instead of working toward a coding solution that adapts to them.

        Admittedly the coding mechanism could allow letting any class equip any weapon (or approve any report), and then restrict it to fit the policy in some other way; the difference gets pretty superficial at some point.

        • The question of who can effectively wield what weapons is a policy decision; having policy decisions made by executable code rather than by a static type system will allow the program to be adapted to fit future policy changes, even those which the type system would be incapable of expressing.

          The extension to “let anyone wield anything” is intended to focus on the question of what the real policy goal is, and centralize enforcement of that policy. Consider the policy “Non-wizards can’t use staffs to cast spells.” Unless unless any wizard who has equipped a staff will unconditionally be able to use it to cast any spell as long as it is equipped, it will be necessary to define a means of determining “can character X use artifact Y to cast spell Z at this time?” Adding to that one method a check “if X is a non-wizard, Y is an ordinary wizard staff, and Z is a spell-casting attempt, the attempt fails” may be necessary, and will be sufficient, to enforce the stated policy. While it may be helpful to *also* have a policy check when wielding a weapon, such a test may sometimes be neither sufficient nor necessary.

  18. I’d like to see you talk about best practices regarding multiple relationships, like A Warrior is a Player, but he is also a Monk and how to solve common problems with this kind of scenario.

    • I considered addressing the multiple inheritance problem in this series but decided to go in a slightly different direction. But you are right that there are lots of potential pitfalls here.

  19. oh man, love this analogy!

    I wonder if I can propose another way of looking at things.
    Let’s not make this about code but about design.

    If we were to write a real rpg game we could consider a little more complicated scenario :

    ok a warrior can use a sword and a wizard can use a staff, but the wizard can also use a dagger and maybe even some swords but not all.

    This illustrates my point, now the accent is not on the entity type but on the item type instead,
    which brings me to this point next :

    maybe the item should have a list of possible archetypes that can use it.
    So I have sword 1 which can be used by warrior and wizards or only by warrior. This now allows the kind of flexibility I actually want plus additional extra information that’s easy to display. Let’s say you loot an item, you can show straight away which archetypes can use it and pop an error message if the wrong archetype tries to equip it.

    This system also makes it easy to add extra items and archetypes with fun combinations.
    As I said, if we start from the design first it makes things easier to code surely. Isn’t this the whole point ?

    • I’d hesitate to put information about who can use a sword in the sword’s data. From the design POV, a sword shouldn’t bother itself with every possible wielder. Instead, the wielder should know what it can wield. Alternatively, as others seem to mention, you could delegate equip logic to some sort of policy engine.
      That is, unless it’s Mjolnir and only the worthy can wield it. That seems like something the weapon could be concerned with. Even then, you might need to move the “is worthy” logic into the domain of who’s actually deciding, like Odin: (http://scifi.stackexchange.com/questions/4404/how-does-mjolnir-determine-worth)

      • The question “can X use Y” is fundamentally a double-dispatch question. Such questions are often best solved by having both parties have information about intermediate entities which contain information about how well X should be able to use Y. Characters shouldn’t directly contain information about what weapons they can use (since otherwise any new weapon added to the game would be unusable by any existing characters), nor should weapons generally contain directly identify the character classes that may wield them (since otherwise any new character class would be unable to use any existing weapons).

    • Hah, I am loving how many comments here directly anticipate the problems I am going to raise in later episodes. Spoiler alert: I will spring “what if a wizard and a warrior can both use a dagger?” on you in part two.

  20. In this case, “Player” (or “Player Character”) sounds like it shouldn’t be a class, but an interface – we know what a generic Character might be able to do, but we don’t know exactly what this specific Character will do. Instead of tying ourselves down by changing the character to support Wizard and Warrior, we should ensure that Wizards and Warriors really are Characters who do something similar to what we would expect.

    That being said, I’d imagine the answer would involve abstracting away the concept of ownership in the situation to the lowest level. A character, we would expect, holds items. What those items are can’t really be predicted, as the implementation will dictate what that specific instance of a character can and cannot do. We could make each subclass be a Character, but that would limit us to only a single type of item. It could make sense, then, to have Weapon (or even just Item) also be an interface.

    This leaves us with a Wizard who we know can Equip(Wand newWand) because we know he is an ICharacter and we know we can expect ICharacters to be able to equip some kind of IWeapon that their own behavior will define, as they made the choice to go down this path (or in this case, become instantiated by the player in our RPG engine). This also solves the multi-class problem quite well, as we can simply overload Equip(IWeapon newWeapon) for any other type of IWeapon and can use interfaces like ICharacterWhoUsesSwords and ICharacterWhoUsesWands to specify from the top level to the bottom.

    The moral of the story seems to be that you should know the difference between creating an object and creating the contract that defines what that object might do. We shouldn’t define concrete implementations in abstract classes or interfaces if possible because sometimes our ITaxForm might be a 1040 tax form and other times it might be a 1090 tax form and it would be a little odd for us to try and write the same information on both despite them looking very similar.

    (I know I switched the class name, but the D&D nerd in my really wanted to differentiate “Player” from “Player Character”)

    • I think there is merit in using both interfaces and abstract classes to model the engine. In fact I am such a nerd that I actually wrote such an engine a while back !

      I like this topic so much that I actually went ahead and moved my code from tfs online into github to be able to share it. Feel free to have a look and see what you think. It’s obviously not perfect but there is a basic combat system, items, loot, armor slots etc.

      There is no graphical interface but there is a Test console project where a few things are shown.

      I fully expect the code to be torn apart and shown to me how bad it is, but this was just a bit of fun and I kinda like the way it turned up. I might end up write an article about it :).

      here’s the link : https://github.com/guardinfo-spam/rpg-engine

      feel free to torn it apart !

      • I’d encourage you to write that article; it would be interesting to see what thought process led you to making various choices.

        This is a good opportunity to point out something important: it is all well and good to have this sort of “armchair” discussion about the pros and cons of different approaches, but that discussion doesn’t actually get something built!

        You actually built something instead of just talking about it like I’m doing, and that thing has value. The design you’ve chosen will undoubtedly have pros and cons, but “existing at all” is certainly a pro!

      • It is certainly interesting, and I do really like that in a real world environment that maintaining this code would be less of a hassle. In my experience, hitting an interface when digging through functionality can be somewhat annoying if you can’t find the classes that implement it.

        I feel that abstract classes fall closer in coding philosophy to interfaces than actual classes a lot of the time, so this solution makes a lot of sense in that regard. If you end up writing the article on it I’d be very interested to read it to see your thought process!

    • In Java and similar object-oriented languages, every type of class is also a type of reference, and the two types are required to share the same inheritance relations. While this generally makes sense, there are times when it would make sense to have multiple kinds of references to a particular class, with is-a relationships among reference types that don’t fit the normal inheritance model (e.g. a `BasicList` class might support reference types `ReadableBasicList`, `MutableBasicList`, and `ImmutableBasicList`, and `FancyList`, derived from it, might have similar types; an `ImmutableFancyList` should be acceptable to code wanting a `ReadableFancyList` or `ImmutableBasicList`, but there’s no way the Java or .NET type system can handle that), or when it would make sense to have multiple classes in code be identified by the same reference type (such that `new Fnord(params)` would generate an object that would appear to the outside world to be a `Fnord`, but which might–depending upon the constructor parameters–actually be one of a number of classes with different fields and virtual methods). I don’t know if any languages have a type system which separates out substitutability from composition and code layout in such a fashion, but it would seem like a helpful ability.

  21. I wonder if Code Contracts will enter into this at any point?

    I looked for a while a previous comment that recommended only having a get option for the weapon, and at first I really like it. But after a bit I realized it would lead to code where later the developer says, “Okay get the player’s weapon. And because he’s a wizard, we know the weapon will be a staff, so it’s okay to cast it.” That to me is another sign of heading down the wrong direction.

    I also see lots of comments questioning the rule that a wizard can only carry a staff, talking about the need for exceptions. This may be true, but seems to miss the premise. If you’re trying to side-step the Liskov problem, you’re missing the point.

    With that in mind, I think a generic solution may be a good choice, where a Wizard is a Player and a Warrior is a Player. This would not be a good fit for a domain that allows for exceptions, but if we accept the premise of the problem it works out okay.

    The real problem with the generic solution comes when you starting expanding into other areas of the domain. A Wizard can use a magic cloak, but a warrior can wear heavy plate armor, and there is not cross between them. Then do the same for a shield, accessory, travel pack, etc; suddenly you have types with a large number of generic parameters.

    • I’m not going to get into code contracts in this series, though that is an interesting direction to go. It lets you capture invariants that are too complicated to put in the type system, but are sort of like a type system.

  22. My two cents example. All the code in the post seems to be in C#. Having started out as VB6 dev, muscle memory aids VB syntax and hence the VB code.

    Public MustInherit Class PlayerBase

    Protected Sub New()

    End Sub

    Friend Property Weapon As WeaponBase

    Public Sub Wield()
    ‘logic to wield the weapon goes here
    End Sub

    End Class

    Public NotInheritable Class Wizard
    Inherits PlayerBase

    End Class

    Public NotInheritable Class Warrior
    Inherits PlayerBase
    End Class

    Public MustInherit Class WeaponBase

    Protected Sub New()

    End Sub

    End Class

    Public NotInheritable Class Staff
    Inherits WeaponBase

    End Class

    Public NotInheritable Class Sword
    Inherits WeaponBase

    End Class

    Public NotInheritable Class SelectableWeapon

    Private _weapon As WeaponBase
    Private _player As PlayerBase

    Friend Sub New(weapon As WeaponBase, player As PlayerBase)
    _weapon = weapon
    _player = player
    End Sub

    Public ReadOnly Property Weapon As WeaponBase
    Get
    Return _weapon
    End Get
    End Property

    Public Sub ArmPlayer()
    _player.Weapon = _weapon
    End Sub
    End Class

    Public NotInheritable Class Armoury

    Private Sub New()

    End Sub

    Private Shared Function FetchWeaponsForPlayer(player As PlayerBase) As IReadOnlyList(Of WeaponBase)
    ‘Logic to find weapon for the player. Simple logic here. can be expanded
    If TypeOf player Is Wizard Then
    Return {New Staff}
    ElseIf TypeOf player Is Warrior Then
    Return {New Sword}
    Else
    Return {}
    End If
    End Function

    Public Shared Function Open(player As PlayerBase) As Armoury
    Dim availableWeapons = FetchWeaponsForPlayer(player)
    Return New Armoury With {._selectableWeapons = availableWeapons.Select(Function(weapon) New SelectableWeapon(weapon, player)).ToArray}
    End Function

    Private _selectableWeapons As IReadOnlyList(Of SelectableWeapon)
    Public ReadOnly Property SelectableWeapons As IReadOnlyList(Of SelectableWeapon)
    Get
    Return _selectableWeapons
    End Get
    End Property
    End Class

    Module Module1

    Sub Main()
    Dim player As New Warrior
    Dim armouryForPlayer = Armoury.Open(player)
    If armouryForPlayer.SelectableWeapons.Count = 0 Then
    Console.WriteLine(“No Weapons selectable for this player.”)
    Else
    armouryForPlayer.SelectableWeapons(0).ArmPlayer()
    End If

    player.Wield()

    Console.ReadKey()
    End Sub

    End Module

  23. Hi
    As an option I would probably try adding another layer on the Weapon types and use generics, like below:

    public interface IWeapon { }
    public interface IWizardCategoryWeapon : IWeapon { }
    public interface IWarriorCategoryWeapon : IWeapon { }

    sealed class Staff : IWizardCategoryWeapon { }
    sealed class Sword : IWarriorCategoryWeapon { }

    abstract class Player where T : IWeapon
    {
    public abstract T Weapon { get; set; }
    }

    sealed class Wizard : Player
    {
    private IWizardCategoryWeapon weapon;
    public override IWizardCategoryWeapon Weapon
    {
    get { return weapon; }
    set { weapon = value; }
    }
    }
    sealed class Warior : Player
    {
    private IWarriorCategoryWeapon weapon;
    public override IWarriorCategoryWeapon Weapon
    {
    get { return weapon; }
    set { weapon = value; }
    }
    }

    But this brakes open-closed principle perhaps, we would have to modify weapon types to make them available to different kind of players, which is not right.

    Technically, some kind of validation should go into the setters of the Weapon property of each player.

  24. the generics near Player of (T) were filtered removed in my previous post… I meant this actually

    public interface IWeapon { }
    public interface IWizardCategoryWeapon : IWeapon { }
    public interface IWarriorCategoryWeapon : IWeapon { }
    
    sealed class Staff : IWizardCategoryWeapon { }
    sealed class Sword : IWarriorCategoryWeapon { }
    
    abstract class Player where T : IWeapon
    {
        public abstract T Weapon { get; set; }
    }
    
    sealed class Wizard : Player
    {
        private IWizardCategoryWeapon weapon;
        public override IWizardCategoryWeapon Weapon
        {
            get { return weapon; }
            set { weapon = value; }
        }
    }
    sealed class Warior : Player
    {
        private IWarriorCategoryWeapon weapon;
        public override IWarriorCategoryWeapon Weapon
        {
            get { return weapon; }
            set { weapon = value; }
        }
    }
    
  25. another try, sorry for spamming:

    public interface IWeapon { }
    public interface IWizardCategoryWeapon : IWeapon { }
    public interface IWarriorCategoryWeapon : IWeapon { }
    
    sealed class Staff : IWizardCategoryWeapon { }
    sealed class Sword : IWarriorCategoryWeapon { }
    
    abstract class Player<T> where T : IWeapon
    {
        public abstract T Weapon { get; set; }
    }
    
    sealed class Wizard : Player<IWizardCategoryWeapon>
    {
        private IWizardCategoryWeapon weapon;
        public override IWizardCategoryWeapon Weapon
        {
            get { return weapon; }
            set { weapon = value; }
        }
    }
    sealed class Warior : Player<IWarriorCategoryWeapon>
    {
        private IWarriorCategoryWeapon weapon;
        public override IWarriorCategoryWeapon Weapon
        {
            get { return weapon; }
            set { weapon = value; }
        }
    }
    
  26. What about the option below?

    abstract class Weapon { }
    sealed class Staff : Weapon { }
    sealed class Sword : Weapon { }
    
    sealed class WizardsWeapon : Weapon
    {
        public static implicit operator WizardsWeapon(Staff b)
        {
            return new WizardsWeapon(); // construct it as needed
        }
    }
    sealed class WariorsWeapon : Weapon
    {
        public static implicit operator WariorsWeapon(Sword b)
        {
            return new WariorsWeapon(); // construct it as needed
        }
    }
    
    abstract class Player<T> where T : Weapon
    {
        public T Weapon { get; set; }
    }
    
    sealed class Wizard : Player<WizardsWeapon> { }
    sealed class Warrior : Player<WariorsWeapon> { }
    

    In this case allowing new weapons to players can be done by just adding new convertion operators to intermediate KindWeapon classes

  27. Pingback: Wizards and warriors, part two | Fabulous adventures in coding

  28. Pingback: PCL Rpg engine – part 1 – actors and gear | Andrei's web corner

  29. After a few days of pondering this article and reading many of the comments, I thought about:
    Why not have the notion of what a Player can equip be a separate entity. The player has a list of “Equippables” which is a list of Types (all subclasses of Weapon) that can be queried at runtime.

    Then the Wizard can override a Weapon.Set method and query its’ Player.Equippables list to see if the Weapon being Equipped is allowed. The notion of having the set of equippable weapons be separate from the player entity itself is key here. Perhaps the set of Equippables could be part of a CharacterClass which would encompass other attributes of that class as well. I might write some code to test out these ideas.

  30. Pingback: Basic OOP is easy, isn’t it? | gerleim

  31. How about:

    abstract class Player
    {
    protected Weapon Weapon { get; set; } // possibly internal instead of protected
    }

    sealed class Warrior : Player
    {
    public Sword Sword { get; set; }
    }

    sealed class Wizard : Player
    {
    public Staff Staff { get; set; }
    }

    Or I honestly sometimes wonder about pretending that the words abstract, virtual, and interface were never added to C# or at least using them almost never.

  32. @Bob Larson

    I believe we need a more dynamic solution:

    sealed class Illusionist : Player
    {
    public dynamic IllusionaryStaff { get; set; }

    public object Attack()
    {
    try
    {
    if (IllusionaryStaff != null)
    {
    if (IllusionaryStaff.GetType().ToString() == “Sword”)
    return new Random().Next(1, 6);
    else if (IllusionaryStaff.GetType().ToString() == “Staff”)
    return new Random().Next(1, 3);
    else if (IllusionaryStaff.GetType().ToString() == “Math”)
    return Math.Sqrt((int)IllusionaryStaff.DesperationAttackResult);
    }

    int dieRoll = new Random().Next(1, 3);

    if (dieRoll == 3)
    return this; // Head First into the fray.
    if (dieRoll == 2)
    return PlayerDataAccess.GetRandomPlayer();

    return Attack(); // Let’s try this again.
    }
    catch
    {
    return “The Kitchen Sink is flying directly at YOU!!!”; // Illusionist frantically attempts to scamper away to safety.
    }
    }
    }

  33. Pingback: 1 – Wizards and warriors | blog.offeryour.com

  34. Pingback: 1p – Wizards and warriors | Profit Goals

  35. Pingback: 1p – Wizards and warriors | Exploding Ads

  36. Pingback: Wizards and warriors, part five | Fabulous adventures in coding

  37. Pingback: Link der Woche: Objektorientierung löst nicht alle Probleme | Fachinformatiker Anwendungsentwicklung

  38. Pingback: Luís Gonçalves

  39. Pingback: TECNOLOGÍA » Wizards and warriors, part five

  40. Pingback: Hard problem, or wrong problem? – willmurphyscode

  41. Pingback: Book Recommendation: POODR – willmurphyscode

  42. Il nostra azienda ha 10 anni di esperienza nel sviluppo di siti e di prodotti di poligrafica. Le proposti che proponiamo sono orientate alla massimizzazione della conversione e all’aumento delle vendite. La nostra funzione non e solo la sviluppo e il design: ogni nostro decisione porta con se le precise idee che vanno trasmesse dal venditore all’acquirente. A seconda degli obbiettivi stabiliti dal cliente cambiano anche le nostre soluzioni.

    Oggi vi suggeriamo di familiarizzare con uno dei nostri servizi – e molto probabile che sara molto utile per voi: SITI WEB E BANNER

    Il Design Studio Paolo Vetlucci sara lieto di offrirvi i propri servizi in questo settore, promesse un massimo livello di professionalita nell’esecuzione del vostro ordine.

    Noi non chiediamo mai il pagamento anticipato per il nostro lavoro perche siamo sicuri che i risultati del nostro lavoro vi lasceranno assolutamente soddisfatti!

    Siamo certi che la nostra collaborazione sara estremamente fruttuosa. Ci vediamo presto!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s