December 30, 2013
On 12/30/13 3:34 AM, Ritu wrote:
>
>> But then the source object may not be mutable. I am not a compiler
>> expert, but could a special case be made in D compiler for the cases
>> where the source struct instance is mutable and is made available to
>> ease such lazy initialization?
>
>
> I am suggesting a DIP here.

Did you take a look at http://wiki.dlang.org/DIP49 and http://wiki.dlang.org/DIP53?

Andrei


December 30, 2013
On Sunday, 29 December 2013 at 19:26:09 UTC, monarch_dodra wrote:
> Nope. What you are asking for is basically a default constructor, which D does not provide. Workarounds include the "static opCall" pattern, as well as the "function builder" pattern (eg: "MyStruct myStruct(Args args)")

Actually it does provide, but does not allow to override it. When you define postblit, dmd generates default constructor like this:

struct S
{
   int data[];
   this(this) { data = data.dup; }
   void __cpctor(const ref S s) const
   {
      this = s;
      s.__postblit();
   }
}

The only way to override it is currently is to make your function, drop original symbol from binary file and link the program.
I think it could work like opAssign - provide default version but allow to place yours. In such case it would be possible to alter original struct object but it would lead to conflict if original object is const or immutable qualified.
December 30, 2013
On 12/30/13 7:58 AM, Benjamin Thaut wrote:
> Am 30.12.2013 16:53, schrieb Andrei Alexandrescu:
>> On 12/30/13 3:29 AM, Benjamin Thaut wrote:
>>>
>>>
>>> As I already said, the solution is another level of indirection. I had a
>>> similar discussion with Andrei a while back and he made clear that there
>>> is no intention in adding any other copy constructor / move constructor.
>>> Postblit will stay as is.
>>
>> Walter is reconsidering that.
>>
>> Andrei
>>
>
> Oh? Could you give a bit more details on the state of this?

There's no state. Just that it's an area in which Walter is opened to a language change. Kenji is opposed though.

Andrei


December 30, 2013
Am 30.12.2013 17:19, schrieb Andrei Alexandrescu:
> There's no state. Just that it's an area in which Walter is opened to a
> language change. Kenji is opposed though.
>
> Andrei
>
>

I must say, that the current situation with only postblit makes it quite easy to implement containers and gives a lot of flexiblity when handling user defined value types in general. But as shown in this thread not every use case can be implemented with just a postblit. I had some other use cases in the past where postblit was not enough, and I had to work around by adding one level of indirection. Usually these use cases involve wrapping a pointer or a reference to an object.

Kind Regards
Benjamin Thaut
December 30, 2013
> There's no state. Just that it's an area in which Walter is opened to a language change. Kenji is opposed though.
>
> Andrei


Greetings

I thank Andrei for spending some time on this thread and for informing that he and Walter are actively considering extensions to the postblit behavior. I take this opportunity to present a detailed use case of ours.

We have been working on implementing a Domain Specific Embedded Language in D. As is true with most other DSLs, the end users would be domain experts and not necessarily expert programmers. In our case the DSL we are creating would be useful for modeling systems in a specific domain.

I will try to create a small use case here. We want to provide our users with a construct called Fifo. A Fifo would be useful to enable data exchange between different blocks of the system being modeled. Typically a Fifo will allow different agents in the system to push or pull data. Additionally we want to enable following capabilities with a Fifo construct:

a/ Ability to declare an array (even multidimensional array) or Fifo's.
b/ Ability to pass a Fifo to a function argument. Also ability to pass an array of Fifos as an argument.
c/ Ability to pass a Fifo to std functions like writeln. In such a scenario, the element on the top of the Fifo gets printed.

Let us consider different aspects of providing the Fifo construct:

1. Fifo should be a Struct (not a Class)

A class instance necessarily needs to be initialized. With a struct we have possibility of lazy initialization.

2. Fifo initialization

As some forumites have suggested, one option is to force initialization at the time of declaration. I do not think this is a good option as far as a DSL is concerned. First of all there is no way in D (at least I am not aware) to disallow the default constructor (the init value must exist). Even for a class object, there is no way to keep the end-user away from trying to use null objects. Secondly, forcing initialization right at the time of declaration might require lots of boiler-plate code. While patterns like static opcall initialization may be good for programmers, these are not intuitive for the purpose of a DSL. Besides consider the amount of boilerplate code required for initializing all the Fifos in a 3 dimensional array of Fifos (requirement (a) in the list above).

3. Lazy Initialization

Given that explicit initialization may not be good enough, we consider lazy initialization. It mostly works, but does not fully satisfy requirement (b). An uninitialized Fifo when passed as a function argument exhibits totally unexpected behavior.

4. Forcing Fifo argument to be passed as a ref

