www.digitalmars.com         C & C++   DMDScript  

D - dynamic array of objects

reply "Mark Brudnak" <malibrud provide.net> writes:
Help!

This code builds but does not run.  It crashes on the indicated line.  What
am I doing wrong?


import std.stream ;
import std.conv ;
import std.string ;

class Foo {
 float x ;
 float y ;
} ;

class Bar {
 float step ;
 Foo[] manyFoos ;
} ;

int main(char[][] args)
{

 Bar myBar = new Bar ;
 myBar.manyFoos.length = 3 ;
 printf("I am here\n") ;
 myBar.manyFoos[0].x = 0.0f ; // Crash: "Error: Access Violation"
 printf("Now I am here\n") ;

 return 0 ;
}
Dec 09 2003
next sibling parent reply "Charles Sanders" <sanders-consulting comcast.net> writes:
You have not allocated space for

myBar.manyFoos[0]




import std.stream ;
import std.conv ;
import std.string ;

class Foo {
 float x ;
 float y ;
} ;

class Bar {
 float step ;
 Foo[] manyFoos ;
} ;

int main(char[][] args)
{

 Bar myBar = new Bar ;
 myBar.manyFoos.length = 3 ;
 printf("I am here\n") ;
 myBar.manyFoos[0] = new Foo;
 myBar.manyFoos[0].x = 0.0f ; // no crash
 printf("Now I am here\n") ;

 return 0 ;
}

works as expected


"Mark Brudnak" <malibrud provide.net> wrote in message
news:br64bc$1r6t$1 digitaldaemon.com...
 Help!

 This code builds but does not run.  It crashes on the indicated line.
What
 am I doing wrong?


 import std.stream ;
 import std.conv ;
 import std.string ;

 class Foo {
  float x ;
  float y ;
 } ;

 class Bar {
  float step ;
  Foo[] manyFoos ;
 } ;

 int main(char[][] args)
 {

  Bar myBar = new Bar ;
  myBar.manyFoos.length = 3 ;
  printf("I am here\n") ;
  myBar.manyFoos[0].x = 0.0f ; // Crash: "Error: Access Violation"
  printf("Now I am here\n") ;

  return 0 ;
 }
Dec 09 2003
parent reply "Mark Brudnak" <malibrud provide.net> writes:
How is what I am doing different than:

 int[] array;
	array.length = 100;

Which is taken from the D spec under Arrays->"Setting Dynamic Array Length"?


"Charles Sanders" <sanders-consulting comcast.net> wrote in message
news:br64j3$1reu$1 digitaldaemon.com...
 You have not allocated space for

 myBar.manyFoos[0]




 import std.stream ;
 import std.conv ;
 import std.string ;

 class Foo {
  float x ;
  float y ;
 } ;

 class Bar {
  float step ;
  Foo[] manyFoos ;
 } ;

 int main(char[][] args)
 {

  Bar myBar = new Bar ;
  myBar.manyFoos.length = 3 ;
  printf("I am here\n") ;
  myBar.manyFoos[0] = new Foo;
  myBar.manyFoos[0].x = 0.0f ; // no crash
  printf("Now I am here\n") ;

  return 0 ;
 }

 works as expected


 "Mark Brudnak" <malibrud provide.net> wrote in message
 news:br64bc$1r6t$1 digitaldaemon.com...
 Help!

 This code builds but does not run.  It crashes on the indicated line.
What
 am I doing wrong?


 import std.stream ;
 import std.conv ;
 import std.string ;

 class Foo {
  float x ;
  float y ;
 } ;

 class Bar {
  float step ;
  Foo[] manyFoos ;
 } ;

 int main(char[][] args)
 {

  Bar myBar = new Bar ;
  myBar.manyFoos.length = 3 ;
  printf("I am here\n") ;
  myBar.manyFoos[0].x = 0.0f ; // Crash: "Error: Access Violation"
  printf("Now I am here\n") ;

  return 0 ;
 }
Dec 09 2003
parent reply "Vathix" <vathix dprogramming.com> writes:
"Mark Brudnak" <malibrud provide.net> wrote in message
news:br6581$1sbi$1 digitaldaemon.com...
 How is what I am doing different than:

  int[] array;
 array.length = 100;

 Which is taken from the D spec under Arrays->"Setting Dynamic Array
Length"?

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.
Dec 09 2003
parent reply "Mark Brudnak" <malibrud provide.net> writes:
"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.
Dec 10 2003
next sibling parent reply Brad Beveridge <brad clear.net.nz> writes:
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.
lid Date
next sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Not really.  Since they're always by reference anyway, how could it make any
new objects... there's no "copy constructor" to accidentally get called.  D
also doesn't have implicit user-defined conversions.

He wasn't saying he wanted stack storage, only that allocation from the heap
should be automatic and implicit.

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.

If you ask me I think it should be the object's responsibility where it gets
allocated and deallocated from.  More than the user of the objects.
Actually the best place for responsibility for creation of objects should be
in the various Container classes.  You then cannot have an object unless you
get it from some container, and all containers have their allocators
parameterized so that they can be replaced if necessary.  Put some "Heap"
memory allocator class in the standard library.  Give it an area of memory
and it can manage it.  Then you can create new heap regions and install Heap
managers for them, and install Containers in your heaps, from which you
allocate other Objects (maybe more Containers).

But how could you always query containers for the storage, while also
passing the list of parameters to the ctor of the newly allocated object, in
the same call?  You don't want to have the object uninitialized.  Heck we
probably don't want references to be uninitialized, and don't allow them to
be null either.  So have to group allocation with initialization, as a unit.
It's convenient anyway.

