Saturday, July 30, 2011

A Reminder About Implicit Conversion and Default Value Arguments

Implicit conversion is usually undesirable, and as a general rule, single-parameter constructors should be explicit unless there is a specific reason otherwise. Using the explicit keyword, we declare a constructor to be non-converting:
class Stuff
    explicit Stuff(int n)

    // ...

Stuff stuff = 5;            
// error: conversion from ‘int’ to non-scalar type ‘Stuff’ requested

Stuff stuff(5);             // ok
But what if the constructor takes more than one argument, and default values are specified for the additional, or for all arguments? We can still call this constructor using one parameter only. Consider the following example:
class Stuff
    Stuff(int x, int y = 0, int z = 1)

    // ....

Stuff stuff = 5;            // aargh!
The explicit keyword should be used here as well. So, the rule actually applies to:
  • single argument constructors, and
  • multiple argument constructors, if all OR all except one of the arguments have a default value.

Wednesday, July 27, 2011

Lambdas in C++0x, Part I

The new C++0x standard adds support for anonymous functions; so called lambda expressions. The concept of anonymous, or locally defined functions plays a central role in functional programming and has its origin in the Lambda Calculus (λ-Calculus); a theory formulated by Alonzo Church in 1936 (yes, that was before FORTRAN). The basic idea here is to treat functions as first class objects – functions can be stored in variables, passed as arguments, and be used as return values etc.
Lambda expressions are similar to functors (function objects), but with the added advantage of now being an integral part of the language. We can think of them as syntactic sugar for a functor. Just like function objects, lambdas are type-safe and can maintain state.

Using lambda expressions

The lambda term λx.3 represents the anonymous function x → 3, i.e., a function which takes a single input, x and (always) returns 3.

Using the new C++0x lambda syntax, this can be expressed as:
[](int x) { return 3; }
…where the initial square brackets ( [ ] ) are called the lambda introducer and tells the compiler that a lambda expression follows. Since x is irrelevant here, we may simply omit the parameter specification in this case. This leaves us with a very basic function that returns the value 3:
[] { return 3; }

Monday, July 25, 2011

Type Inference in C++: The Return of Auto

With the new C++ standard (C++0x), the auto keyword has returned to the language, like a phoenix rising from the ashes – with new and completely different meaning.

With this new auto, we can ask the compiler to deduce the type of a declared variable from the expression used to initialize it. This feature is known as type inference, and is found in many functional programming languages. Type inference (or type deduction) introduces some of the advantages of dynamic type systems, without incurring the performance penalty and various other negative side-effects associated with relaxed type safety, such as increased risk of run time failure.

A very basic, and not very useful example could look something like:
int x = 1;
auto y = x + 1;
The important thing to note here is that auto is a keyword and not a type. This is to say that, unlike in a dynamically typed language, we can’t assign a value of a different type once the variable has been declared. The type of y (int) must be known at compile time, we just leave to the compiler to figure out what it is.

Saturday, July 23, 2011

Storage Class Specifiers and Name Scope in C++

The following is part of a contribution I made to one of the pages on the
Qt Centre Community Wiki, titled "Going Out of Scope":

In C++, as in many other languages, variables have scope; i.e., a variable or function name can be used only within certain parts of a program. This "area of visibility" is referred to as the name's scope. Additionally, C and C++ also employ the concepts storage duration and linkage. Storage duration determines how and when during program execution an identifier exists in memory – the lifetime of its storage. Linkage affects a name's visibility across translation units (the contents of a single source file, plus the contents of any header files included by it).

The two concepts that are most relevant here are scope and storage duration.