December 11, 2003
I've seen *many* C++ programmers who suffer from the explicit construction. All of them (and me!) have written as:

1)
A a;
a.foo();  // Access Violation!

2)
A[] a = new A[size];
a[0].foo();  // Access Violation!

IMHO, it is a troublesome problem that such a code causes no errors on compiling.


And, I would like implicit array construction, too.
Indeed, a[i] of "A[] a = new A[size];" is a reference, I know,
but I want not to initialize array elements by foreach:

A[] a = new A[size];
foreach(inout elem; a) { elem = new A; }  // bother!

This problem is solved by template as:

template anew(T) {
T[] size(int size) {
T[] array = new T[size];
foreach(inout elem; array) {
elem = new T;
}
return array;
}
}
A[] a = instance anew(A).size(size);

However, I would like it to be supported by D.
e.g....

// null initialization
N[] n = new N[size];

// initialized by default constructor
A[] a = new A[size].create();

// initialized by this(int) constructor
B[] b = new B[size].create(10);

// initialized index by index
C[] c = new C[size].neweach(function C(int i) { return new C(i); });

This example adds no keywords and syntax.
Only create and neweach methods are added to array object.


In article <br9069$6oi$1@digitaldaemon.com>, Brad Beveridge says...
>
>I think that this would get too confusing.  The semantics at the moment
>are: all objects are references.  The only way to create an object is
>with new.  I like explicitly creating an object.  Implicit object
>creation (example, passing objects via the stack in C++) is a hassle,
>and you need to be careful not to end up passing huge structures when a
>reference would do.
>I think with your suggestion objects would end up being created at
>unexpected times.
>
>Brad
>
>Mark Brudnak wrote:
>> "Vathix" <vathix@dprogramming.com> wrote
>> 
>> 
>>>Classes are different from other types because they use references. If you set the length of an array of classes, you're allocating more references, not class objects themselves. You should loop through the array and assign new objects.
>>>
>>>
>> 
>> 
>> Ok.  So for built in types...
>> 
>> int thisArray[] ;
>> thisArray.length = theLength ;   // now I have an array of ints
>> thisArray[anIndex] = aNumber ;
>> 
>> But for classes...
>> 
>> SomeClass thatArray[] ;
>> thatArray.length = theOtherLength ;    // now I have an array of
>> uninitialized class references
>> thatArray[anIndex] = new SomeClass ;  // create something for it to
>> reference.
>> thatArray[anIndex].aField = aNumber ;
>> 
>> Now my question...
>> 
>> Why can't both have the same semantics?  That is why can't classes behave like the built in types?  I am sure that this issue has been discussed before and I know that the immediate answer has to do with passing objects by reference, garbage collection, reference counting etc.
>> 
>> The issue is why do we maintain the reference/object distinction?  Since a reference which is never assigned anything is meaningless and an unassigned new is equally meaningless.  To my knowledge, there are only two scenarios in which a class reference is used.
>> 
>> 1) It holds a reference to an explicitly created object ;
>> 
>> AlphaClass alpha = new AlphaClass(p1, p2) ; // create a new object to be
>> held by alpha
>> alpha.fieldN = x ;
>> 
>> 2) It is assigned a reference to some pre-existing object by assignment ;
>> 
>> BetaClass beta ;
>> /* some code.... */
>> beta = lookupBeta("lastWeeksBeta") ; // reference is assigned by a lookup
>> 
>> Now in case 1) the 'new' should be implicit.  That is, I should be able to write...
>> 
>> AlphaClass alpha(p1, p2) ;
>> alpha.fieldN = x ;    // execute  alpha = new AlphaClass(p1, p2)  implicitly
>> 
>> And the compiler knows to create a new AlphaClass object and assign it to alpha.
>> 
>> In this way both garbage collection and garbage creation would be implicit. Right now garbage creation is explicit (via new) and garbage collection is implicit.
>> 
>> P.S. garbage creation is probably not the right term.  When an object is new it is not garbage.
>> 
>

Robert (Japanese)
December 12, 2003
"Sean L. Palmer" <palmer.sean@verizon.net> wrote

<snip>

> By saying
>
> A a;
>
> you are telling the compiler to make a new object of class a by calling
its
> "default" constructor (I guess also by calling new!) and simultaneously creating the reference A to hold a reference to said object.
>

Yes.  To add to that, why should the programmer care where memory is allocated?  When I type:

class A{ /*stuff */} ;
A a ;

I expect to be able to use 'a' whether 'A' is a builtin type, struct, or object.  IMO 'new' is nothing more than malloc++ and it should not be necessary.

The above example is not too apealing, because it is just as easy to type:

A a = new A ;

