What happens if I cast an item twice (e.g. for an inventory system)? - xna

I am developing a game with an inventory system in C#/XNA. My plan is for the inventory to store the base class, Item. Derived from Item is an Equipment class (and other classes). Derived from the Equipment class is a Gun class (and other classes). Item has an enum that contains its type (Equipment, Crafting, etc.) and the Equipment class has an enum that contains its type (Gun, Armor, etc.). Using the information from the type enums would it work when--dropping a Gun from the inventory into the world for instance--to cast from Item to Equipment, then from Equipment to Gun?

Yes
Casting doesn't change the nature of the object, just what you are "looking at it as". The cast will throw an InvalidCastException if it isn't actually of that type (or inherits from that type), so be careful when doing this.
You could instead use the as operator and check for null afterwards as a much safer way of casting. Either way, you can cast as much as you like and it won't cause any problems.
To try and explain why casting from Item to Gun is ok, think about it in pure English terms:
Say I hand you a bunch of Items. Those items are of many types, some of which are Guns. You pick an item at random (say its a Gun for arguments sake). You can safely treat it as an Item, a piece of Equipment, or a Gun. It doesn't matter which, as long as it actually is a gun. Of course, if you picked an apple, and tried to treat it as a gun, that could cause some problems (and hilarity :) ).

I believe the question is this:
var someItem = new Gun() { ItemType = ItemTypes.Equipment, EquipmentType = EquipmentTypes.Gun };
//Later, after item is dropped, we know it is an Item only, do some fancy dynamic cast?
Item droppedItem = Drop(someItem);
var castItem = ((droppedItem.EquipmentType)(droppedItem.ItemType)droppedItem) //Can't do this
Unfortunately, it is not possible to do a dynamic cast at runtime in C#.
You're going to need something like:
if(droppedItem is Gun)
{
DoSomethingWithAGun(droppedItem);
}
As others mentioned though, if you already know it is a Gun, then simply do:
Gun droppedGun = (Gun)droppedItem;
//Or
Gun droppedGun = droppedItem as Gun;
There are some differences between those two statements. See Direct casting vs 'as' operator?

Related

What is the preferred way of getting value in swift, var vs. func?

