Jump to page: 1 2
Thread overview
dynamic array of objects
Dec 10, 2003
Mark Brudnak
Dec 10, 2003
Charles Sanders
Dec 10, 2003
Mark Brudnak
Dec 10, 2003
Vathix
How about implicit garbage creation????
Dec 11, 2003
Mark Brudnak
Dec 11, 2003
Brad Beveridge
Dec 11, 2003
Sean L. Palmer
Dec 12, 2003
Mark Brudnak
Dec 12, 2003
Ian Johnston
Dec 12, 2003
Sean L. Palmer
Dec 11, 2003
Robert
Dec 11, 2003
Antti Sykäri
Dec 11, 2003
Felix
Dec 12, 2003
J Anderson
Dec 10, 2003
Patrick Down
December 10, 2003
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 ;
}


December 10, 2003
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 ;
> }
>
>


December 10, 2003
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 ;
> > }
> >
> >
>
>


December 10, 2003
"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 ;
> }
> 
> 
December 10, 2003
"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.




December 11, 2003
"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 11, 2003
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.
> 
> 
> 
> 

December 11, 2003
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

December 11, 2003
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 11, 2003
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.


« First   ‹ Prev
1 2