February 09, 2009
Christopher Wright пишет:
> Weed wrote:
>> (Has started here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81359)
>>
>>
>> To me still does not give rest performance of classes (in comparison
>> with C++ or with D structs)
> 
> On my system, your struct example averaged 0.36 seconds, and your class example averaged 0.38 seconds.
> 
> Your benchmark is flawed in three ways:
> 1. You're timing allocations in the class example. Use opAddAssign to
> avoid it.

Earlier I proved that it is impossible. For example here in such expression:
==============
space_ship_1.calculatePathTo("Moon").getCheckpoint(3).getCoords;

In this example we create a temporary class "path", create temporary
class "checkpoint" and we take coords of checkpoint of this path. It is
not expedient to us to store all this path and checkpoint because it is
vary.
==============

> 2. You're passing large structs in the struct example. Use ref to avoid it.
> 3. c1 is never assigned to, so c1 + c1 + c1 is moved outside the loop.
> The assignment has no side effect, so the loop is optimized out. Replace
> "c1 + c1 + c1" with "c1 + c2 + c1", for instance, and the struct example
> takes 20 seconds rather than 0.36.

Really, it has a little affected. Thanks!
February 09, 2009
Rainer Deyke пишет:
> Michel Fortin wrote:
>> Polymorphism doesn't work very well while passing objects by value, even in C++. This is called the slicing problem.
> 
> I have heard about the slicing problem.  I know what it is.  But in all my years of using C++ as my primary language, I have never actually encountered it.  I don't believe it actually exists.

I am absolutely agree with you.

Besides, slicing it is possible to detect in a compile time in many cases.

It can be too grandiloquent sounds, but in D us have deprived of one degree of freedom - freedom to use a stack.
February 09, 2009
Walter Bright пишет:
> Frits van Bommel wrote:
>> Which helps (a bit) with the two instances allocated in main(), but is
>> rather unhelpful with the 100_000_000 allocated in opAdd() (they're
>> returned)...
> 
> The use of classes in this example is like using a screwdriver as a hammer. It'll work in a pinch, but a hammer works a lot better. If you're allocating 100_000_000 classes in a tight loop, some refactoring looks to be in order.
> 
> In particular, classes are *meant* to be used as reference types, but the program is trying to treat them as value types.

But without such types the bulky code turns out
(examples in this branch already presented)

> Virtual functions
> are orthogonal to what value types are - a continuing problem C++
> programs have is conflating value types with reference types.

The compiler cannot optimize such code? No

We have virtual machine for fast allocations of memory at such heavy using of objects? No

Perfectly - it is necessary to leave this question to the programmer: the class will be stored in a stack or in a heap is better will solve the programmer instead of the compiler.

It is impossible to lose to an C++ in what.
February 09, 2009
On Mon, Feb 09, 2009 at 09:59:50AM +0700, Weed wrote:
> Perfectly - it is necessary to leave this question to the programmer: the class will be stored in a stack or in a heap is better will solve the programmer instead of the compiler.

scope class does just that. You can also put a custom allocator in your class and do whatever you want.

-- 
Adam D. Ruppe
http://arsdnet.net
February 09, 2009
Radu пишет:

> While nor so orthodox, this improves the situation a bit:
> 
> template stackAllocator(T) {
>    new(size_t size, void* sp = alloca(T.classinfo.init.length)) {
>        return sp;
>    }
> 
>    delete(void* ptr) {
>    }
> }
> 
> final class C {
>    int i;
>    real[5] unused; // to prevent returning this object in registers
> 
>    C opAdd(C src) {
>        auto ret = new C;
>        ret.i = i + src.i;
>        return ret;
>    }
> 
>    mixin stackAllocator!(C);
> 
> }
> 
> Radu

If the used object it is impossible to change? It is written by other person, for example?

And, we all will take for a rule in each object using overload to add stackAllocator?
February 09, 2009
Adam D. Ruppe пишет:
> On Mon, Feb 09, 2009 at 09:59:50AM +0700, Weed wrote:
>> Perfectly - it is necessary to leave this question to the programmer: the class will be stored in a stack or in a heap is better will solve the programmer instead of the compiler.
> 
> scope class does just that.

No, D do not allow return scope value.

> You can also put a custom allocator in your
> class and do whatever you want.
> 

Often you add custom allocator in the classes who uses overload? You begin to do it after that talk? :)
February 09, 2009
Weed wrote:
> Christopher Wright пишет:
>> Weed wrote:
>>> (Has started here:
>>> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81359)
>>>
>>>
>>> To me still does not give rest performance of classes (in comparison
>>> with C++ or with D structs)
>> On my system, your struct example averaged 0.36 seconds, and your class
>> example averaged 0.38 seconds.
>>
>> Your benchmark is flawed in three ways:
>> 1. You're timing allocations in the class example. Use opAddAssign to
>> avoid it.
> 
> Earlier I proved that it is impossible. For example here in such expression:
> ==============
> space_ship_1.calculatePathTo("Moon").getCheckpoint(3).getCoords;
> 
> In this example we create a temporary class "path", create temporary
> class "checkpoint" and we take coords of checkpoint of this path. It is
> not expedient to us to store all this path and checkpoint because it is
> vary.
> ==============

