View mode: basic / threaded / horizontal-split · Log in · Help
October 23, 2009
Re: this() not executing code on structs
Don wrote:
> Bartosz Milewski wrote:
>> Andrei Alexandrescu Wrote:
>>
>>>     this() { myCount = count++; }       // ERROR
>>
>> It's worse than that. Try this:
>>
>> struct foo {
>>        this(int dummy = 0) { writeln("Default constructor");}
>> }
>>
>> foo x = foo();
>>
>> Nothing gets printed. If default constructors are disallowed, so 
>> should constructors with all parameters defaulted.
> 
> Ouch.
> It's because it's interpreting foo() as a struct literal.
> If a struct has any constructors, struct literals should be disabled.

http://d.puremagic.com/issues/show_bug.cgi?id=3438

The more I think of it, the more imperious it becomes that we allow 
default constructors that execute code. The main question is what to do 
about .init.

Andrei
October 23, 2009
Re: this() not executing code on structs
On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
<SeeWebsiteForEmail@erdani.org> wrote:

> Don wrote:
>> Bartosz Milewski wrote:
>>> Andrei Alexandrescu Wrote:
>>>
>>>>     this() { myCount = count++; }       // ERROR
>>>
>>> It's worse than that. Try this:
>>>
>>> struct foo {
>>>        this(int dummy = 0) { writeln("Default constructor");}
>>> }
>>>
>>> foo x = foo();
>>>
>>> Nothing gets printed. If default constructors are disallowed, so  
>>> should constructors with all parameters defaulted.
>>  Ouch.
>> It's because it's interpreting foo() as a struct literal.
>> If a struct has any constructors, struct literals should be disabled.
>
> http://d.puremagic.com/issues/show_bug.cgi?id=3438
>
> The more I think of it, the more imperious it becomes that we allow  
> default constructors that execute code. The main question is what to do  
> about .init.
>
> Andrei

I'd suggest ditching it and enforce explicit member initialization (unless  
a variable is nullable). This will also remove a lot of bloat from  
executables.
October 23, 2009
Re: this() not executing code on structs
Denis Koroskin wrote:
> On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu 
> <SeeWebsiteForEmail@erdani.org> wrote:
> 
>> Don wrote:
>>> Bartosz Milewski wrote:
>>>> Andrei Alexandrescu Wrote:
>>>>
>>>>>     this() { myCount = count++; }       // ERROR
>>>>
>>>> It's worse than that. Try this:
>>>>
>>>> struct foo {
>>>>        this(int dummy = 0) { writeln("Default constructor");}
>>>> }
>>>>
>>>> foo x = foo();
>>>>
>>>> Nothing gets printed. If default constructors are disallowed, so 
>>>> should constructors with all parameters defaulted.
>>>  Ouch.
>>> It's because it's interpreting foo() as a struct literal.
>>> If a struct has any constructors, struct literals should be disabled.
>>
>> http://d.puremagic.com/issues/show_bug.cgi?id=3438
>>
>> The more I think of it, the more imperious it becomes that we allow 
>> default constructors that execute code. The main question is what to 
>> do about .init.
>>
>> Andrei
> 
> I'd suggest ditching it and enforce explicit member initialization 
> (unless a variable is nullable). This will also remove a lot of bloat 
> from executables.

I don't understand. The problem right now is that even of all fields are 
explicitly intialized, e.g.

struct A {
    Widget x = null;
    double d = 0;
    int i = -1;
}

there is still no ability to execute code upon initialization, e.g. 
force A to contain a non-null Widget.


Andrei
October 23, 2009
Re: this() not executing code on structs
On Fri, 23 Oct 2009 19:40:33 +0400, Andrei Alexandrescu
<SeeWebsiteForEmail@erdani.org> wrote:

> Denis Koroskin wrote:
>> On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
>> <SeeWebsiteForEmail@erdani.org> wrote:
>>
>>> Don wrote:
>>>> Bartosz Milewski wrote:
>>>>> Andrei Alexandrescu Wrote:
>>>>>
>>>>>>     this() { myCount = count++; }       // ERROR
>>>>>
>>>>> It's worse than that. Try this:
>>>>>
>>>>> struct foo {
>>>>>        this(int dummy = 0) { writeln("Default constructor");}
>>>>> }
>>>>>
>>>>> foo x = foo();
>>>>>
>>>>> Nothing gets printed. If default constructors are disallowed, so  
>>>>> should constructors with all parameters defaulted.
>>>>  Ouch.
>>>> It's because it's interpreting foo() as a struct literal.
>>>> If a struct has any constructors, struct literals should be disabled.
>>>
>>> http://d.puremagic.com/issues/show_bug.cgi?id=3438
>>>
>>> The more I think of it, the more imperious it becomes that we allow  
>>> default constructors that execute code. The main question is what to  
>>> do about .init.
>>>
>>> Andrei
>>  I'd suggest ditching it and enforce explicit member initialization  
>> (unless a variable is nullable). This will also remove a lot of bloat  
>> from executables.
>
> I don't understand. The problem right now is that even of all fields are  
> explicitly intialized, e.g.
>
> struct A {
>      Widget x = null;
>      double d = 0;
>      int i = -1;
> }
>
> there is still no ability to execute code upon initialization, e.g.  
> force A to contain a non-null Widget.
>
>
> Andrei

