Const as a supertype

May 9, 2017, 11:31 p.m.

My professor once told us that, following the common OOP polymorphism rules, one can consider that the const or volatile versions of a type (e.g. in C or C++) to be the supertype of the non-qualified type.

It didn't make a lot of sense to me back then.

Usually when people explain super/subtyping, they think about substitutability. If you can say with confidence that A is a B, then A is a subtype of B. As a common OOP example, a Student is a Person. You cannot say, always, that a Person is a Student. This suggests a subtype relationship in one direction.

So putting my professor's words into that context, he is asserting that an int is always a const int, while a const int is not always an int.

This still made no sense - a red balloon is obviously a balloon, but a balloon is not always a red balloon. Intuitively, the qualifier should result in a subtype.

However, there is a more precise way (short of drawing arcane greek symbols) to think about substitutability than the handwavy "is a" thing. If A is a subtype of B, then it should be the case that B can be "safely used" wherever A is expected. Let's think about it in this context then.

If I have an int, can I safely pretend that it's a const int instead? Actually, yes. That's why you can easily cast an int to a const int, but not vice versa. You can do all the same read-only operations as before. The read-only operations are what a const int possesses; an int simply "inherited" those operations. Any write operations are only "defined" for the subtype int. An int can do everything a const int can, plus more.

What about volatile? That's a bit more subtle because the allowable operations are seemingly the same, but it still makes sense if you consider what it means for "an int to safely pretend to be a volatile int". When you add volatile to a type, the compiler no longer saves the value into a register. Each read or write will always go to memory (or more likely, the L[1-3] caches). It makes sense then that always reading from memory is "safer" than relying on the register value, which may be wrong if another thread or piece of hardware changed the canonical value in the memory address. You can thus say an int can safely pretend to be volatile, but not the other way around.

C++ implicit conversion 2

April 22, 2017, 8:23 p.m.

Better than just single-step implicit conversion, we can go deeper.

struct Wat {
    Wat(bool b) {};
};
void foo(Wat w) {};

Now you can do:

foo(new int);

A int* is passed to foo, but that's not a Wat. So the compiler first coerces the pointer to become a bool (remember, that's how people often check for NULL pointers), which is then used to construct a Wat to be passed into foo.

this is fine

Javascript Variable Scoping

March 12, 2017, 1:25 a.m.

Vanilla Javascript has only function scope and no block scope. Python is like this too, but Python at least doesn't try to mislead you into thinking you can shadow a local variable by redeclaring it inside a block. That's because Javascript variables, without the var "declaration", is implicitly global, whereas Python variables is by default local.

Javascript is pretty messed up. News at 11.

And then when you look up this issue, some people recommend moving all the var declarations to the top of the function. What is this, C89?

Comma Operator

Jan. 13, 2017, 9:11 p.m.

I saw this today:

void foo() {}
void bar() {
    bool b = (foo(), 1);
}

I thought the C++ standards committee sneaked in first-class tuple support under my nose, but no, that's just abusing the comma operator. Something about having a void function call on the right-hand side just rubs me the wrong way though.

The only good use of comma operator that I've seen is doing slightly more complex things in for-loop endings:

for (int i = 1, j = 2; i < 10; i++, j *= 2) {
    ...
}

But I also see some examples of people overloading comma for the tuple class (with some C++11 template magick) so that they can pretend there is first class support. I guess I wasn't that off after all!

C++ enum sizes

Dec. 5, 2016, 10:27 p.m.

How big are C++ enums?

It would be a very boring note if I said 4 bytes. Yes, it can be more than or less than 4, the only requirement in the standard is that the enum can hold all of its enumerated values. That is, different enum types may have different sizes.

Obviously, in practice most sane compilers nowadays would default to 4 bytes. But it's simple to nudge an enum beyond an int.

enum Big {
    BIG_ELE = 1LL << 32
};
assert(sizeof(BIG_ELE) == 8);

It works even with gcc's weird __int128 type!

enum Hueg {
    HUEG_ELE = (__int128)1 << 64
};
assert(sizeof(HUEG_ELE) == 16);

C++11 enum classes also supports this, but only if you specify a data type for the enum class (otherwise, it will assume int by default, and throw a compiler error).



Page 1/6 >> older