When can you use the 'as' operator? - casting

I have the following program:
fun main(args: Array<String>) {
var a: Int
var b = 23.5
a = b as Int
println(a)
}
If I run it, the program throws a java.lang.ClassCastException exception.
Since the data types used in Kotlin are represented as objects, I can understand why it is not possible to frivolously cast them like I have, and instead should use the built-in conversion methods associated with each type or the "safe" as? operator -- but then this brings the question: when can (or should) you use the as operator?

Kotlin compiler's smart casts are pretty smart, so in most cases you don't need explicit casting. This code in Java:
Object foo = "foo";
if (foo instanceof String) {
String fooString = (String) foo;
System.out.println(fooString.length);
}
would translate to this Kotlin code:
val foo: Any = "foo"
if (foo is String) {
println(foo.length)
}
However, as and as? are still relevant, e.g.:
fun test(foo: Any) {
val fooString = foo as? String ?: throw IllegalArgumentException()
...
}
Overall, rely on smart casts as much as you can and leave as and as? for specific cases.

In your example, b is a Double floating-point value, not an Int.  (As other answers have pointed out.)  To convert it, you'd need to use something like b.toInt().
Your program doesn't convert it, because Kotlin's as operator doesn't change the value into a new type; instead it tells the compiler that the value is already of the required type.  That's called a cast.
So for example, if I have:
val n: Number = 4
Then the type of n is Number.  Its current value is actually an Int (which is a subclass of Number).  So in this case I can cast it to Int, e.g.:
val i = n as Int
after which the compiler will treat it like an Int.
(This particular case is a down-cast, because Int is below Number in the class hierarchy.  In general, up-casts are safe but down-casts and others aren't.  If you had initialised n with a floating-point number instead, then its value would be of type Double, which is another subclass of Number, and not an Int; the program would fail at run-time and throw a ClassCastException, as you saw.  That's why Kotlin also has a safe-cast operator, as?, which gives null instead of the exception.)
The Kotlin compiler is very smart, and most of the time it already knows what type a value can be, so casting isn't needed very often.  There can still be occasions when you know something the compiler doesn't, and a cast is appropriate; but too many of them can be a ‘code smell’ indicating that there may be a better approach.

Related

Why can you do this conversion?

