January 10, 2009
2009/1/11 Christopher Wright <dhasenan@gmail.com>:
> Weed wrote:
>>
>> Denis Koroskin пишет:
>>
>>> I'd suggest you to state you ideas as simple and keep your posts as small as possible (trust me, few people like reading long posts).
>>
>> The extra-short formulation of my idea:
>> Objects should be divided on POD (struct) and non-POD (class).
>>
>> Instead of such division as now: POD && value type (struct) and POD &&
>> reference type (class).
>
> The reference versus value type difference is just a matter of defaults.
>
> Returning a class instance on the stack from a function is possible with inout parameters, though you can't use a constructor in that case:
>
> void main ()
> {
>        scope MyClass obj = new MyClass;
>        foo (obj);
> }
>
> void foo (inout MyClass obj)
> {
>        // initialize obj somehow
> }

I don't think that does what you think it does.
Remember that obj is basically a pointer under the hood.  So what that
'inout' does is allow you to make obj point to something else.  You
don't need the 'inout' if all you want to do is change the contents of
what obj points to.

I think what 'scope MyClass obj' actually does is reserve the appropriate amount of space on the stack somewhere, then make obj point to that space instead of the heap.  So that means you can still reassign obj if you feel like it.  And it can be reassigned to either a scope or non-scope instance.  It doesn't matter to obj because obj is just a pointer.

--bb
January 10, 2009
2009/1/11 Christopher Wright <dhasenan@gmail.com>:
>> Instead of such division as now: POD && value type (struct) and POD &&
>> reference type (class).
>
> The reference versus value type difference is just a matter of defaults.

No it's not.  scope MyClass does not make a MyClass that works like a value type.  It merely makes a MyClass instance that's allocated on the stack.  The semantics of it otherwise is identical to a regular class.

Another difference is that class instances can only be 'scope' in functions.
A use case that's missing is:
class MyClass {
     scope OtherClass foo;
}
This would embed the memory for 'foo' right inside MyClass, so that

   scope x = new MyClass;

Would not involve any heap allocations.  Currently if you have a class inside a class, there's no way to use 'scope' to avoid the heap allocation on the contained class.

Also you could imagine scope arrays.
MyClass foo = new scope MyClass[10];

Where this would do one heap allocation, not 10.
There is a problem with this though, mentioned below, precisely
because scope MyClass does *not* have value semantics.

> Returning a class instance on the stack from a function is possible with
> inout parameters, though you can't use a constructor in that case:
> void main ()
> {
>        scope MyClass obj = new MyClass;
>        foo (obj);
> }
>
> void foo (inout MyClass obj)
> {
>        // initialize obj somehow
> }

To further follow up on this, what you are showing is *not* returning a class instance on the stack via inout.  You are just modifying a pre-existing instance.   Returning a scope instance via inout would look like this:

void main() {
    MyClass obj;
    foo(obj);
}
void foo(inout MyClass obj) {
    scope tmp = new MyClass;
    obj = tmp;
}

And that will crash because it refers to memory allocated on the stack. What is impossible with D right now is to make a value copy of a class (short of getting hackish with memcpy).

But since classes can be polymorphic, value copying gets you into
slicing problems.  That's why value copying is disabled to begin with.
 So disabling value copies is a good thing.

And that's also the problem with putting scope'd things inside another class or an array.  Since they don't have value semantics, there's no way to overwrite the memory that's there with a new version of the object.  If you try to overwrite it you will instead just change the pointer.  (This is what happens with scope objects in functions now).


Assuming this worked:

class MyClass {
     scope OtherClass foo;
}
scope x = new MyClass;
x.foo = new OtherClass;

You haven't reused the memory that foo originally occupied.  You've instead made foo point to the heap.  And now you have a chunk of your class that stored the original foo that's dead, useless and uncollectable.

