Saturday 24 September 2011

C++ 101

C++ source programs are translated from text into an executable format the machine can understand by a tool known as a compiler. These come in all shapes and formats. For Windows, the most common compiler is Visual Studio- you can get C++ Express for free. For Linux, the most common compiler is G++. For Mac, the compiler is known as XCode. You will have to refer to your compiler's documentation on how to use it- they mostly follow platform conventions. Visual Studio has a pretty GUI, while G++ is usually invoked through the command line, for example.

The first source program we will convert is known as "Hello, World". It is traditionally the first program written by a novice in a language. In C++, this program looks like this:

#include <iostream>
int main() {
    std::cout << "Hello, World!\n";
}

This will output the text "Hello, World!" to your computer screen. Some compilers like Visual Studio will close the console as soon as the program is done running. In this case, you may need to use a breakpoint. Breakpoints are used to pause a program's execution. You can place a breakpoint on the last line of the program.

This small example program actually includes many both simple and advanced features of C++.











Whew, that's a lot- and it's a simplification, too. Fortunately, most of these topics we need to know next to nothing about to work with something a little easier and of more immediate interest. The only current line of interest is the indented one. The purpose of "std::cout << something;" is to print "something" to the screen. That "something" can be a string literal, as in this case, or it can be various other language-provided types, or it can even be custom user-defined types. For now, we will stick to using it with provided types. In addition, this effect can be chained to produce the same effect- that is, "std::cout << something << something_else;" will print both "something" and "something_else" to the screen.

Computer programs work with objects. These objects act as boxes into which values can be placed. The actual definition of these values can be simple, but it can also be very complex. Objects in C++ always have a known, fixed type that cannot change. Variables are simple, named objects, created and destroyed at predictable, known times. The simplest type available is int. int is a simple integral type that can represent integers of a certain range. C++ offers numerous integral types with varying ranges. In the following program, we will perform a simple computation using int.

#include <iostream>
int main() {
    int i = 5; // This is called a declaration.
    i = i + 4;
    std::cout << "Five plus four is " << i;
}

As you can see, each individual chunk of code in the "main" area must end with a semicolon. These chunks do not necessarily correspond to a line, but they almost always do. Furthermore, the language has no rules about the indentation of code, but again, there's a lot of convention about indenting. All professional programmers indent their code to a greater or lesser degree, and many languages or tools enforce certain styles.

First we declared a variable, called i, of type int. This means that we told the compiler of i's existence so that it could, for example, allocate the necessary memory. You cannot access a variable if it has not been declared. Conceptually, the declaration brings the variable into existence- it simply did not exist before that line. We gave it the initial value of 5. 5 is an integer within int's range and therefore a perfectly good int. The compiler will give you an error if you attempt to initialize an int with a value of a different type that it cannot convert- for example, a string. This kind of variable is technically known as an "automatic-lifetime" variable, but is usually referred to as a "stack" variable or a variable on the stack. There are other kinds of variable that we will meet later.

Next, we added 4 to it. This was achieved by giving it a new value- it's old value, plus four.

Finally, we output it to the screen. This example can be trivially modified to perform other, more complex operations. C++ can cope with arbitrarily complex mathematical expressions. In addition, you may create as many variables as you like.


#include <iostream>
int main() {
    int i = 5; // This is called a declaration.
    int j = 6;
    i = i * j; // Multiplication
    i = (i - j); // C++ also supports parenthesis, with the usual meaning
    i = i / j; // Division
    std::cout << "i is " << i << " and j is " << j;
}

An interesting caveat of integer division is that the result is an integer- any additional decimal places are simply removed. This means that the result of, for example, (3 / 5) is not 0.6, but simply 0. This will be addressed in the next lesson.

Friday 23 September 2011

Direct3D11 and Direct2D

Curse the genius at Microsoft who decided that they should not be allowed to play together. For Windows 8 this is fixed. But does Microsoft know if this will be backdated to Windows 7 and Vista? No. How helpful.

I guess I should just bite the bullet and get over the shared-surfaces rubbish?

Tuesday 20 September 2011

ABI

The ability to pass information between compilers- at compile-time- provides a unique opportunity to rectify the ABI issues present in Standard C++.

Name mangling: Export by ordinal, and associate regular names with their ordinal.
Exception handling: I believe this can be done by exporting the try/catch/throw functionality at run-time. Failing that, I was thinking that the process could be exported at compile-time- like, "This is how I implemented throw, and this is how to implement catch.". Bonus if you've got a platform-specific extant mechanism like SEH.
RTTI: I'm really planning on just having `type_info` as a virtual interface. Then you can pass the values at compile-time, like, typeid(int).name() returns "AMAGAD WTF IMPLEMENTATION IS THIS". As long as your virtual functions are compatible, that'll be good to go.

Calling conventions, structure layouts, and such- feel free to describe in detail how to pass parameters and that baloney.

As such, I believe that all I'd have to do is Standardise the means of this communication, and I'd be golden.

Monday 19 September 2011

Microsoft Fail

How is it that Microsoft can endlessly make the same basic design failures every time? The new Metro API's suck a tremendous amount of bollocks. I mean, I'm glad that we invented some of the more basic C++ features ... again ... but Microsoft obviously has no idea whatsoever how to use them. For example, look at the XAML/Direct3D interop class, Presenter. How the fuck do you use that? The interface doesn't at all support the necessary use cases. And there's the usual ApplicationModel rubbish. As if I need a pre-packaged class to tell me how to design my application. Also, handily, they introduced Object, GetType, and a bunch of other utterly useless run-time reflection style stuff. If I wanted run-time reflection, I'd go use WPF. Metro is going to be as slow as a dog, consume a bunch of memory, and it's got a crappy API to boot.