Why can you do this:
class Dummy {
double i,j;
};
class Addition {
int x,y;
public:
Addition (int a, int b) { x=a; y=b; }
int result() { return x+y;}
};
int main () {
Dummy d;
Addition * padd;
padd = (Addition*) &d;
cout << padd->result();
return 0;
}
Why is padd = (Addition*) &d; valid when it will generate a run-time error whenever it gets used afterwards? A quote from cplusplus.com:
Unrestricted explicit type-casting allows to convert any pointer into
any other pointer type, independently of the types they point to.
But why can you convert any pointer into any other pointer type just if you precede the reference with a casting operator?
Talking about that casting operator, how can it convert all types to another type? Does it call a conversion constructor because if so, I do not get it, because both Dummy nor Addition do not have a conversion constructor so how does this operation work then? How many operators does it have and is it the parentheses that are the operator itself, like = is an operator.
These kinds of casts are C style casts, and will let you cast just about anything to anything else. A cast is a statement to the compiler to disregard it's type safety rules and trust that you know best. This is sometimes necessary when the type system can't have all the information it needs to reach the right conclusions. However, if you are lying to the compiler about something's type, then you are producing undefined behavior.
In c++, you should avoid preforming C style casts and prefer the safer c++ alternatives (listed here. Theses casts can't completely protect you from yourself, but they do allow you to communicate the kind of cast you want to preform. Using this extra information, the compiler can warn you if your casts would do something other than what you expect them to do.
When you use:
padd = (Addition*) &d;
the compiler assumes that you, the person in charge, know what you are doing. If you shoot yourself in the foot, that's of your own choosing. The compiler is happy to let you do that.
If you would like the compiler to prevent you from such accidental, shoot-yourself-in-the-foot, situations, use static_cast.
padd = static_cast<Addition*>(&d);
The compiler will let you know that that is not OK.
If you use a C style cast, there is no check for errors or compatibility between the pointers. Also, I think you misunderstand the purpose of the unary operator &, in this case it gives the address of d and is not related to references.
Objects in memory are just bits that the program knows to be some type, if you tell it that it is another type it will not affect anything in the variable.

Templated function can't convert 'int' to nullptr_t

TL;DR:
Why can't templated functions access the same conversions that non-templated functions can?
struct A {
A(std::nullptr_t) {}
};
template <typename T>
A makeA(T&& arg) {
return A(std::forward<T>(arg));
}
void foo() {
A a1(nullptr); //This works, of course
A a2(0); //This works
A a3 = makeA(0); //This does not
}
Background
I'm trying to write some templated wrapper classes to use around existing types, with the goal of being drop-in replacements with minimal need to rewrite existing code that uses the now-wrapped values.
One particular case I can't get my head around is as follows: we have a class which can be constructed from std::nullptr_t (here called A), and as such, there's plenty of places in the code base where someone has assigned zero to an instance.
However, the wrapper cannot be assigned a zero, despite forwarding the constructors. I have made a very similar example that reproduces the issue without using an actual wrapper class - a simple templated function is sufficient to show the issue.
I would like to allow that syntax of being able to assign zero to continue to be allowed - it isn't my favourite, but minimising friction to moving to newer code is often a necessity just to get people on board with using them.
I also don't want to add a constructor that takes any int other than zero because that's very much absurd, was never allowed before, and it should continue to be caught at compile time.
If such a thing is not possible, it would satisfy me to find an explanation, because with as much as I know so far, it makes no sense to me.
This example has the same behaviour in VC++ (Intellisense seems to be OK with it though...), Clang, and GCC. Ideally a solution will also work in all 3 (4 with intellisense) compilers.
A more directly applicable example is follows:
struct A {
A(){}
A(std::nullptr_t) {}
};
template <typename T>
struct Wrapper {
A a;
Wrapper(const A& a):a (a) {}
template <typename T>
Wrapper(T&& t): a(std::forward<T>(t)){}
Wrapper(){}
};
void foo2() {
A a1;
a1 = 0; // This works
Wrapper<A> a2;
a2 = 0; //This does not
}
Why has the compiler decided to treat the zero as an int?
Because it is an integer.
The literal 0 is a literal. Literals get to do funny things. String literals can be converted into const char* or const char[N], where N is the length of the string + NUL terminator. The literal 0 gets to do funny things too; it can be used to initialize a pointer with a NULL pointer constant. And it can be used to initialize an object of type nullptr_t. And of course, it can be used to create an integer.
But once it gets passed as a parameter, it can't be a magical compiler construct anymore. It becomes an actual C++ object with a concrete type. And when it comes to template argument deduction, it gets the most obvious type: int.
Once it becomes an int, it stops being a literal 0 and behaves exactly like any other int. Not unless it is used in a constexpr context (like your int(0)), where the compiler can figure out that it is indeed a literal 0 and therefore can take on its magical properties. Function parameters are never constexpr, and thus they cannot partake in this.
See [conv.ptr]/1:
A null pointer constant is an integer literal with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type [...]
So the integer literal 0 can be converted to a null pointer. But if you attempt to convert some other integer value, that is not a literal, to a pointer type then the above quote does not apply. In fact there is no other implicit conversion from integer to pointer (since none such is listed in [conv.ptr]), so your code fails.
Note: Explicit conversion is covered by [expr.reinterpret.cast]/5.

why std::string is not implicitly converted to bool

Is there a reason why in c++ std::string is not implicitly converted to bool? For example
std::string s = ""
if (s) { /* s in not empty */ }
as in other languages (e.g. python). I think it is tedious to use the empty method.
This probably could be added now that C++11 has added the concepts of explicit conversions and contextual conversion.
When std::string was designed, neither of these was present though. That made classes that supported conversion to bool fairly difficult to keep safe. In particular, that conversion could (and would) happen in lots of cases you almost never wanted it to. For example, if we assume std::string converts to false if empty and otherwise to true, then you could use a string essentially anywhere an integer or pointer was intended.
Rather than telling you about the type mismatch, the compiler would convert the string to bool, and then the bool to an integer (false -> 0, true -> 1).
Things like this happened often enough with many early attempts at string types (and there were many) that the committee apparently decided it was better to keep implicit conversions to an absolute minimum (so about the only implicit conversion supported by string is to create a string object from a C-style string).
There were a number of methods devised for handling conversion to bool more safely. One was converting to void * instead, which prevented some problems, but not others (this was used by iostreams). There was also a "safe bool" idiom (actually, more like a "safe bool" theme, of which there were several variations). While these certainly improved control over what conversions would and wouldn't be allowed, most of them involved a fair amount of overhead (a typical safe bool required a base class of ~50 lines of code, plus derivation from that base class, etc.)
As to how explicit conversion and contextual conversion would help, the basic idea is pretty simple. You can (starting with C++11) mark a conversion function as explicit, which allows it to be used only where an explicit cast to the target type is used:
struct X {
explicit operator bool() { return true; }
};
int main() {
X x;
bool b1 = static_cast<bool>(x); // compiles
bool b2 = x; // won't compile
}
Contextual conversion adds a little to let the conversion to bool happen implicitly, but only in something like an if statement, so using a class with the conversion function above, you'd get:
X x;
if (x) // allowed
int y = x; // would require explicit cast to compile
I'd add that complaints about "orthogonality" seem quite inapplicable here. Although convenient, converting a string to a Boolean doesn't really make a lot of sense. If anything, we should complain about how strange it is for string("0") to convert to 1 (in languages where that happens).
This article mentions some reasons why operator bool() can lead to surprising results.
Note that std::string is just a typedef for std::basic_string<char>. There is also std::wstring for multi-byte characters. An implicit conversion would let you write:
std::string foo = "foo";
std::wstring bar = "bar";
if (foo == bar) {
std::cout << "This will be printed, because both are true!\n";
}
std::string still has to coexist with C-style strings.
A C-style string is by definition "a contiguous sequence of characters terminated by and including the first null character", and is generally accessed via a pointer to its first character. An expression such as "hello, world" is, in most contexts, implicitly converted to a pointer to the first character. Such a pointer may then be implicitly converted to bool, yielding true if the pointer is non-null, false if it's null. (In C, it's not converted to bool, but it can still be used directly as a condition, so the effect is nearly the same.)
So, due to C++'s C heritage, if you write:
if ("") { ... }
the empty string is already treated as true, and that couldn't easily be changed without breaking C compatibility.
I suggest that having a C-style empty string evaluate as true and a C++ empty std::string evaluate as false would be too confusing.
And writing if (!s.empty()) isn't that difficult (and IMHO it's more legible).
The closest thing to what you (and I) want, that I've been able to find, is the following.
You can define the ! operator on std::string's like so:
bool operator!(const std::string& s)
{
return s.empty();
}
This allows you to do:
std::string s;
if (!s) // if |s| is empty
And using a simple negation, you can do:
if (!!s) // if |s| is not empty
That's a little awkward, but the question is, how badly do you want to avoid extra characters? !strcmp(...) is awkward, too, but we still functioned and got used to it, and many of us preferred it because it was faster than typing strcmp(...) == 0.
If anyone discovers a way to do if (s), in C++, please let us know.