So the conclusion is that scope without value semantics is of somewhat limited use.   Or at least in the case of embedded scope objects, they should best be considered kind of like 'final', only for cases where you're never going to rebind the reference to something else.

--bb
January 10, 2009
Bill Baxter пишет:

> But since classes can be polymorphic, value copying gets you into
> slicing problems.  That's why value copying is disabled to begin with.
>  So disabling value copies is a good thing.

It is not always a good thing.

I propose to prohibit only the copying by value of the base type to derivative type

> 
> And that's also the problem with putting scope'd things inside another class or an array.  Since they don't have value semantics,

Yes, this is what I mean
January 11, 2009
2009/1/11 Weed <resume755@mail.ru>:
> Bill Baxter пишет:
>
>> But since classes can be polymorphic, value copying gets you into
>> slicing problems.  That's why value copying is disabled to begin with.
>>  So disabling value copies is a good thing.
>
> It is not always a good thing.

Yeh, I just mean there is some merit in disabling value copies.  But I don't rule out the possibility that there may be an even better way that banning them altogether.

> I propose to prohibit only the copying by value of the base type to derivative type

Ok, this is key.  How do you propose to do this?  In general it
requires a runtime check, I think.
And I think you need to say that you prohibit copying unless
typeA==typeB exactly.  If you allow copying either way between base
and derived you are asking for trouble.

But still given
  Base x = get_one();
  Base y = get_another();
  *x = *y; // presumed value copy syntax

you have no way in general to know that x and y are really both a Base at compile time.  So you must have a run-time check there.  Perhaps it could be omitted for -release builds, though.

>> And that's also the problem with putting scope'd things inside another class or an array.  Since they don't have value semantics,
>
> Yes, this is what I mean

So assuming you had this, the important question is what would you do with it?
You still have the problem that the current system works pretty well.
And has a lot of history.  So you need a very compelling use case to
convince Walter that something should change.

--bb
January 11, 2009
Bill Baxter пишет:
> 2009/1/11 Weed <resume755@mail.ru>:
>> Bill Baxter пишет:
>>
>>> But since classes can be polymorphic, value copying gets you into
>>> slicing problems.  That's why value copying is disabled to begin with.
>>>  So disabling value copies is a good thing.
>> It is not always a good thing.
> 
> Yeh, I just mean there is some merit in disabling value copies.  But I don't rule out the possibility that there may be an even better way that banning them altogether.
> 
>> I propose to prohibit only the copying by value of the base type to derivative type
> 
> Ok, this is key.  How do you propose to do this?  In general it
> requires a runtime check, I think.
> And I think you need to say that you prohibit copying unless
> typeA==typeB exactly.  If you allow copying either way between base
> and derived you are asking for trouble.
> 
> But still given
>   Base x = get_one();
>   Base y = get_another();
>   *x = *y; // presumed value copy syntax
> 
> you have no way in general to know that x and y are really both a Base at compile time.  So you must have a run-time check there.  Perhaps it could be omitted for -release builds, though.

It can lead to a difficult and non-reproduceable errors than old C++-style splitting.

It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.

>>> And that's also the problem with putting scope'd things inside another class or an array.  Since they don't have value semantics,
>> Yes, this is what I mean
> 
> So assuming you had this, the important question is what would you do with it?

The most difficult. My arguments:

1. Problem of a choice of correct type for the object. A mathematical matrix - a classical example. A class it should be or structure?

My offer without serious consequences allows to move solution of this problem from a design stage to a programming stage - is it will be simple by replacement keyword class to struct.


2. Performance increases. It is not necessary to allocate at the slightest pretext memory in a heap.


3. I offer syntax which presumably does not break an existing code.
+ On how many I understand, in the existing compiler all necessary for
implementation already is, a problem only in syntax addition.


4. Java and C# also uses objects by reference? But both these of language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.

D is compiled language and to borrow reference model incorrectly. In D
the programmer should have possibility most to decide where to place object.


