C/C++ had the potential for automatic garbage collection in the form of the conservative mark-sweep Boehm-Demers-Weiser garbage collector for decades (at least from 1988 onwards). Although an early version of the garbage collector is even included in the GCC distribution, only a few groups actively use it. Some have used it as a leak detector. Boehm himself explains this as due to lack of standardization. With C++11, the hope is that this will change with official sanctioning of garbage collected implementations. The slide presentation you can find in the above link summarizes the design. The argument for garbage collection in C++ is the move to multicore, where the claim is that GC parallelizes better than manual management and that some parallelization techniques are simplified in the presence of GC.
Thursday, January 5, 2012
POPL 2012 Papers
It's just a few weeks until POPL 2012 (Symposium on Principles of Programming Languages, one of the top programming language theory research conferences) in Philadelphia. The program has been out for a while. This time, there are three papers on C/C++ semantics. Apparently we have gotten to the point where researchers have (mechanically) formalized interesting chunks of that large, complicated edifice. The one coming out from INRIA [PDF] has a mechanized (Coq) semantics for C++ construction and destruction including C++11 features. The authors actually give a formal proof of the RAII (resource acquisition is initialization) pattern, specifically that in a terminating program every construction of a subobject is indeed matched by a destruction. The process of developing a formal semantics also helped identify issues in the C++ standard both C++03 and C++11. On the type systems side, there is also a paper from Adobe Research on gradual type systems, especially a type inference scheme with support for dynamic types. One paper describes a type system and language design supporting probability density functions for custom probability distributions and continuous probability. Apparently probability distributions are monads too!
Monday, November 7, 2011
Semantics of Nested Classes
First thing is first, what are nested classes?
class A {
class B { }
}
In essence, they are scoped type declarations and definitions. Instead of defining a class B at the top-level of the program source, one declares a locally scoped one within the definition of another class, A in this case. One immediate consequence of this is a form of namespace management for user-defined aggregate types (i.e., classes). There are a lot of gotchas due the language design here. The scoping discipline is incomplete. C/C++'s restriction on shadowing prohibits the following code:
class B;
class A {
B something;
class B { };
}
In contrast, the following code compiles:
class A {
private:
class B {};
public:
B makeB();
}
Despite the fact that A::B is unnameable outside an instance of A, A exports the member function makeB which yields a value of type A::B. Though one cannot name the return value of makeB outside of A, the value can still be used as is in the case in the following:
class A {
private:
class B {
int x;
public:
B add(B _x) { x += _x; }
};
public:
B makeB();
};
int f() {
A a0, a1;
a0.makeB().add(a1.makeB());
}
The above illustrates an important point. C++ nested classes do not declare distinct types for each instance. Although one cannot annotate them as static, they are exactly that. In the example, a0.B and a1.B are of the same type. This is why a0.makeB().add(a1.makeB()) type checks. This means that writing a nested class is equivalent to lifting that class definition out to the top-level and selectively hiding the name of the nested class. Between different languages, there is a design chasm. In C++, there is only the unitary nested class and its associated semantics. Java distinguishes between static nested classes (similar to the C++ nested class) and inner classes. Java actually has a number of variants of nested classes (https://blogs.oracle.com/darcy/entry/nested_inner_member_and_top). The above C++ example translated into Java fails type checking because of A.B is private.
class A {
private class B {
public B add(B rhs) { val += rhs.val; return this; }
private int val;
}
public B makeB() { return new B(); };
}
public class Nested0 {
public static void main() {
A a0 = new A();
A a1 = new A();
a0.makeB().add(a1.makeB());
}
}
The call to add is flagged as a problem because a0.makeB()'s type (i.e., A.B) is inaccessible. If A.B were public or protected, however, the type checker is satisfied despite a0.B and a1.B supposedly denoting two distinct inner classes. Thus, at least at this point, inner classes do not provide abstract types in the sense of generative types.
On the other hand, as this discussion on Java decompilation (javap) shows, the semantics of inner classes are such that have a kind of C++
friendrelationship with their outer enclosing class. The discussion on TheServerSide shows how this is implemented: the compiler generates a static method that "breaks the encapsulation wall" to permit accessing private members of the outer class.
References
- Herb Sutter wrote an article on nested classes in C++.