Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

To what extent is C++ a statically-typed language?

Tags:

I used to think that the answer to this question was "100%", but I've recently been pointed to an example that makes it worth thinking twice. Consider a C array declared as an object with automatic storage duration:

int main()
{
    int foo[42] = { 0 };
}

Here, the type of foo is clearly int[42]. Consider, instead, this case:

int main()
{
    int* foo = new int[rand() % 42];
    delete[] foo;
}

Here, the type of foo is int*, but how can one tell the type of the object created by the new expression at compile-time? (Emphasis is meant to stress the fact that I am not talking about the pointer returned by the new expression, but rather about the array object created by the new expression).

This is what Paragraph 5.3.4/1 of the C++11 Standard specifies about the result of a new expression:

[...] Entities created by a new-expression have dynamic storage duration (3.7.4). [ Note: the lifetime of such an entity is not necessarily restricted to the scope in which it is created. —end note ] If the entity is a non-array object, the new-expression returns a pointer to the object created. If it is an array, the new-expression returns a pointer to the initial element of the array.

I used to think that in C++ the type of all objects is determined at compile-time, but the above example seems to disprove that belief. Also, per Paragraph 1.8/1:

[...] The properties of an object are determined when the object is created. An object can have a name (Clause 3). An object has a storage duration (3.7) which influences its lifetime (3.8). An object has a type (3.9). [...]

So my questions are:

  1. What is meant by "properties" in the last quoted paragraph? Clearly, the name of an object cannot count as something which is determined "when the object is created"- unless "created" here means something different than I think;
  2. Are there other examples of objects whose type is determined only at run-time?
  3. To what extent is it correct to say that C++ is a statically-typed language? Or rather, what is the most proper way of classifying C++ in this respect?

It would be great if anybody could elaborate at least on one of the above points.

EDIT:

The Standard seems to make it clear that the new expression does indeed create an array object, and not just several objects laid out as an array as pointed out by some. Per Paragraph 5.3.4/5 (courtesy of Xeo):

When the allocated object is an array (that is, the noptr-new-declarator syntax is used or the new-type-id or type-id denotes an array type), the new-expression yields a pointer to the initial element (if any) of the array. [ Note: both new int and new int[10] have type int* and the type of new int[i][10] is int (*)[10] —end note ] The attribute-specifier-seq in a noptr-new-declarator appertains to the associated array type.

like image 833
Andy Prowl Avatar asked Apr 10 '13 23:04

Andy Prowl


People also ask

Is C statically typed language?

A statically-typed language is a language (such as Java, C, or C++) where variable types are known at compile time. In most of these languages, types must be expressly indicated by the programmer; in other cases (such as OCaml), type inference allows the programmer to not indicate their variable types.

Is C statically or dynamically-typed?

Statically typed languages: Statically typed languages are the languages like C, C++, Java, etc, In this type of language the data type of a variable is known at the compile time which means the programmer has to specify the data type of a variable at the time of its declaration.

Is C strongly or weakly typed?

C is strongly typed in that the variable type must be specified when declaring the variable. However, C can also be regarded as weakly typed because users can convert data types through a cast and without compiler errors.

Is C sharp a statically typed language?

C# — pronounced “see sharp” — is an object-oriented and statically typed computer programming language created by Microsoft for use on its . NET platform.


2 Answers

The new-expression doesn't create an object with runtime-varying array type. It creates many objects, each of static type int. The number of these objects is not known statically.


C++ provides two cases (section 5.2.8) for dynamic type:

  • Same as the static type of the expression
  • When the static type is polymorphic, the runtime type of the most-derived object

Neither of these gives any object created by new int[N] a dynamic array type.


Pedantically, evaluation of the new-expression creates an infinite number of overlapping array objects. From 3.8p2:

[ Note: The lifetime of an array object starts as soon as storage with proper size and alignment is obtained, and its lifetime ends when the storage which the array occupies is reused or released. 12.6.2 describes the lifetime of base and member subobjects. — end note ]

So if you want to talk about the "array object" created by new int[5], you have to give it not only type int[5] but also int[4], int[1], char[5*sizeof(int)], and struct s { int x; }[5].

I submit that this is equivalent to saying that array types do not exist at runtime. The type of an object is supposed to be restrictive, information, and tell you something about its properties. Allowing a memory area to be treated as an infinite number of overlapping array objects with different type in effect means that the array object is completely typeless. The notion of runtime type only makes sense for the element objects stored within the array.

like image 33
Ben Voigt Avatar answered Nov 07 '22 03:11

Ben Voigt


The terms 'static type' and 'dynamic type' apply to expressions.

static type

type of an expression (3.9) resulting from analysis of the program without considering execution semantics


dynamic type

<glvalue> type of the most derived object (1.8) to which the glvalue denoted by a glvalue expression refers

Additionally, you can see that a dynamic type only differs from a static type when the static type can be derived from, which means a dynamic array type is always the same as the expression's static type.

So your question:

but how can one tell the type of the object created by the new expression at compile-time?

Objects have types, but they're not 'static' or 'dynamic' types absent an expression that refers to the object. Given an expression, the static type is always known at compile time. In the absence of derivation the dynamic type is the same as the static type.

But you're asking about objects' types independent of expressions. In the example you give you've asked for an object to be created but you don't specify the type of object you want to have created at compile time. You can look at it like this:

template<typename T>
T *create_array(size_t s) {
    switch(s) {
        case 1: return &(*new std::array<T, 1>)[0];
        case 2: return &(*new std::array<T, 2>)[0];
        // ...
    }
}

There's little special or unique about this. Another possibility is:

struct B { virtual ~B() {}};
struct D : B {};
struct E : B {};

B *create() {
    if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
        return new D;
    }
    return new E;
}

Or:

void *create() {
    if (std::bernoulli_distribution(0.5)(std::default_random_engine())) {
        return reinterpret_cast<void*>(new int);
    }
    return reinterpret_cast<void*>(new float);
}

The only difference with new int[] is that you can't see into its implementation to see it selecting between different types of objects to create.

like image 89
bames53 Avatar answered Nov 07 '22 03:11

bames53