I am new to Kotlin,
data class RewardDetail(
val name: String
val isActivated: Boolean
val amountInCents: Int?
val Campain: String?
val expirationDate: Long?
)
class Rewards(Array<Reward>)
class Reward(
val name: String
isActive: Boolean
amountInCents: Int
campaignId: String
expirationDate: LocalDateTime
)
val details : List<RewardDetail> = blablabla
val rewards = Rewards(details)
can details cast to rewards successfully?
Also note campaignId and Campain field name are different in RewardDetail and Reward and some fields can be nullable in RewardsDetail
What is the best way to handle situation like this?
Kotlin is strongly-typed. You can never successfully cast one thing into a different class. You can only cast an object into a type that it already satisfies. For example, if you have an Int that is currently only known to the compiler to be a Number, you can cast to Int to tell the compiler that it has an Int, so the compiler will allow you to use the functions that are specific to Int. But nothing but an Int can ever be cast to an Int.
So, unlike weakly typed languages, casting does not convert from one type to another. Casting is only you making a promise to the compiler that an object already is of the other type.
In your example, the only way to get a RewardDetail from a Reward is by writing a function that manually converts each property to the appropriate type.
The Rewards class above is largely redundant. There's no need for a wrapper class around a single Array or List unless you need to do validation of items added to or retrieved from the list. In that case, it would probably make more sense to create a subclass of ArrayList for that purpose, so you could still easily iterate the list and use all the List and Iterable helper functions on it.
Probably about 95% of the time, you should prefer using List over using Array. Arrays should be used only when you need a fixed size collection that is also mutable, or if you are working with highly performance-critical code. The reason it should be limited to these uses is that mutability should be avoided when possible for robustness and Arrays are more cumbersome to work with than MutableLists.
A typical implementation of a function that converts from one type to another would be to write an extension function RewardDetail.toReward() extension function, or a toReward() function inside the RewardDetail class. However, in your case you need to decide what you need to happen when some of the values of RewardDetail are null. Maybe you just return null so your conversion function should be toRewardOrNull(), or you provide default values for the properties that have no value in RewardDetail.
Related
In a Flutter app I have a Row of Columns widget hierarchy. However I'd like to add an extra SizedBox into every alternating column of widgets.
Column getColumn(List<DAO> column, int index, BoardLayout layout) {
final key = column.map((c) => c.toString()).toList().join('_');
final items = column.map((c) => MyWidget(data: c)).toList();
if (index % 2 == 0 && layout == BoardLayout.Hexagonal)
items.add(SizedBox(height: magicNumber));
return Column(children: items);
}
This yields a compile time error of "The argument type 'SizedBox' can't be assigned to the parameter type 'MyWidget'.". That's understandable, because final items must have gotten the inferred type List<MyWidget> and then I wanted to add a SizedBox. All of these have the supertype of Widget though. If I modify this as:
Column getColumn(List<DAO> column, int index, BoardLayout layout) {
final key = column.map((c) => c.toString()).toList().join('_');
List<Widget> items = column.map((c) => MyWidget(data: c)).toList();
if (index % 2 == 0 && layout == BoardLayout.Hexagonal)
items.add(SizedBox(height: magicNumber));
return Column(children: items);
}
It compiles, but then it throws a runtime exception of _TypeError "type 'SizedBox' is not a subtype of type 'MyWidget' of 'value'". I haven't found a way to force cast the list yet. I tried List's cast<T>, and trying explicit (Widget) or (List<Widget>) casting prefixes but none of my tries compiled yet. What's a possible solution for this? Details of MyWidget or DAO doesn't matter, I want the list to be a superclass type so I can add various types of Widgets to it.
When you call column.map, Dart infers the type based on what the inner function returns. In this case, it returns a MyWidget, so even though Dart's type system allows you to declare items as a List<Widget>, it is actually a List<MyWidget>. (This ambiguity is supposedly getting removed in an upcoming version of Dart.)
To fix this, you need to add a type parameter to map to explicitly state what kind of list you want it to return:
List<Widget> items = column.map<Widget>((c) => MyWidget(data: c)).toList();
And on another note, casting in Dart is done using the as keyword. So for example, if you wanted to fix this using casting, it would look like this:
List<Widget> items = column.map((c) => MyWidget(data: c) as Widget).toList();
But the type parameter on map is the cleaner approach in my opinion.
The reason this is a problem is that unlike most programming languages, Dart allows the assignment of supertype values to subtype variables. This essentially means that if you assign a supertype value to a subtype variable, the compilation will allow it even though the runtime will not.
Take the following for example:
int a = 2.5; // Compilation error: double is not int
This code will obviously throw an error because a double is not an int. However, if you change it to the following:
int a = 2.5 as num; // Linter warning: unnecessary cast
The only notification we get on this code in the IDE is that casting a double to a num is unnecessary, but this is now shadowing a pretty grave error. Like before, we are trying to assign a double value to an int variable, but because of the cast, all the compiler sees is that we are trying to assign a num to an int. In most strongly-typed languages this would still result in a compile error since even though all ints are nums, not all nums are ints, so the compatibility between the value and the variable is not guaranteed. Dart, however, decides to allow the assignment anyway in the compilation, and it's not until the program runs that it throws the type mismatch error.
I can't for the life of me come up with a reason why the Dart engineers designed the language this way, since the only practical result of this I can see would be to change an easy-to-spot compilation error into a potentially elusive runtime error. The only possible justification I can come up with is that it's for interoperability with JavaScript (which Dart was originally developed for) and is an artifact of Dart's younger days as a weakly-typed language. This is a pretty major design flaw, and as I said before, I believe that a future version of Dart will remove this "feature" (though I cannot find the page I read that said so, so I hope I'm not just smoking something).
Background
Take this simple java class as an example:
class SomeWrapper {
List<SomeType> internalDataStructure = new ArrayList<>();
boolean hasSomeSpecificSuperImportantElement = false;
// additional fields that do useful things
public void add(SomeType element) {
internalDataStructure.add(element);
if (SUPER_IMPORTANT.equals(element)) {
hasSomeSpecificSuperImportantElement = true;
}
}
public Iterable<SomeType> getContents() {
return internalDataStructure;
}
// additional methods that are definitely useful
}
Although it looks somewhat okay it has a big flaw. Because internalDataStructure is returned as is, callers of getContents() could class cast it to List and modify the internal data structure in ways they are not supposed to.
class StupidUserCode {
void doSomethingStupid(SomeWrapper arg) {
Iterable<SomeType> contents = arg.getContents();
// this is perfectly fine
List<SomeType> asList = (List<SomeType>) contents;
asList.add(SUPER_IMPORTANT);
}
}
In java and in other, similar programming languages, this problem can be solved by wrapping the internal data structure in some immutable wrapper. For example:
public Iterable<SomeType> getContents() {
return Collections.unmodifiableList(internalDataStructure);
}
This works now, but has, in my humble opinion, a number of drawbacks:
tiny performance drawback, not a big deal in all but the most extreme circumstances
developers who are new to the language need to learn this immutable API
developers of the standard library need to keep adding immutable support for all kinds of data structures
The code becomes more verbose
The immutable wrapper has a number of public methods that all throw exceptions. This is a rather dirty solution in my opinion because it requires additional documentation for users of the API.
Question
Are there any programming languages where you can specify a return type of a method to be impossible to be class cast?
I was thinking of something like synthetic types where appending an exclamation mark ! to the end of a typename makes it un-class-cast-able. Like this:
public Iterable!<SomeType> getContents() {
return internalDataStructure;
}
void doSomethingStupid(SomeWrapper arg) {
// The ! here is necessary because Iterable is a different type than Iterable!
Iterable!<SomeType> contents = arg.getContents();
// this now becomes a compile-time error because Iterable! can not be cast to anything
List<SomeType> asList = (List<SomeType>) contents;
asList.add(SUPER_IMPORTANT);
}
Since the point here is about mutability, the Java example of List vs. Iterable isn't a great example of mutable vs. immutable data types (the Iterator.remove method mutates the underlying collection, so the List could be corrupted by the external caller even without casting).
Let's instead imagine two types, MutableList and ReadonlyList, where MutableList is the subtype, and a ReadonlyList only prevents the user from mutating it; the list itself is not guaranteed to avoid mutation. (We cannot sensibly name the supertype ImmutableList because no value is both a mutable and an immutable list.)
Casting from the supertype to the subtype, e.g. from ReadonlyList to MutableList, is called downcasting. Downcasting is unsafe, because not every value of the supertype is a value of the subtype; so either a check needs to be performed at runtime (as Java does, throwing ClassCastException if the instance being casted does not have the right type), or the program will do something memory-unsafe (as C might do).
In theory, a language might forbid downcasting on the grounds that it is unsafe; popular programming languages don't, because it's convenient to be able to write code which you know is type-safe, but the language's type system is not powerful enough for you to write suitable type annotations which allow the type-checker to prove that the code is type-safe. And no type-checker can reasonably be expected to prove every provable property of your code. Still, in theory there is nothing stopping a language from forbidding downcasts; I just don't think many people will choose to use such a language for developing large software.
That said, I think the solution to the problem you describe would be simply not to make MutableList a subtype of ReadonlyList. The MutableList class can still have a method to get a read-only view, but since there would be no subtype/supertype relation, that view would not be a value of type MutableList so it could not be cast to the mutable type, even if you upcast to a common supertype first.
To avoid the performance cost at runtime, it could be possible for a language to have specific support for such wrappers to allow the wrapper to delegate its methods to the original list at compile-time instead of at runtime.
This quesiton is composed of a couple parts, the first has to do with the -> operator in a class. Does it take some sort of input (according to the C++ standard)? For example
some_return_type? operator->( long address ) {
cast the address to some sort of pointer and do something with it...
return something?...possibly... maybe not?;
}
So in reality A::SomeMethod() would refer to an address for a function in memory passed to ->. Or
A::someStaticOrNonStaticDataMember would refer to an address for a field?
If so (given that we do not have access to the actual type of the class), or something like this exists, what is it, and can we reconstruct part of a pointer, or align a pointer, (or write a class with an algorithm to do this), for a class based on some information about that class, so that it had an operable -> operator, so one could write:
somePointer->A::SomeMethod();
and have it call A::SomeMethod()? And maybe make context for the memory used in the class?
From the comments it seems you want to control how Compiler handles and generates -> tokens. This is for your bad luck not possible, because Compiler doesn't expose such information, nor is it required by Standard to do so
It is like you are trying to have "dynamic" (the C# type) but in C++, unluckily this is not possible. What could be similiar is wrapping some sort of "Closure collection" addressed by strings (a sort of scripting language) but that would be really heavy and not very nice.
Actually doing what you want with the syntax you showed is not possible.
If the type of an object is not known, then you have that object hided behind a "void *". That means basically that the only way you can use that object is by casting it back to its original type.
Suppose you have a DLL that expose 2 functions (with header files)
// creates an object of given type or null_ptr if no object match
void* getObject(std::string obj_type);
// call a method on that object
void callMethod(void* obj, std::string method_name, void* args, void* returnval);
Actually that solution (even if ugly) allows to call methods on objects that you don't know (it could be a lot better than that.)
But that force you to use void* and strings. That's because how C++ resolve method names (in reality also in C# the "dynamic" type generates behind the scenes reflection code that use strings with method names and is particulary slow)
So something similiar can be achieved with
float fuelLiters = 3.0f;
void * myObj = createObject("SomeCar");
callMethod(myObj,"loadFuel", &fuelLiters, null_ptr);
you probably can make the syntax a little better with templates or some macro, but you'll never be able to do something like
myObj->A::loadFuel(fuelLiters);
What you can do is having the externally loaded class, use the same interfaces of your application, says:
class ICar{
public:
void loadFuel(float liters)=0;
};
In that case you can use a function that cast the opaque object handle to ICar. This is what I already doing in a library I wrote 2 years ago:
So you just need the DLL expose a method for casting the class (downcast)
//if given object is implementing a ICar, the correct pointer is returned, else
// this function will return nullptr (or throw exception if you like more)
void * downcast( typeof(ICar), myObj);
You'll need simply
ICar *myCar = static_cast<ICar>(downcast( typeof(ICar), myObj));
myCar->loadFuel(3.0f);
However note that both the DLL and your application should "know" about what "ICar" is, so they must include the "ICar" header.
doing that is definitely possible, I did it already in 2 different ways, so If you need more details about implementation I'll be happy to show a possible way (given I understood correctly your question).
The arrow operator (->) is a dereference operator that is used exclusively with pointers to objects that have members.
foo->bar() is the same as (*foo).bar()
If you want to overload -> you should also overload *
Lets say I have a List<object> which is passed into a class as an argument, this list should contain a bunch of models for my application all of the same type. Is it then possible for me to somehow retrieve the type of the list which was passed in? (without calling GetType() on a item in the list).
For example, I pass in List<User> which is stored as List<object>, can I now retrieve the type User from the list without doing something like:
List<object> aList;
aList[0].GetType();
Well, you can use:
Type elementType = aList.GetType().GetGenericArguments[0];
However, that will fail if you pass in FooList which derives from List<Foo> for example. You could walk the type hierarchy and work things out appropriately that way, but it would be a pain.
If at all possible, it would be better to use generics throughout your code instead, potentially making existing methods generic - e.g. instead of:
public void Foo(List<object> list)
you'd have
public void Foo<T>(List<T> list)
or even
public void Foo<T>(IList<T> list)
If you just need it for the very specific case where the execution-time type will always be exactly List<T> for some list, then using GetGenericArguments will work... but it's not terribly nice.
As I understand it, the purpose of generics is to not have to do the type checking manually. The compiler ensures that the items in the list are the type they claim to be, and therefore the items that come out will be that type.
If you have a List<object>, you're defeating the purpose of using generics at all. A List<object> is a list that can store any type of object, no matter what types you actually put into it. Therefore, the onus is upon you to detect what the actual type of the object you retrieve is.
In short: you have to use GetType.
I'm developing a game and I need to find a way of getting the value of a certain 'map block' in the game (in char format). I have a class DisplayableObject which takes care of all sprites, and a sub-class ThreeDCubePlayer which takes care of the player object. For ease of rendering/updating everything, all DisplayableObjects are stored in an array, with the 0th cell containing the player (which is of type ThreeDCubePlayer). ThreeDCubePlayer has a different constructor from DisplayableObject (it takes two additional arguments) and only ThreeDCubePlayer has the GetMap() functions that I need. So, here is what I have done so far:
ThreeDCubePlayer* cubePlayer = &((ThreeDCubePlayer &)m_ppDisplayableObjects[0]);
char mapEntry = GetMapEntry((int)*(cubePlayer->GetMapX()), (int)*(cubePlayer->GetMapY()));
This is the part of ThreeDCubeGame.cpp (the function which controls the map and keyboard input). The problem I've had is that both of these lines give an 'illegal indirection' error at compilation. I thought this error is when I try to dereference something that isn't a pointer, and I'm sure cubePlayer looks like a pointer...
Does anyone have an idea as to what I should do?
Use one of the type safe casts, e.g. dynamic_cast instead of the C-style cast.
If m_ppDisplayableObjects is a DisplayableObject**, then it would look something like this:
ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);
if (cubePlayer != NULL)
{
char mapEntry = GetMapEntry(cubePlayer->GetMapX(), cubePlayer->GetMapY());
}
else // Not a ThreeDCubePlayer* ...
A couple of suggestions:
Don't use the C-style casts, use proper C++ casts instead. In your case, as you're casting down the inheritance hierarchy, you should be using dynamic_cast instead of the sledgehammer C-style cast. This will incur a small runtime overhead but it'll also make the whole thing type safe inasmuch as it isn't going to do something nasty behind your back simply because you're treating a chunk of $deity_knows_what as a ThreeDCubePlayer. Assuming that your m_ppDisplayableObjects array actually holds pointers, it'll look like this:
ThreeDCubePlayer *cubePlayer = dynamic_Cast<ThreeDCubePlayer *>(m_ppDisplayableObjects[0])
if (cubePlayer) { // Important, if you don't check for 0 here you might dereference a null pointer
... cubePlayer->GetMapX() ...
Also, if you have to cast the result of the GetMapX then you have an impedance mismatch that you should sort out somewhere else; I'd recommend either adjusting the return type of GetMapX or the parameters passed to GetMapEntry. Usually, having to wildly cast about is a sign of a design issue - well-designed C++ code should not require a lot of casts and especially not a lot of C-style casts.
Your cast is wrong, and I think the second line requires no cast at all (depends on how the methods are defined).
It should be:
ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer*)m_ppDisplayableObjects[0];
char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );
The cast in the first line should also be a C++ style cast, e.g.:
ThreeDCubePlayer* cubePlayer = static_cast<ThreeDCubePlayer*>(m_ppDisplayableObjects[0]);
Be aware that in a game application, having a situation where you end up doing zillions of dynamic_casts per game frame can negatively impact performance. You'll usually find people doing other solutions to determine how to recast a object pointer stored in a container to the appropriate object type using static_cast or C style casting rather than relying on RTTI. Depending on the number of object types and other factors, there are various ways of doing this, but a simple method is just to have a enum class id and a get method for each of the enum types that returns null if the class id doesn't match the one being requested.
For the first line, you can cast the DisplayableObject to the derived class ThreeDCubePlayer type using dynamic_cast.
ThreeDCubePlayer* cubePlayer = dynamic_cast<ThreeDCubePlayer*> (m_ppDisplayableObjects[0]);
For the second line, you're dereferencing whatever is returned by ThreeDCubePlayer::GetMapX(). If that function doesn't return a pointer (or some class with an overloaded * operator), you'll get a compilation error.
You haven't given much code to go on, but I think your first line should be:
ThreeDCubePlayer* cubePlayer = (ThreeDCubePlayer *) m_ppDisplayableObjects[0]);
We'd need to see the declaration of GetMapX() to know about the second line.
ppDisplayableObjects is an array or base pointers isn't it?
so try this?
const ThreeDCubePlayer* const cubePlayer = m_ppDisplayableObjects[0];
char mapEntry = GetMapEntry( cubePlayer->GetMapX(), cubePlayer->GetMapY() );
GetMapX etc. ought to return an (unsigned) int? and not a pointer to an int? (no negs? so unsigned?)
I'd like to second everyone else's comments on casting, they're a sign that your hierachy is not working quite right, but... but if you do have to cast then thinking about which C++ cast you'd need to use is a useful exercise, it also means when you want to revisit/tighten up your code all the casts are easier to search out and remove
ps - rack up your constness too where you can
and add the arrays etc to some sort of owner class, maybe a singleton if you know you've only got the one
also IMHO... (sorry) write yourself a Coords class so that you can do things like GetMapEntry(const Coords& coords) instead of getting the x and the y values separately, this'll save you getting them swapped round the wrong way etc.
:)