In that example, you can use structs instead of classes. Your response to that is that structs do not participate in polymorphism.

There was a suggestion elsewhere like this:
interface IPathResolver
{
	Checkpoint getCheckpoint(Path* path, int i);
}

struct Path
{
	char[] path;
	// any other info you need....
	IPathResolver resolver;
	Checkpoint getCheckpoint(int value)
	{
		return resolver.getCheckpoint(this, value);
	}
}

This way, you only allocate once for each type you need, you have polymorphism, and you can put stuff on the stack for quick access.
February 09, 2009
Christopher Wright пишет:
> Weed wrote:
>> Christopher Wright пишет:
>>> Weed wrote:
>>>> (Has started here: http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.D&article_id=81359)
>>>>
>>>>
>>>>
>>>> To me still does not give rest performance of classes (in comparison
>>>> with C++ or with D structs)
>>> On my system, your struct example averaged 0.36 seconds, and your class example averaged 0.38 seconds.
>>>
>>> Your benchmark is flawed in three ways:
>>> 1. You're timing allocations in the class example. Use opAddAssign to
>>> avoid it.
>>
>> Earlier I proved that it is impossible. For example here in such
>> expression:
>> ==============
>> space_ship_1.calculatePathTo("Moon").getCheckpoint(3).getCoords;
>>
>> In this example we create a temporary class "path", create temporary
>> class "checkpoint" and we take coords of checkpoint of this path. It is
>> not expedient to us to store all this path and checkpoint because it is
>> vary.
>> ==============
> 
> In that example, you can use structs instead of classes. Your response to that is that structs do not participate in polymorphism.
> 
> There was a suggestion elsewhere like this:
> interface IPathResolver
> {
>     Checkpoint getCheckpoint(Path* path, int i);
> }
> 
> struct Path
> {
>     char[] path;
>     // any other info you need....
>     IPathResolver resolver;
>     Checkpoint getCheckpoint(int value)
>     {
>         return resolver.getCheckpoint(this, value);
>     }
> }
> 
> This way, you only allocate once for each type you need, you have polymorphism, and you can put stuff on the stack for quick access.

And if I need some different such combinations? For each it is necessary to write such 8-10 lines? This is terrible!
February 09, 2009
Michel Fortin пишет:
> On 2009-02-08 09:30:08 -0500, Weed <resume755@mail.ru> said:
> 
>> Let's assume, polymorphism is necessary to these objects
> 
> Polymorphism doesn't work very well while passing objects by value, even
> in C++. This is called the slicing problem.
> <http://stackoverflow.com/questions/274626/what-is-the-slicing-problem-in-c>
> 
> 
> I think D does a good job at avoiding that problem.
> 

By performance loss
:(
February 09, 2009
Andrei Alexandrescu wrote:
> How long have you used C++?

My first serious C++ project was started in 1997.

> This is not a tendentious question. In the recent years, the advent of quality smart pointers, an increased scrutiny of use of inheritance, and the teaching of idioms associated with reference types has greatly diminished slicing accidents. But in the olden days, people were inheriting value types left and right because it was the emperor's new clothes.

Slicing is caused by naive copying of polymorphic types, which is only tangentially related to inheriting value types.

Example 1 (C++):

struct point2d {
  int x, int y;
};

struct point3d : public point2d {
  int z;
}

'point2d' is a non-polymorphic value type.  Slicing behavior exists, is intentional, and does not invalidate any invariants.

Example 2 (C++):

class data_source {
public:
  virtual char read_byte() = 0;
};

class input_file : public data_source {
public:
  char read_byte() = 0;
};

'input_file' is a value type that implements an interface.  No slicing problem exists because 'data_source' is an abstract type.

Example 3 (C++):

class person {
public:
  person(person const& org) {
    assert(typeid(org) == typeid(*this));
  }
  virtual ~person() {}
};

class avatar : public person, public deity {
};

'person' and 'avatar' are value types that can be used polymorphically.
 In any context 'person&' may be either a reference to an instance of
class 'person' or a polymorphic reference to an instance of any class
that inherits from 'person'.  Unfortunately the C++ type system does not
distinguish between these two uses.  It is an error (checked at runtime)
to construct a new 'person' from a polymorphic reference, but any other
use of 'person' as a value type or a polymorphic type is valid.  No
slicing problem exists except through user error.

Example 4 (D):

class RubberChicken {
  RubberChicken dup() {
    return new RubberChicken();
  }
}

class RubberChickenWithAPulleyInTheMiddle {
  private Pulley pulley;
  // Forget to override 'dup'.
}

Here 'RubberChicken' is a reference type, but due to programmer error, the slicing problem still exists.


-- 
Rainer Deyke - rainerd@eldwood.com