why implicit conversion is harmful in C++

I understand that the keyword explicit can be used to prevent implicit conversion.
For example
Foo {
public:
explicit Foo(int i) {}
}
My question is, under what condition, implicit conversion should be prohibited? Why implicit conversion is harmful?
Use explicit when you would prefer a compiling error.
explicit is only applicable when there is one parameter in your constructor (or many where the first is the only one without a default value).
You would want to use the explicit keyword anytime that the programmer may construct an object by mistake, thinking it may do something it is not actually doing.
Here's an example:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
With the following code you are allowed to do this:
int age = 29;
//...
//Lots of code
//...
//Pretend at this point the programmer forgot the type of x and thought string
str s = x;
But the caller probably meant to store "3" inside the MyString variable and not 3. It is better to get a compiling error so the user can call itoa or some other conversion function on the x variable first.
The new code that will produce a compiling error for the above code:
class MyString
{
public:
explicit MyString(int size)
: size(size)
{
}
//... other stuff
int size;
};
Compiling errors are always better than bugs because they are immediately visible for you to correct.
It introduces unexpected temporaries:
struct Bar
{
Bar(); // default constructor
Bar( int ); // value constructor with implicit conversion
};
void func( const Bar& );
Bar b;
b = 1; // expands to b.operator=( Bar( 1 ));
func( 10 ); // expands to func( Bar( 10 ));
A real world example:
class VersionNumber
{
public:
VersionNumber(int major, int minor, int patch = 0, char letter = '\0') : mMajor(major), mMinor(minor), mPatch(patch), mLetter(letter) {}
explicit VersionNumber(uint32 encoded_version) { memcpy(&mLetter, &encoded_version, 4); }
uint32 Encode() const { int ret; memcpy(&ret, &mLetter, 4); return ret; }
protected:
char mLetter;
uint8 mPatch;
uint8 mMinor;
uint8 mMajor;
};
VersionNumber v = 10; would almost certainly be an error, so the explicit keyword requires the programmer to type VersionNumber v(10); and - if he or she is using a decent IDE - they will notice through the IntelliSense popup that it wants an encoded_version.
Mostly implicit conversion is a problem when it allows code to compile (and probably do something strange) in a situation where you did something you didn't intend, and would rather the code didn't compile, but instead some conversion allows the code to compile and do something strange.
For example, iostreams have a conversion to void *. If you're bit tired and type in something like: std::cout << std::cout; it will actually compile -- and produce some worthless result -- typically something like an 8 or 16 digit hexadecimal number (8 digits on a 32-bit system, 16 digits on a 64-bit system).
At the same time, I feel obliged to point out that a lot of people seem to have gotten an almost reflexive aversion to implicit conversions of any kind. There are classes for which implicit conversions make sense. A proxy class, for example, allows conversion to one other specific type. Conversion to that type is never unexpected for a proxy, because it's just a proxy -- i.e. it's something you can (and should) think of as completely equivalent to the type for which it's a proxy -- except of course that to do any good, it has to implement some special behavior for some sort of specific situation.
For example, years ago I wrote a bounded<T> class that represents an (integer) type that always remains within a specified range. Other that refusing to be assigned a value outside the specified range, it acts exactly like the underlying intger type. It does that (largely) by providing an implicit conversion to int. Just about anything you do with it, it'll act like an int. Essentially the only exception is when you assign a value to it -- then it'll throw an exception if the value is out of range.
It's not harmful for the experienced. May be harmful for beginner or a fresher debugging other's code.
"Harmful" is a strong statement. "Not something to be used without thought" is a good one. Much of C++ is that way (though some could argue some parts of C++ are harmful...)
Anyway, the worst part of implicit conversion is that not only can it happen when you don't expect it, but unless I'm mistaken, it can chain... as long as an implicit conversion path exists between type Foo and type Bar, the compiler will find it, and convert along that path - which may have many side effects that you didn't expect.
If the only thing it gains you is not having to type a few characters, it's just not worth it. Being explicit means you know what is actually happening and won't get bit.
To expand Brian's answer, consider you have this:
class MyString
{
public:
MyString(int size)
: size(size)
{
}
// ...
};
This actually allows this code to compile:
MyString mystr;
// ...
if (mystr == 5)
// ... do something
The compiler doesn't have an operator== to compare MyString to an int, but it knows how to make a MyString out of an int, so it looks at the if statement like this:
if (mystr == MyString(5))
That's very misleading since it looks like it's comparing the string to a number. In fact this type of comparison is probably never useful, assuming the MyString(int) constructor creates an empty string. If you mark the constructor as explicit, this type of conversion is disabled. So be careful with implicit conversions - be aware of all the types of statements that it will allow.
I use explicit as my default choice for converting (single parameter or equivalent) constructors. I'd rather have the compiler tell me immediately when I'm converting between one class and another and make the decision at that point if the conversion is appropriate or instead change my design or implementation to remove the need for the conversion completely.
Harmful is a slightly strong word for implicit conversions. It's harmful not so much for the initial implementation, but for maintenance of applications. Implicit conversions allow the compiler to silently change types, especially in parameters to yet another function call - for example automatically converting an int into some other object type. If you accidentally pass an int into that parameter the compiler will "helpfully" silently create the temporary for you, leaving you perplexed when things don't work right. Sure we can all say "oh, I'll never make that mistake", but it only takes one time debugging for hours before one starts thinking maybe having the compiler tell you about those conversions is a good idea.