> You still have the problem that the current system works pretty well. And has a lot of history.  So you need a very compelling use case to convince Walter that something should change.

Thus, actually Java and C# systems works pretty well. And they has a lot of history. But not D.


This situation reminds me history with the Hungarian notation:
Many years ago many developers have started to deliver interfaces and to
sell books where it was used. This very correct invention affirmed as
many books that and only in ~5 years there were articles with the
materials specifying in groundlessness of usage of this notation. Till
this time many entered it into corporate standards and suffered, though,
I am sure, they were visited by thoughts about irrelevance of the
given notation except for special cases.
January 11, 2009
On Sun, 11 Jan 2009 05:04:11 +0300, Weed <resume755@mail.ru> wrote:

> Bill Baxter пишет:
>> 2009/1/11 Weed <resume755@mail.ru>:
>>> Bill Baxter пишет:
>>>
>>>> But since classes can be polymorphic, value copying gets you into
>>>> slicing problems.  That's why value copying is disabled to begin with.
>>>>  So disabling value copies is a good thing.
>>> It is not always a good thing.
>>
>> Yeh, I just mean there is some merit in disabling value copies.  But I
>> don't rule out the possibility that there may be an even better way
>> that banning them altogether.
>>
>>> I propose to prohibit only the copying by value of the base type to
>>> derivative type
>>
>> Ok, this is key.  How do you propose to do this?  In general it
>> requires a runtime check, I think.
>> And I think you need to say that you prohibit copying unless
>> typeA==typeB exactly.  If you allow copying either way between base
>> and derived you are asking for trouble.
>>
>> But still given
>>   Base x = get_one();
>>   Base y = get_another();
>>   *x = *y; // presumed value copy syntax
>>
>> you have no way in general to know that x and y are really both a Base
>> at compile time.  So you must have a run-time check there.  Perhaps it
>> could be omitted for -release builds, though.
>
> It can lead to a difficult and non-reproduceable errors than old
> C++-style splitting.
>
> It is possible to try to prohibit assignment of the dereferenced
> pointers? Simply to prohibit assignment too it is possible, essentially
> it changes nothing.
>

Err.. I don't get what you say. The *x = *y is just one of the possible syntaxes, nothing else.

>>>> And that's also the problem with putting scope'd things inside another
>>>> class or an array.  Since they don't have value semantics,
>>> Yes, this is what I mean
>>
>> So assuming you had this, the important question is what would you do with it?
>
> The most difficult. My arguments:
>
> 1. Problem of a choice of correct type for the object. A mathematical
> matrix - a classical example. A class it should be or structure?
>
> My offer without serious consequences allows to move solution of this
> problem from a design stage to a programming stage - is it will be
> simple by replacement keyword class to struct.
>

Having the same syntax for both classes and struct is a nice goal, I agree.
But it should be taken as a different issue and solved separately, too.

>
> 2. Performance increases. It is not necessary to allocate at the
> slightest pretext memory in a heap.
>
>
> 3. I offer syntax which presumably does not break an existing code.
> + On how many I understand, in the existing compiler all necessary for
> implementation already is, a problem only in syntax addition.
>
>
> 4. Java and C# also uses objects by reference? But both these of
> language are interpreted. I assume that the interpreter generally with
> identical speed allocates memory in a heap and in a stack, therefore
> authors of these languages and used reference model.
>

Neither of these languages are interpreted, they both are compiled into native code at runtime.

> D is compiled language and to borrow reference model incorrectly. In D
> the programmer should have possibility most to decide where to place object.
>
>
>> You still have the problem that the current system works pretty well.
>> And has a lot of history.  So you need a very compelling use case to
>> convince Walter that something should change.
>
> Thus, actually Java and C# systems works pretty well. And they has a lot
> of history. But not D.
>

DMD 0.001 was released 7 years ago. Long enough, I think.