Yes, I was talking about a different scheme, where default ctors are
allowed. They aren't allowed now but we are talking about things we can
change/improve, right?

I mean there is no _real_ need for T.init, just malloc()'ate some memory  
and call the __ctor on it. Struct members default values would be  
converted into runtime initialization expressions like this:

struct A
{
    this(Args)(Args args) // may be an empty set of arguments
    {
        // the following lines are inserted automatically
        x = null;
        d = 0;
        i = -1;

        // user-defined code follows
        i = 42;
    }

    Widget x = null;
    double d = 0;
    int i = -1;
}

Optimization pass would eliminate double initialization (in the case about  
i would be initialized straight to 42)
October 23, 2009
Re: this() not executing code on structs
Steven Schveighoffer wrote:
> On Thu, 22 Oct 2009 12:50:21 -0400, grauzone <none@example.net> wrote:
> 
>> dsimcha wrote:
>>> == Quote from grauzone (none@example.net)'s article
>>>> Andrei Alexandrescu wrote:
>>>> I'd really like to know why "scope x = new X();" is "unsafe", while
>>>> encouraging doing exactly the same with structs seems to be a perfectly
>>>> fine idea. Allocating structs on the stack is obviously not any safer
>>>> than with classes. I don't remember the exact reasons why you wanted to
>>>> turn "scope" into a library feature, but I think I remember something
>>>> about discouraging it for safety reasons; please forgive me is this is
>>>> wrong.
>>>  Because classes in D are always passed by pointer.  (Technically 
>>> references, but
>>> really they're just pointers under the hood.)  Returning a scope 
>>> (stack-allocated)
>>> class from a function is equivalent to escaping a pointer to a stack 
>>> variable.
>>> Returning a struct is done by value, just like returning an int.
>>
>> (I'm talking about scope classes as declared in "scope class T { ... }")
> 
> Your original question was about the statement "scope x = new X()", 
> which can be done on any type of class, even non-scope ones.

I mentioned that "scope class T" thing in my original post too.

> 
>> But you can't return scope classes from a function. You can't pass 
>> them as ref parameters either. They're designed to be safe.
>>
>> On the other hand, you can pass struct pointers all the way you want 
>> around, and it's damn unsafe.
>>
>> I don't get this "structs are safe because they are value types" 
>> argument anyway, because the this pointer for structs is a 
>> pointer/reference anyway. If it's trivial to break that "safety", can 
>> you really call it "safety"?
> 
> Passing struct pointers is not always the norm.  Passing class 
> references *is* the norm (and actually the only way), even for scope 
> classes, so there is much more chance for escape.

You can end up passing hidden pointers quickly, because a struct's this 
is a reference, and there are ref parameters and even ref returns. But 
Andrei is convinced that he can make passing refs safe, and as soon as 
they're safe, you're probably right.

>>> Scope is really a dangerous hack to allocate a *reference type* on 
>>> the stack.
>>> It's dangerous and kludgey, but in a performance-oriented language 
>>> it's a
>>> necessary evil.
>>
>> You could say the same about structs.
> 
> You have to go out of your way to pass a struct by reference.  You 
> *can't* possibly pass a class by value, so they are more dangerous.
> 
> In order to make scope safer, it has to be a type modifier in addition 
> to a storage class, so the compiler can make reasonable decisions (like 
> disallowing implicit casting to a non-scope version).

That would have been possible. That type modifiers is already there and 
is partially implemented. But Andrei seems to have decided to go another 
way (using structs instead of classes), and this will become a useless 
feature. So I hope it will be removed to make the language less bloater.

> <OT>
> 
>> Why do all objects have monitor pointers anyway? The idea, that every 
>> object can act as lock, is a really bad one. But this is off-topic...
> 
> All objects have a *placeholder* for a lock, which isn't allocated until 
> the object is locked for the first time.  It's a very pervasive idea in 
> other successful languages like Java and C#.  Having used it extensively 
> in C#, I find it very easy to use and well designed.

I found it never useful. Even more, implicitly using an object as a lock 
makes the locking scheme more unclear ("which object is a lock and which 
isn't? I can't tell anymore!"), and I see lots of code that does the 
"Object lock = new Object();" thing to get rid of this confusion.

Being able to use an object as lock looks like a nice, naive idea from 
the early days of multithreading, but it's obsolete now.

Even if the allocation of the mutex is done lazily on demand, why add 
overhead to *all* light weight objects for such a useless thing?

> However, in C#, there is support for conditions on objects as well, 
> which isn't "builtin" for D.  IMO, mutexes without conditions is 
> severely limiting.  The library condition variables aren't as nice as 
> C#'s builtin conditions.

I always wondered how D could claim to make "big steps" into 
multithreading, without having any mechanism to signal other threads; it 
only had locks. The library condition variables from D runtime just 
fixed this hole from "outside".

> </OT>
> 
> -Steve
October 24, 2009
Re: this() not executing code on structs
On Sat, 24 Oct 2009 03:28:02 +0400, Denis Koroskin <2korden@gmail.com>  
wrote:

> On Fri, 23 Oct 2009 19:40:33 +0400, Andrei Alexandrescu
> <SeeWebsiteForEmail@erdani.org> wrote:
>
>> Denis Koroskin wrote:
>>> On Fri, 23 Oct 2009 18:46:47 +0400, Andrei Alexandrescu  
>>> <SeeWebsiteForEmail@erdani.org> wrote:
>>>
>>>> Don wrote:
>>>>> Bartosz Milewski wrote:
>>>>>> Andrei Alexandrescu Wrote:
>>>>>>
>>>>>>>     this() { myCount = count++; }       // ERROR
>>>>>>
>>>>>> It's worse than that. Try this:
>>>>>>
>>>>>> struct foo {
>>>>>>        this(int dummy = 0) { writeln("Default constructor");}
>>>>>> }
>>>>>>
>>>>>> foo x = foo();
>>>>>>
>>>>>> Nothing gets printed. If default constructors are disallowed, so  
>>>>>> should constructors with all parameters defaulted.
>>>>>  Ouch.
>>>>> It's because it's interpreting foo() as a struct literal.
>>>>> If a struct has any constructors, struct literals should be disabled.
>>>>
>>>> http://d.puremagic.com/issues/show_bug.cgi?id=3438
>>>>
>>>> The more I think of it, the more imperious it becomes that we allow  
>>>> default constructors that execute code. The main question is what to  
>>>> do about .init.
>>>>
>>>> Andrei
>>>  I'd suggest ditching it and enforce explicit member initialization  
>>> (unless a variable is nullable). This will also remove a lot of bloat  
>>> from executables.
>>
>> I don't understand. The problem right now is that even of all fields  
>> are explicitly intialized, e.g.
>>
>> struct A {
>>      Widget x = null;
>>      double d = 0;
>>      int i = -1;
>> }
>>
>> there is still no ability to execute code upon initialization, e.g.  
>> force A to contain a non-null Widget.
>>
>>
>> Andrei
>
> Yes, I was talking about a different scheme, where default ctors are
> allowed. They aren't allowed now but we are talking about things we can
> change/improve, right?
>
> I mean there is no _real_ need for T.init, just malloc()'ate some memory  
> and call the __ctor on it. Struct members default values would be  
> converted into runtime initialization expressions like this:
>
> struct A
> {
>      this(Args)(Args args) // may be an empty set of arguments
>      {
>          // the following lines are inserted automatically
>          x = null;
>          d = 0;
>          i = -1;
>
>          // user-defined code follows
>          i = 42;
>      }
>
>      Widget x = null;
>      double d = 0;
>      int i = -1;
> }
>
> Optimization pass would eliminate double initialization (in the case  
> about i would be initialized straight to 42)

This scheme works fine for C++, and it would fit languages that don't  
support MI even better.

I believe D's approach with init is a bit easier to understand (rules are  
less complicated), but it is also not very efficient: a few stores/pushes  
are faster than memcpy'ing few bytes in most cases (minor but still). And  
an additional bloat it introduces is also not very welcome, of course.

While I'm not a idealizing C++ object initialization scheme, I do think it  
is sound (even though it is complicated). Some variation of it may be well  
suitable for D.

I made the following post a while ago  
(http://www.digitalmars.com/d/archives/digitalmars/D/D_programming_practices_object_construction_order_85468.html),  
it may interest you as I believe it is relevant to this discussion.  
Unfortunately no one has made any comments about it (is it silly, or just  
nobody cares?).
Next ›   Last »
1 2 3
Top | Discussion index | About this forum | D home