What's the preferred way of getting a value in swift?
Using a read-only variable
var getString: String? {
return "Value"
}
or using a function?
func getString() -> String? {
return "Value"
}
Also, is there a performance difference between the two?
First, neither of these would be appropriate names. They should not begin with get. (There are historical Cocoa meanings for a get prefix that you don't mean, and so even if you mean "go out to the internet and retrieve this information" you'd want to use something like fetch, but certainly not in the case you've given.)
These issues are addressed in various sections of the Swift API Design Guidelines. First, a property is a property, whether it is stored or computed. So there is no difference in design between:
let someProperty: String?
and
var someProperty: String? { return "string" }
You should not change the naming just because it's computed. We can then see in the guidelines:
The names of other types, properties, variables, and constants should read as nouns.
Furthermore, as discussed in The Swift Programming Language:
Properties associate values with a particular class, structure, or enumeration. Stored properties store constant and variable values as part of an instance, whereas computed properties calculate (rather than store) a value.
So if this is best thought of as a value associated with the type (one of its "attributes"), then it should be a property (computed or stored). If it is something that is not really "associated" with the type (something that the caller expects this type to retrieve from elsewhere for instance), then it should be a method. Again from the Design Guidelines:
Document the complexity of any computed property that is not O(1). People often assume that property access involves no significant computation, because they have stored properties as a mental model. Be sure to alert them when that assumption may be violated.
If "stored properties as a mental model" doesn't match what you mean to express, then it probably shouldn't be a property in the first place (and you need to document the discrepancies if you make it a property anyway). So, for instance, accessing a property should generally have no visible side effects. And if you read from a property immediately after writing to it, you should get back the value you wrote (again, as a general mental model without getting into the weeds of multi-threaded programming).
If you use a method, it can often result in a different appropriate name. See the "Strive for Fluent Usage" section of the Design Guidelines for more on that. There are several rules for selecting good method names. As a good example of when to use properties vs methods, consider the x.makeIterator(), i.successor() and x.sorted() examples and think about why these are methods and why they're named as they are. This is not to say there is exactly one answer in all cases, but the Design Guidelines will give you examples of what the Swift team intends.
With no discernible difference in performance, make the choice for readability:
When an attribute behaves like a variable, use a property. Your example falls into this category.
When reading an attribute changes object state, use a function. This includes
Attributes that behave like a factory, i.e. returns new objects when you access them
Attributes that produce new values, such as random number generators
Peripheral readers
Input iterators
Of course, if the attribute is computed based on one or more argument, you have no other choice but to use a function.
Just as a note: If you want to use both getters and setters in Swift you can do as follows:
var myString: String {
get {
return "My string"
}
set {
self.myPrivateString = newValue
}
}
This way you can access your value as if it was a regular variable, but you can do some "under-the-hood magic" in your getters and setters

Array of custom class implementing generics not allowing custom class with subclassed generic

I have the following scenario
class Human {}
class Child: Human {}
class Person<T: Human> {}
var people = [Person<Human>]()
people.append(Person<Child>())
yet on the line people.append(Person<Child>()) I receive an error of
cannot convert value of type 'Person<Child>' to expected argument type 'Person<Human>'
This is really strange as doing the following works (which seems to be an identical situation)
var myArray = [Array<UIView>]()
myArray.append(Array<UIImageView>())
Would anyone have an understanding of why one way works and not the other?
Actually you're not putting the case strongly enough. Define:
class Human {}
class Child: Human {}
struct Holder<T> {}
I made Holder a struct so no one can accuse us of cheating: Array is a struct, Holder is a struct. And I took away your constraint on the placeholder, reducing everything to the simplest possible form.
Now just assign an array of Child where an array of Human is expected:
var arr = Array<Human>()
arr = Array<Child>()
Fine. Now try it with a Holder:
var holder = Holder<Human>()
holder = Holder<Child>() // error
The parallelism now appears perfect: Array is a struct, Holder is a struct, and all we're doing is trying to assign polymorphically. So what's the problem?
The problem, as you have probably already suspected, is that you are not Apple. Apple writes the code, so they get to define Array and similar types as covariant on the parametrized type. But it isn't an automatic feature of the language — that is, it is not true for generics in general. And in particular, you don't get to do that for types you define.
So Apple's Array is covariant, but your Holder (or Person) is not, and there's nothing that allows you to switch covariance on.
You can see why Array is covariant. It is a very special case. An array is a collection of objects. Apple knows that an array of, say, Child objects is also in fact an array of Human objects, because every Child is a Human (polymorphism). So they have implemented covariance for arrays, to ensure that this is so.
But there is no such guarantee about your Person or my Holder. Swift doesn't know what you intend to do with the placeholder T. You can probably think of cases where substituting a Holder<Child> where a Holder<Human> is expected would be wrong. So Apple makes no assumptions in that direction.
I should add that it's important to distinguish the following:
class Human {}
class Child: Human {}
struct Holder<T> {
let thing : T
}
let holder : Holder<Human> = Holder(thing:Child()) // fine
That's legal, but it has nothing whatever to do with what we've been talking about. Only one generic type is involved here: Holder<Human>. All we're doing is assigning a Child into thing, where a Human is expected. That's good old-fashioned non-generic polymorphism. But you still can't cast a Holder<Human> down to a Holder<Child>, even if thing is a Child, and you still can't assign a Holder<Child> where a Holder<Human> is expected.

How to avoid changing state in F#?

I have a C# WebAPI application that uses an F# library.
The F# library has a value:
let mutable CurrentCustomer:Customer option = None
I also have:
let Customers:Map<string,Customer> option = None
Both Customers and Customer are "global variables". On start-up the C# application loads a collection of customers into this global variable Customers. Then I have a customersController that has a Post, which calls an F# function setCurrentCustomer that sets the global variable CurrentCustomer from the collection stored in Customers:
// Post in customersController:
public HttpResponseMessage Post(string identifier)
{
var _customer = FSharpLibrary.setCurrentCustomer(identifier);
// code
}
// setCurrentCustomer function:
let mutable CurrentCustomer:Customer option = None
let setCurrentCustomer() =
CurrentCustomer <- customer |> Some
CurrentCustomer
Is there any way to avoid changing state by changing CurrentCustomer?
I know I could create a function that takes a CurrentCustomer object and returns a new CurrentCustomer object, but how will the customersController know what is the current customer set to?
Is there any way of avoiding having this global mutable variable Customer?
Is there any way to avoid changing state by changing CurrentCustomer?
Yes, there are many ways to do that, but most will involve changing the design of your FSharpLibrary so that it doesn't rely on mutable state.
As a completely general answer, you could apply the State Monad, but something less involved is often sufficient. Exactly what that would be, however, is impossible to answer without knowing what you are attempting to accomplish.
how will the customersController know what is the current customer set to?
It already knows, because it's setting the current customer to the identifier argument from the Post method. That value is in scope throughout the entire method.
The question is why your FSharpLibrary has mutable state? Can't you instead implement it with pure functions?

Why are these contravariant argument types considered safe?

I just learned in my programming languages class that "contravariant argument types would actually be safe, but they have not been found useful and are hence not supported in practical languages." Even though they are not supported, I am confused as to why something like this example we were given would still be, in theory, "safe":
class Animal {
...
public bool compare(Panda) { ... }
}
class Panda extends Animal {
...
public bool compare(Animal) { ... }
}
From what I understand, problems with subtyping come up when something is done that could cause a loss of specificity. So what if I did this? :
Panda p = new Panda();
Animal a = new Animal
...
p.compare(a);
When I look at this, it seems like panda could (and probably does) have some extra fields in it that a plain animal wouldn't know about. Thus, even if all of their animal-specific data members are the same, a panda can have other stuff that differs. How would that make it okay to compare it to a plain animal? Would it just consider the animal-only stuff and ignore the rest?
In your example you don't use any generic types. You have Panda extending Animal, and it's an example of inheritance and leads to polymorphism which is more or less what you describe. Check the links.
To get contravariance, you need to consider some generic type. I'll use .NET type IComparer`1[T] as an example. With C# syntax (which I'll use rather than Java), we indicate that IComparer is contravariant in T by writing in in the definition:
public interface IComparer<in T>
{
...
}
Suppose I have a method which returns an IComparer`1[Animal] (or IComaparer<Animal>), like:
static IComparer<Animal> CreateAnimalComparer()
{
// code that returns something here
}
Now in C#, it's legal to say:
IComparer<Panda> myPandaComparer = CreateAnimalComparer();
Now, this is because of contravariance. Note that the type IComparer<Animal> does not derive from (or "extend") the type IComparer<Panda>. Instead, Panda derives from Animal, and this leads to the IComparer<Xxxx> being assignable to each other (in the opposite order, hence "contravariance" (not "covariance")).
The reason why it's meaningful to declare a Comparer<> contravariant, is if you have a comparer that can compare two arbitrary animals, and return a signed number indicating which is greater, then that same comparer can also take in two pandas and compare those. For pandas are animals.
So the relation
any Panda is an Animal
(from inheritance) leads to the relation
any IComparer<Animal> is an IComparer<Panda>
(by contravariance).
For an example with covariance, the same relation
any Panda is an Animal
leads to
any IEnumerable<Panda> is an IEnumerable<Animal>
by covariance (IEnumerable<out T>).

F# Modify & Return

type Tag(Kids) =
member this.Kids = Kids
static member (-) (this: Tag, that: list<obj>) =
Tag(that::this.Kids)
The point of this code is to construct a new object based on an existing one, but modifying one (or more) fields on the object. Basically, it is a proxy for a thing.setX(...) mutator method, except using immutable data.
It looks incredibly ugly and verbose, and I'm sure there must be a better way of doing it while maintaining the immutability of the data, but I haven't figured out how. Is there some syntactically nice way of doing this?
EDIT: Just for clarity, I also have other classes in the hierarchy:
type HTMLTag(s, Classes, Kids, Styles) =
inherit Tag(Kids)
member this.NominalTag = s
member this.Classes = Classes
member this.Styles: list<String * String> = Styles
static member (-) (this: HTMLTag, that: list<obj>) =
HTMLTag(this.NominalTag, this.Classes, that::this.Kids, this.Styles)
Apart from it being very verbose, the - function's "copy with modification" thing is completely non-generic: even though I am doing the same thing each time (copy w/ modification to same variable) I have to rewrite the whole thing all over again, which isn't very nice.
One thing I find very annoying is that this would be very simple with mutation:
static member (-) (this: Tag, that: list<obj>) =
this.Kids = that :: this.Kids
this
But I'm trying to keep everything immutable as far as possible
Copy and update record expressions[MSDN] are meant to handle this exact case. If you can use a record type instead you can do
type Tag =
{ NominalTag : obj
Classes : obj
Kids : list<obj>
Styles : list<String * String> }
static member (-) (this: Tag, that: list<obj>) =
{ this with Kids = this.Kids # that }
The compiled forms of this code and yours are virtually identical.
Incidentally, it's odd that the (-) operator is being used to append...but I presume this is a contrived case.
UPDATE
Now that you've updated your question I'm confused about what you want to do. If you want to return a new object I don't see how mutation helps you.
A more functional approach (vs inheritance) is to separate your data and behaviors, the data being records and the behaviors functions grouped within a module. If you want behavior to be shared across types, use interfaces. Records can implement interfaces.

Resources