Newbie initial comments on D language - scope

Walter Bright newshound1 at digitalmars.com
Sat Feb 2 20:07:58 PST 2008


Edward Diener wrote:
> Your analogy to C++'s 'const' is a bad one.
> 
> The C++ 'const' refers to a quality of the object while the D 'scope' 
> refers to a quality of the type. There is no equivalent of 'const' in 
> C++ which refers to the type.

'const' in C++ is very much a characteristic of the type of the object. 
It pervades the semantics of the type. It's easy to envision a scheme of 
const where the const-ness is controlled by a bit in the runtime 
instantiation of the object, and any mutating operations would first 
check that bit.

C++ avoids the overhead of that by having a static typing system, and 
such 'bits' become part of the compile-time information (i.e. the type) 
rather than the run-time information.

> Once we say that a type is 'scope' in D we 
> should no longer have to say that an object of that type is 'scope'. An 
> object of that type should be 'scope' automatically and the user of that 
> object should not care or even need to know. In C++ the user of an 
> object specifically says it is 'const' to set the quality of the object 
> to something ( one can not change the object ). Your analogy is mixing 
> apples and oranges. These are different things.

I don't believe they are different at all. Consider also languages that 
have no static types - the types are determined at runtime (Javascript 
is an example). What a language chooses to specify about an object at 
compile-time vs run-time is a spectrum with various tradeoffs, not an 
apples-oranges with a sharp dividing line.

Certainly, there is plenty of debate about static typing vs dynamic 
typing. D is a statically typed language primarily for performance 
reasons - a dynamically typed language can run 100x slower.


> What I am saying is that an object whose type is 'scope' is treated 
> magically by the compiler in that the compiler is now doing reference 
> counting on it and calling its destructor when the last reference goes 
> out of scope. Furthermore as that object gets reference assigned the 
> reference count is manipulated and whatever object is specified in that 
> reference assignment, as long as it is allowable by the compiler by the 
> rules of D, takes part in the 'scope' magic. In a polymorphic language 
> this means that you should associate 'scope' with the dynamic type of 
> the object, not its static type, and how you decide to do that is up to 
> you. Think of it as wrapping a boost::shared_ptr around the object and 
> for every object to which you legally assign/copy it a boost::shared_ptr 
> gets wrapped around that object.

Pulling on that string leads us to every object having scope semantics, 
because that machinery will have to exist and be checked at runtime for 
every object.

> I agree this adds some overhead, but so what.

And there lies the crux of our disagreement. My experience with memory 
allocation is that ref counting is appropriate for scarce resources, and 
gc is appropriate for abundant resources (i.e. memory). We both agree 
that gc is a poor choice for scarce resources, and I'm going to argue 
that rc is a poor choice for abundant resources.


> Using boost::shared_ptr 
> also imposes overhead and whole generation of programmers have somehow 
> survived the extra x bytes per object in an age where physical memmory 
> is in the gigabytes and virtual memory in 64 bit systems in the 
> quadrabytes.

There is a large push to add gc to C++. (rc has disadvantages besides 
using more memory - the overhead to allocate two objects instead of one, 
and the overhead of doing the inc/dec/test. A further disadvantage is 
you cannot do array slicing with rc without adding substantial more 
overhead - memory and runtime.)


> My added suggestion is that when applying the 'scope' keyword to the 
> object, and not the type, this essentially means that the compiler now 
> treats that object as 'scope' even though the type is not 'scope'. I 
> will call this object 'scope' injection. My suggestion for this is based 
> solely on the practical consequences:
> 
> 1) Allow the instantiator of a type to have 'scope' control over the 
> object even when the designer of the type does not specify it as a 
> 'scope' type. The user may know something about using the type at 
> run-time that the class designer can not know, makes optional, or even 
> disregards.

I agree with you that the scopeness of an object is best determined by 
the user, not the class designer. But this doesn't preclude making scope 
part of the type any more than the user adding 'const' precludes it.


> 2) Following from the above, the most obvious practical cases occur when 
> the type is created from a template class/struct, when the type is some 
> built-in language container which can hold polymorphic objects of some 
> base class type, and when the type embeds an object of 'scope' class 
> type which may only be used in a corner case so that the designer of the 
> type leaves scoping up to the user.
> 
> In other words the flexibility of control would be wonderful and, I 
> believe, often necessary. Having both the class designer be able to 
> 'scope' the type and the end user be able to 'scope' an object of any 
> type ( which has a destructor ) is the ultimate ideal. If you wanted to 
> go even further you could allow the end-user to 'unscope' an object of a 
> 'scope' type when instantiating the object, even though the benefits of 
> doing this seem to be practically negligible.
> 
> I view your choices as, from most desirable to least desirable:
> 
> 1) Keep tracks of the objects themselves at run-time to see if they are 
> 'scope' or not. This allows object 'scope' injection and refernce 
> assignment to objects whose static type is not 'scope' to make them 
> 'scope'.
> 
> 2) Keep track of the dynamic type of the objects themselves in order to 
> see whether the dynamic type of the object is 'scope'. This does not 
> allow object 'scope' injection, but does allow reference assignment to 
> objects whose static type is not 'scope' since you are only considering 
> the dynamic type of the object and not the static type to determine if 
> the object should be 'scope'.
> 
> 3) Keep track of only the static type of the object. This does not allow 
> object 'scope' injection nor even reference assignment to objects whose 
> static type is not 'scope'.

I believe that adding scope to the type allows for scope 'injection' as 
you defined it. But you're right in that (3) does not allow an object to 
be dynamically retyped as scope, though it could be 'wrapped' at runtime 
with a proxy struct that is itself statically scoped.

> I view choice 3 as pretty poor and would really like to see choice 1 
> rather than choice 2 for practical reasons.
> 
> I hope this at least gives you food for further thought.



More information about the Digitalmars-d mailing list