This may be too difficult to explain to the end-user. To force it we may be required to disable the postblit (thereby disabling the copy constructor). But when we do that, a lot of other unexpected issues come up. For example the std.stdio.writeln expects copyable arguments. If we disable postblit, it becomes impossible to print the object using writeln (see requirement (c)).


With all these considerations, we need our Fifo to either:

(I) Get implicitly initialized at the time of declaration. This will require user-defined default constructor. We understand that this is not possible in D. We also understand that this is a small sacrifice we make to enable a lot of meta-programming at compile time.

OR

(II) Allow postblit to take care of uninitialized lazy Fifo instances. For this only we are asking for the ability to access and modify the source Fifo instance as well as the copied instance in the postblit.

Thanks for bearing with my long rant. As far as I can make out neither DIP49 nor DIP53 directly addresses this issue. Let me know if I have overlooked some aspects of these DIPs. I and my colleague at work are ready to spend time on creating a DIP for my use case. I believe it will also be useful for a couple of other usecases as well.

Regards
- Ritu
December 30, 2013
Ritu:

> First of all there is no way in D (at least I am not aware) to disallow the default constructor (the init value must exist).

Do you mean something like this?


struct Foo {
    @disable this();
    this(int) {}
}
void main() {
    // Foo f1; // Error
    auto f2 = Foo(1);
}


Or do you mean this?

struct Bar {}
void main() {
    Bar b = void;
}


Bye,
bearophile
December 30, 2013
On Monday, 30 December 2013 at 16:18:22 UTC, Maxim Fomin wrote:
> On Sunday, 29 December 2013 at 19:26:09 UTC, monarch_dodra wrote:
>> Nope. What you are asking for is basically a default constructor, which D does not provide. Workarounds include the "static opCall" pattern, as well as the "function builder" pattern (eg: "MyStruct myStruct(Args args)")
>
> Actually it does provide, but does not allow to override it. When you define postblit, dmd generates default constructor like this:
>
> struct S
> {
>    int data[];
>    this(this) { data = data.dup; }
>    void __cpctor(const ref S s) const
>    {
>       this = s;
>       s.__postblit();
>    }
> }
>
> The only way to override it is currently is to make your function, drop original symbol from binary file and link the program.
> I think it could work like opAssign - provide default version but allow to place yours. In such case it would be possible to alter original struct object but it would lead to conflict if original object is const or immutable qualified.

Hum... The original question was "Any possibility of *preblit* kind functionality?". I meant "default constructor" in the C++ sense: A constructor that gets called with no arguments. That does not exist in D.

I did not know dmd generated an actual symbol for CC though. Interesting to know.
December 31, 2013
> Do you mean something like this?
>
>
> struct Foo {
>     @disable this();
>     this(int) {}
> }
> void main() {
>     // Foo f1; // Error
>     auto f2 = Foo(1);
> }


Thanks Beorophile. I somehow overlooked @disable for default constructor. But I hope that you get the larger picture. Imagine an end-user wanting to create an array of Fifos. In a DSL, it does not come out nice if you ask him to initialize all the Fifo elements.

My rant boils down to this. To have the ability to create "native like" data in any DSL embedded in D, we need one of the following three:

1. The ability to have a user-defined default constructor for structs. I believe this is not possible since it does not go well with D's metaprogramming.
2. Some sort of preblit. That also is not possible since it boils down to having a default constructor.
3. Allowing postblit to access and modify both the source and target struct instances in a postblit.

The last two of these options rely on lazy initialization which works fine except for the situation wherein you pass an uninitialized struct instance to a function. Also I believe "lazy initialization" is a pattern used often in D containers. And the postblit enhancement I am asking for helps take care of the unexpected behavior that shows up with those container classes too.

Regards
- Ritu
December 31, 2013
On Monday, 30 December 2013 at 16:10:35 UTC, Andrei Alexandrescu wrote:
> On 12/30/13 3:34 AM, Ritu wrote:
>>
>>> But then the source object may not be mutable. I am not a compiler
>>> expert, but could a special case be made in D compiler for the cases
>>> where the source struct instance is mutable and is made available to
>>> ease such lazy initialization?
>>
>>
>> I am suggesting a DIP here.
>
> Did you take a look at http://wiki.dlang.org/DIP49 and http://wiki.dlang.org/DIP53?
>
> Andrei

I have done that now. These DIPs though related, do not make the original object available for modification. But since DIP49 allows qualification of postblit, I believe what I am asking for becomes very much possible as an extension. We just need to provide another overloaded "mutable" postblit that would provide access to the "original" as well as "copied" struct instances.

I believe this will go a long way in fixing the behavior of some containers like the appender too. In general it will make "lazy initialization" much more usable in D.

Regards
- Ritu
December 31, 2013
On 12/30/2013 7:53 AM, Andrei Alexandrescu wrote:
> Walter is reconsidering that.

<cough><cough>