>
> This situation reminds me history with the Hungarian notation:
> Many years ago many developers have started to deliver interfaces and to
> sell books where it was used. This very correct invention affirmed as
> many books that and only in ~5 years there were articles with the
> materials specifying in groundlessness of usage of this notation. Till
> this time many entered it into corporate standards and suffered, though,
> I am sure, they were visited by thoughts about irrelevance of the
> given notation except for special cases.

January 11, 2009
Denis Koroskin пишет:
> On Sun, 11 Jan 2009 05:04:11 +0300, Weed <resume755@mail.ru> wrote:
> 
>> Bill Baxter пишет:
>>> 2009/1/11 Weed <resume755@mail.ru>:
>>>> Bill Baxter пишет:
>>>>
>>>>> But since classes can be polymorphic, value copying gets you into
>>>>> slicing problems.  That's why value copying is disabled to begin with.
>>>>>  So disabling value copies is a good thing.
>>>> It is not always a good thing.
>>>
>>> Yeh, I just mean there is some merit in disabling value copies.  But I don't rule out the possibility that there may be an even better way that banning them altogether.
>>>
>>>> I propose to prohibit only the copying by value of the base type to derivative type
>>>
>>> Ok, this is key.  How do you propose to do this?  In general it
>>> requires a runtime check, I think.
>>> And I think you need to say that you prohibit copying unless
>>> typeA==typeB exactly.  If you allow copying either way between base
>>> and derived you are asking for trouble.
>>>
>>> But still given
>>>   Base x = get_one();
>>>   Base y = get_another();
>>>   *x = *y; // presumed value copy syntax
>>>
>>> you have no way in general to know that x and y are really both a Base at compile time.  So you must have a run-time check there.  Perhaps it could be omitted for -release builds, though.
>>
>> It can lead to a difficult and non-reproduceable errors than old C++-style splitting.
>>
>> It is possible to try to prohibit assignment of the dereferenced pointers? Simply to prohibit assignment too it is possible, essentially it changes nothing.
>>
> 
> Err.. I don't get what you say. The *x = *y is just one of the possible syntaxes, nothing else.
> 

(I have incorrectly expressed)

If dereferencing was not used in lvalue or rvalue and is both a classes by value it is possible to assignment, except cases when the base type to the derivative is assigned.

Example:

class C {}
class C2 : C {}

C c();
C2 c2();

C* c_p = &c;
C2* c2_p = &c2;

c = c2; // ok
c2 = c; // err
*c_p = *c2_p; // err
*c2_p = *c_p; // err
c2 = *c2_p; // err

and:
c = c2 + *c2_p; // ok

>>>>> And that's also the problem with putting scope'd things inside another class or an array.  Since they don't have value semantics,
>>>> Yes, this is what I mean
>>>
>>> So assuming you had this, the important question is what would you do with it?
>>
>> The most difficult. My arguments:
>>
>> 1. Problem of a choice of correct type for the object. A mathematical matrix - a classical example. A class it should be or structure?
>>
>> My offer without serious consequences allows to move solution of this problem from a design stage to a programming stage - is it will be simple by replacement keyword class to struct.
>>
> 
> Having the same syntax for both classes and struct is a nice goal, I agree. But it should be taken as a different issue and solved separately, too.

So I offer: the inheritance of structures this one of offers, which in itself it seems insignificant, but useful if to make classes by value.

>>
>> 2. Performance increases. It is not necessary to allocate at the slightest pretext memory in a heap.
>>
>>
>> 3. I offer syntax which presumably does not break an existing code.
>> + On how many I understand, in the existing compiler all necessary for
>> implementation already is, a problem only in syntax addition.
>>
>>
>> 4. Java and C# also uses objects by reference? But both these of language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.
>>
> 
> Neither of these languages are interpreted, they both are compiled into native code at runtime.

Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.