How should C bitflag enumerations be translated into C++?

C++ is mostly a superset of C, but not always. In particular, while enumeration values in both C and C++ implicitly convert into int, the reverse isn't true: only in C do ints convert back into enumeration values. Thus, bitflags defined via enumeration declarations don't work correctly. Hence, this is OK in C, but not in C++:
typedef enum Foo
{
Foo_First = 1<<0,
Foo_Second = 1<<1,
} Foo;
int main(void)
{
Foo x = Foo_First | Foo_Second; // error in C++
return 0;
}
How should this problem be handled efficiently and correctly, ideally without harming the debugger-friendly nature of using Foo as the variable type (it decomposes into the component bitflags in watches etc.)?
Consider also that there may be hundreds of such flag enumerations, and many thousands of use-points. Ideally some kind of efficient operator overloading would do the trick, but it really ought to be efficient; the application I have in mind is compute-bound and has a reputation of being fast.
Clarification: I'm translating a large (>300K) C program into C++, so I'm looking for an efficient translation in both run-time and developer-time. Simply inserting casts in all the appropriate locations could take weeks.
Why not just cast the result back to a Foo?
Foo x = Foo(Foo_First | Foo_Second);
EDIT: I didn't understand the scope of your problem when I first answered this question. The above will work for doing a few spot fixes. For what you want to do, you will need to define a | operator that takes 2 Foo arguments and returns a Foo:
Foo operator|(Foo a, Foo b)
{
return Foo(int(a) | int(b));
}
The int casts are there to prevent undesired recursion.
It sounds like an ideal application for a cast - it's up to you to tell the compiler that yes, you DO mean to instantiate a Foo with a random integer.
Of course, technically speaking, Foo_First | Foo_Second isn't a valid value for a Foo.
Either leave the result as an int or static_cast:
Foo x = static_cast<Foo>(Foo_First | Foo_Second); // not an error in C++