...or better yet...

A a = A.new() ;

However things get ugly when object references are created by a container class, like dynamic arrays, for example

A b[] ;
b.length = c ;
foreach(A thisb ; b){ thisb = new A} ;

int oldlength = b.length ;
b.length = d ;
// now which values of 'b' are initialized? Which are null references?  if d
> c i need to do something...
if (d > c) {
    foreach(a thisb ; b[oldlength..b.length]) {thisb = new A } ;
}

This type of forced allocation is a fertile place for bugs to develop.  It also breaks the metaphor of the dynamic arrays. That is they grow by assigning .length, and in most cases newly allocated elements are ready to use, if it is an array of class references they are not.

<snip>

> I almost agree with the newbie, that the end result of the declaration should be a live object.  But apparently people find this null reference idea useful, so to allow those null references to be created, you should allow a syntax to do so... currently that's "A a;"  So let's leave that
one
> alone and add this one:
>

I think that in every case I have seen, a NULL is always used as to pass boolian type information such as a flag, error indicator, special mode for a function, etc.  all of which can be handled by better means than testing against NULL.  A truely modern language should not return NULL to indicate an error, etc....  The only legitimate use that I can think of for NULL is for the termination of a linked list.

> A a();  // initialize a with new a allocated with default new and initialized using the default constructor
>
> This is precisely equivalent to:
>
> A a = new A; // the final empty () to call the default ctor elided

A a = new A ;
A a =A.new() ;
A a() ;
A a ;

These four statements are all equivalent and call the parameterless constructor.  Syntactically (FWIW) I prefer the fourth, then the second. The only problem with this is that the construction is wasted if the object reference 'a' is assigned to some other preexisting object.

A a ;  // implicitly executes as:  A a = new A ;

a = lookUpObject("someString") ;  // overwrite the previously allocated
object.

>
> You can add other parameters to call a different constructor:
>
> A a(parm1,p2); // same as A a = new A(parm1,p2);

Yes...exactly...


<snip>

>
> Maybe property syntax could be unified with the "new" operator (or
object!)
>
> extern Heap new;
> extern MyObj foo,bar;
>
> A a = new.A(foo);

A better construction is:

A a = A.new(foo) ;

Because this is what is happening behind the scenes.  You are asking the class to instantiate an instance of itself.

>
> You could also allocate derived classes.  Something that wouldn't be
> possible with "A a(x);" syntax.
>
> You could even pass commands to the new object (thru it's new variable, in case it matters) by continuing the property chain:
>
> A a = new.A(foo).DoTask1().DoTask2(bar).DoTask3();

As long as DoTask1, DoTask2, DoTask3 all return a reference to the object. This is the convention of Smalltalk.

>
> But not sure what you could do with the results of such functions.  Maybe that's going too far.

The functions would have to return a reference to the class.  see above.

>
> Whaddya think?  Maybe C/C++ got allocation responsibility wrong and it should reside with the container.  Thus the complexity of C++ operator new and delete overloading.  Those are overloaded on the type of the object itself.  Unfortunately those control creation everywhere, not just in one region of the program, have to deal with the possibility of being
overridden
> in derived classes, have to deal with allocating derived classes, so size must be a parameter, then how to allocate arrays, and so on, and so forth. It wouldn't be so bad, deriving from a class and overriding some things,
if
> it weren't such a hassle to do generically (you have to insert shims to patch thru constructor calls and certain other operations, which you may
not
> know the exact variations of if you are a template.)  The new STL
allocators
> are nicer, but are pretty complicated.  I don't know anybody who really
uses
> them.  Allocation shouldn't be all that complicated.
>

If you think about it, an object reference is already a container of sorts. It is a chunk of memory of fixed size which points to among other things the instance variables of the object, which live on the heap.

One more thought, when I learned to program I did not know the difference between a stack and a heap, and I didn't need to.  Thankfully the language hid those details from the programmer.  Then I learned C and was exposed to the heap via the malloc() function.  As history proved, programmers managing their own memory is a tremendous source of bugs.  With the post C++ languages (D, Java, C#) the responsibility of memory management is being pushed back to the compiler and the runtime environment (at least part way). With the introduction of garbage collection object destruction has been pushed back beneath the surface of the language definition.  Unfortunately, memory allocation is still a part of these languages so we still have to maintain the reference/object distinction.


December 12, 2003
For template object creation, it would be nice if there was one uniform syntax (you could still keep the old ones) for object creation on the stack and heap.

I suggest a new property on all types.

template TCopy(T)
{
  void new(out T newObj)
  {
     T newObj = T.new; //Creates a new int, struct, class (whatever)
  }
}


Felix wrote:

>I agree that heap/stack distinction is useful for some optimizations. As for me,
>I do not bother about.
>I think it is the compiler's job where to allocate and when to instantiate an
>object. As for semantics/syntax, I would definetely preffer an uniform one...
>
>
>In article <br8sve$12k$1@digitaldaemon.com>, Mark Brudnak says...
>  
>
>>"Vathix" <vathix@dprogramming.com> wrote
>>
>>    
>>
>>>Classes are different from other types because they use references. If you
>>>set the length of an array of classes, you're allocating more references,
>>>not class objects themselves. You should loop through the array and assign
>>>new objects.
>>>
>>>
>>>      
>>>
>>Ok.  So for built in types...
>>
>>int thisArray[] ;
>>thisArray.length = theLength ;   // now I have an array of ints
>>thisArray[anIndex] = aNumber ;
>>
>>But for classes...
>>
>>SomeClass thatArray[] ;
>>thatArray.length = theOtherLength ;    // now I have an array of
>>uninitialized class references
>>thatArray[anIndex] = new SomeClass ;  // create something for it to
>>reference.
>>thatArray[anIndex].aField = aNumber ;
>>
>>Now my question...
>>
>>Why can't both have the same semantics?  That is why can't classes behave
>>like the built in types?  I am sure that this issue has been discussed
>>before and I know that the immediate answer has to do with passing objects
>>by reference, garbage collection, reference counting etc.
>>
>>The issue is why do we maintain the reference/object distinction?  Since a
>>reference which is never assigned anything is meaningless and an unassigned
>>new is equally meaningless.  To my knowledge, there are only two scenarios
>>in which a class reference is used.
>>
>>1) It holds a reference to an explicitly created object ;
>>
>>AlphaClass alpha = new AlphaClass(p1, p2) ; // create a new object to be
>>held by alpha
>>alpha.fieldN = x ;
>>
>>2) It is assigned a reference to some pre-existing object by assignment ;
>>
>>BetaClass beta ;
>>/* some code.... */
>>beta = lookupBeta("lastWeeksBeta") ; // reference is assigned by a lookup
>>
>>Now in case 1) the 'new' should be implicit.  That is, I should be able to
>>write...
>>
>>AlphaClass alpha(p1, p2) ;
>>alpha.fieldN = x ;    // execute  alpha = new AlphaClass(p1, p2)  implicitly
>>
>>And the compiler knows to create a new AlphaClass object and assign it to
>>alpha.
>>
>>In this way both garbage collection and garbage creation would be implicit.
>>Right now garbage creation is explicit (via new) and garbage collection is
>>implicit.
>>
>>P.S. garbage creation is probably not the right term.  When an object is new
>>it is not garbage.
>>
>>
>>
>>
>>    
>>
>
>
>  
>

December 12, 2003
In article <br97fu$i0u$1@digitaldaemon.com>, Sean L. Palmer says...

[...]

>By saying
>
>A a;
>
>you are telling the compiler to make a new object of class a by calling its "default" constructor (I guess also by calling new!) and simultaneously creating the reference A to hold a reference to said object.

Hmmm, it's not clear to me that this is so. What if I want a reference to a base class (maybe abstract), and allow some factory to instantiate the object? I may not know what class of object I will end up with, especially if one day objects could be loaded from DLLs...

And how would you declare members in a class declaration, would they always need an initialiser too? Wouldnt that be more confusing if there were different meanings for locals and class data members?

class X
{
A a1;  // declare reference, no instantiation
};

void X::f()
{
A a2;  // declare reference and instantiate
}


December 12, 2003
Did you even read the rest of the post?

Sean

"Ian Johnston" <Ian_member@pathlink.com> wrote in message news:brcqjm$2s48$1@digitaldaemon.com...
> In article <br97fu$i0u$1@digitaldaemon.com>, Sean L. Palmer says...
>
> [...]
>
> >By saying
> >
> >A a;
> >
> >you are telling the compiler to make a new object of class a by calling
its
> >"default" constructor (I guess also by calling new!) and simultaneously creating the reference A to hold a reference to said object.
>
> Hmmm, it's not clear to me that this is so. What if I want a reference to
a
> base class (maybe abstract), and allow some factory to instantiate the
object?
> I may not know what class of object I will end up with, especially if one
day
> objects could be loaded from DLLs...
>
> And how would you declare members in a class declaration, would they
always
> need an initialiser too? Wouldnt that be more confusing if there were
different
> meanings for locals and class data members?
>
> class X
> {
> A a1;  // declare reference, no instantiation
> };
>
> void X::f()
> {
> A a2;  // declare reference and instantiate
> }


1 2
Next ›   Last »