> 
>> D is compiled language and to borrow reference model incorrectly. In D the programmer should have possibility most to decide where to place object.
>>
>>
>>> You still have the problem that the current system works pretty well. And has a lot of history.  So you need a very compelling use case to convince Walter that something should change.
>>
>> Thus, actually Java and C# systems works pretty well. And they has a lot of history. But not D.
>>
> 
> DMD 0.001 was released 7 years ago. Long enough, I think.

Yes, I know.
I hint at that that it seems this scheme have copied because it is
popular but have not considered characteristic for C++-like compiled
language nuances.
January 11, 2009
Weed пишет:

>>> 4. Java and C# also uses objects by reference? But both these of language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.
>>>
>> Neither of these languages are interpreted, they both are compiled into native code at runtime.
> 
> Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.
> 

I guess allocation in Java occurs fast because of usage of the its own
memory manager.

I do not know how it is fair, but:
http://www.ibm.com/developerworks/java/library/j-jtp09275.html

"Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."

Therefore they do not worry concerning performance of creation of objects in a heap and reference classes for them approach.
January 11, 2009
Weed wrote:
> Weed пишет:
> 
>>>> 4. Java and C# also uses objects by reference? But both these of
>>>> language are interpreted. I assume that the interpreter generally with
>>>> identical speed allocates memory in a heap and in a stack, therefore
>>>> authors of these languages and used reference model.
>>>>
>>> Neither of these languages are interpreted, they both are compiled into
>>> native code at runtime.
>> Oh!:) but I suspect such classes scheme somehow correspond with
>> JIT-compilation.
>>
> 
> I guess allocation in Java occurs fast because of usage of the its own
> memory manager.
> 	
> I do not know how it is fair, but:
> http://www.ibm.com/developerworks/java/library/j-jtp09275.html
> 
> "Pop quiz: Which language boasts faster raw allocation performance, the
> Java language, or C/C++? The answer may surprise you -- allocation in
> modern JVMs is far faster than the best performing malloc
> implementations. The common code path for new Object() in HotSpot 1.4.2
> and later is approximately 10 machine instructions (data provided by
> Sun; see Resources), whereas the best performing malloc implementations
> in C require on average between 60 and 100 instructions per call
> (Detlefs, et. al.; see Resources)."

Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model.

Andrei
January 11, 2009
Andrei Alexandrescu wrote:
> Weed wrote:
>> Weed пишет:
>>
>>>>> 4. Java and C# also uses objects by reference? But both these of language are interpreted. I assume that the interpreter generally with identical speed allocates memory in a heap and in a stack, therefore authors of these languages and used reference model.
>>>>>
>>>> Neither of these languages are interpreted, they both are compiled into native code at runtime.
>>> Oh!:) but I suspect such classes scheme somehow correspond with JIT-compilation.
>>>
>>
>> I guess allocation in Java occurs fast because of usage of the its own
>> memory manager.
>> 
>> I do not know how it is fair, but:
>> http://www.ibm.com/developerworks/java/library/j-jtp09275.html
>>
>> "Pop quiz: Which language boasts faster raw allocation performance, the Java language, or C/C++? The answer may surprise you -- allocation in modern JVMs is far faster than the best performing malloc implementations. The common code path for new Object() in HotSpot 1.4.2 and later is approximately 10 machine instructions (data provided by Sun; see Resources), whereas the best performing malloc implementations in C require on average between 60 and 100 instructions per call (Detlefs, et. al.; see Resources)."
> 
> Meh, that should be taken with a grain of salt. An allocator that only bumps a pointer will simply eat more memory and be less cache-friendly. Many applications aren't that thrilled with the costs of such a model.
> 
> Andrei

Take it as nicely seasoned.  The current jvm gc and memory subsystem is _extremely_ clever.  However, it completely relies on the ability to move objects during garbage collection.  If it was purely the allocator that behaved that way, you'd be right.  But it's interaction with the gc is where the system comes together to form a useful whole.

Later,
Brad