The only good thing is that sometimes, if you want an app that's pre-packaged, the designer might hide all the shit from you.

Friday 16 September 2011

Windows 8

Honestly, I'm just not sure what to make of it.

Yay, DirectX 11 and Direct2D now play together properly, and it therefore doesn't suck tremendously to attempt to render text with DirectX 11.
Boo, ugly language extensions. Metro isn't C++/CLI, despite the visual similarities, but I am more than suspicious of all those language extensions. What's wrong with ComPtr<T> instead of T^?
It is deterministic destruction, and it does have nice exceptions & such, but I am still feeling kind of iffy about it. What if I want to use GCC to produce Metro applications?

Man, the new C++0x features in VC11 are a poor lot, aren't they? Basically just some bug fixes. Not very impressive at all. I mean, AMP is pretty impressive. But come on.. some of the easier features to do would have been nice? Like, say, default/deleted functions?

I also am not very impressed with Win8's Metro. OK, if I had a tablet, it would be great. But I don't have a tablet and I'd much rather have the desktop. So please dear Lord, stop booting into tablet view first. Also, the new Start bar is good for fuck all.

Friday 9 September 2011

Science

Here's how science works. Scientist(s) A do a study. They publish it in a journal after being reviewed by Scientist(s) B,C,D,etc. If you wish to reject the conclusions of A's study, then get out your relevant qualifications,  and kindly ask a peer-reviewed journal to post your detailed rejection. Or at least make an argument grounded in common sense. Until then, you accept what Scientist(s) A have to say, even if that involves ridiculous things like relativity and space/time, or quantum physics, or that young people have different neurochemistries that enforce different sleep cycles.

Sunday 4 September 2011

Namespaces and types

Firstly, a name change. So far, the language has only been called "DeadMG++" for an informal name. However, I've currently decided to refer to it as WideC. Why this is, I've forgotten long ago, but I figure it's a better interim name. I've been grappling for some time now the idea of a relatively simple problem. How does one store constant expressions in a type? Consider a relatively simple C++ class

class X {
    static const int i = 5;
};
int main() {
    int array[X::i];
}

How does this get replicated in WideC?

In fact, specifically, consider my previous application of a memory allocator. The relative complexity of specifying it was just wrong- because it had to exist in *two* times at once. This means that there's only one real solution- namespaces and types are the same thing. Types represent data that *will* exist. Namespaces represent data that *does* exist. However, conceptually, the two are the same. I already had the beginnings of this idea with accessibility in namespaces, and the follow-up with considering mutable namespaces. Now, I'm going to finalize that with a strict equality- the same idea as Standard.Functional.Function versus a FunctionReference. I also had to solve the infinitely recursive problem of the allocator depending on a hash map- which will depend on the allocator.

I'm thinking of using almost "instant-objects" for this job. That is, namespaces will be automatically default constructed - and they may have construction logic- and they may also have destruction logic. They'll be constructed once from source, and then can be mutated for the "next" phase, and can also be queried as to their contents.

That is, "meta-objects" like the allocator dealie that I posted previously would now be simpler to specify, and in addition, I could get rid of those annoying "compile-time" and "run-time" blocks and simply use deduction.



namespace Standard {
namespace Memory {
namespace Allocator {
    // implicitly "private" and "compile-time"
HashMap(
key := int,
value := VariableReference
allocator := GCAllocator
) Pools;
VariableReference Default := HeapAllocator; // basically "new"
GetAllocator(Size)() {
if (Size > 48)
return Default;
if (Pools.Find(Size) == Pools.End())
Pools[Size] = Pool(Size);
return Pools[Size];
}
public {
Allocate(Size)() {
return GetAllocator(Size).Allocate();
}
Allocate(T)() {
return GetAllocator(T.Size()).Allocate(T);
}
Allocate()(Size) {
return Default.Allocate(Size);
}
}
}
}
}

On reflection, I'm not sure that this is actually *better*. Sure, it removes keywords and scoping from the language, but I'm not sure that it's actually better.

Perhaps the fundamental issue here at hand is the N-pass system to begin with. What you're really talking about is a three-pass deal- one to hold the type of the allocator's compile-time stuff, one to hold the type of the allocator's run-time stuff, and one for the run-time itself. Using the namespace might remove the problems of "How do I access the type's compile-time data and call it's compile-time functions through a TypeReference?". Which you can't.

Actually, that's not really true. The data doesn't actually exist at compile-time. It exists in some sort of mid-time. Code-generation time. The issue is that, well, partly, this stuff is bending my mind in ways it was never supposed to go and it's been much too long. And secondly, I never actually intended the language to be able to do that.

I might just opt for the namespace system for now. It's simpler.

Thursday 1 September 2011

Some politics

In the latest United Kingdom General Election, votes per seat breakdown per party:

Conservative: 34980
Labour: 33370
Liberal Democrat: 119944

That is, a Liberal Democrat vote is worth 27.8% of a Labour vote, and 29.2% of a Conservative vote.

If every Lib Dem seat cost as much as a Labour seat, then they would have had 1.9 million votes. Instead, it was 6.8 million votes. That means that 4.9 million people wasted their votes in the UK- a sixth of the turnout.