Unfortunately it's not that simple.  We also want to be able to override
where an object comes from, otherwise may as well just let each object
decide where it comes from, and have to basically derive from a class and
override the allocation to change it, or do typecasting yourself, like C++.

It seems natural to group allocation and initialization.  And as mentioned
earlier what would you do with a newly allocated reference unless you're
going to store it directly into a variable?  Increment it?  No.  Give it
commands?  That's a lot to pack together syntactically.  You either put it
in an existing variable via assignment, or you initialize a newly created
reference to hold the new object, with the pattern:

class A
{
}

A a = new A;

or sometimes

A a;
a = new A;

and the thing that actually does get a lot of newbie questions here on this
NG and is in the FAQ,

A a; // newbie expects he actually has a live A object instance stored in a,
but really by current rules it's null.

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:

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

You can add other parameters to call a different constructor:

A a(parm1,p2); // same as A a = new A(parm1,p2);

Only I really do want objects to come from containers (such as Heap, which
would be nice if it could create any kind of object)

So I'd want to somehow get the object from the container, whilst
simultaneously supplying its constructor with parameters.

A a = myheap.A();

This reminds me a bit of C++'s user-defined conversion function, which in
fact could potentially, now that I think about it, as a way to "create"
objects of a given type 'from' some other object.

I used to come across the idea frequently that creation should be thought of
as a conversion from void to some other object type.  But maybe a cast from
the container type to the containee type would be an allocation.  Obviously
you would want to be able to override this.  And also it makes sense that
you would want to be able to convert to (allocate) more than one type (think
Heap) and this is precisely what C++'s user defined conversion operators do.
They give the object the opportunity to allocate, initialize, and return a
new object.  But C++'s stop at copy constructor semantics (no parameters,
new object is either another representation of the called object, or needs
no parameters in order to be constructed).  If you want to pass parameters
to the new object you have to make a function, which has different syntax.

Maybe property syntax could be unified with the "new" operator (or object!)

extern Heap new;
extern MyObj foo,bar;

A a = new.A(foo);

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();

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

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.

Sean

"Brad Beveridge" <brad clear.net.nz> wrote in message
news:br9069$6oi$1 digitaldaemon.com...
 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.
Dec 10 2003
next sibling parent "Mark Brudnak" <malibrud provide.net> writes:
"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++ 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.
Dec 11 2003
prev sibling parent reply Ian Johnston <Ian_member pathlink.com> writes:
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 }
Dec 12 2003
parent "Sean L. Palmer" <palmer.sean verizon.net> writes:
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
 }
Dec 12 2003
prev sibling parent Robert <Robert_member pathlink.com> writes:
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)
Dec 11 2003
prev sibling next sibling parent Antti =?iso-8859-1?Q?Syk=E4ri?= <jsykari gamma.hut.fi> writes:
In article <br8sve$12k$1 digitaldaemon.com>, Mark Brudnak wrote:
 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.
Value objects (structs, enums, built-in objects, function pointers, delegates and the sort) are allocated on the stack, and class objects are allocated on the heap. Stack allocation is more efficient since there's no cost of reclaiming the memory, and heap allocation has different semantics anyway. Therefore, we distinguish the two by having to use "new X" to claim memory from the heap, and leaving it out when doing it on the stack. (Don't ask me about arrays - they are somewhere in between, sometimes you must use new and sometimes not, but I haven't quite gotten the hang of it.)
 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.
So null should be removed from the language? But might be handy sometimes, for example when you don't have a default constructor in the class.
 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.
Still, nice thoughts. In C++ you can make a smart pointer class that automatically instantiates an object when it's created. Which might be nice sometimes, but my personal preference is to keep heap allocation explicit. Are you searching similarity between stack/heap allocated objects so that newbies would not be overwhelmed when they notice that class references are initialized to null (because they wouldn't)? They have to learn the difference between reference and value objects at some point anyway, so why not make it explicit right from the start? -Antti
Dec 10 2003
prev sibling parent reply Felix <Felix_member pathlink.com> writes:
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.
Dec 10 2003
parent J Anderson <REMOVEanderson badmama.com.au> writes:
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.
Dec 11 2003
prev sibling parent Patrick Down <pat codemoon.com> writes:
"Mark Brudnak" <malibrud provide.net> wrote in
news:br64bc$1r6t$1 digitaldaemon.com: 

 Help!
 
 This code builds but does not run.  It crashes on the indicated line. 
 What am I doing wrong?
 
 
 import std.stream ;
 import std.conv ;
 import std.string ;
 
 class Foo {
  float x ;
  float y ;
 } ;
 
 class Bar {
  float step ;
  Foo[] manyFoos ;
 } ;
 
 int main(char[][] args)
 {
 
  Bar myBar = new Bar ;
  myBar.manyFoos.length = 3 ;
  printf("I am here\n") ;
myBar.manyFoos[0] = new Foo;
  myBar.manyFoos[0].x = 0.0f ; // Crash: "Error: Access Violation"
  printf("Now I am here\n") ;
 
  return 0 ;
 }
 
 
Alternately: struct Foo { float x ; float y ; };
 class Bar {
  float step ;
  Foo[] manyFoos ;
 } ;
 
 int main(char[][] args)
 {
 
  Bar myBar = new Bar ;
  myBar.manyFoos.length = 3 ;
  printf("I am here\n") ;
  myBar.manyFoos[0].x = 0.0f ; // Crash: "Error: Access Violation"
  printf("Now I am here\n") ;
 
  return 0 ;
 }
 
 
Dec 09 2003