Jump to page: 1 2
Thread overview
Make sure lifetime of helper structs is less than owning struct
Nov 15, 2021
WebFreak001
Nov 15, 2021
H. S. Teoh
Nov 15, 2021
Sebastiaan Koppe
Nov 15, 2021
WebFreak001
Nov 15, 2021
Ali Çehreli
Nov 15, 2021
Imperatorn
Nov 15, 2021
Ali Çehreli
Nov 16, 2021
Sebastiaan Koppe
Nov 16, 2021
Ali Çehreli
Nov 15, 2021
Imperatorn
November 15, 2021

I have an API with some struct like a file reader. I want to add byChunks-like functionality to it, so I'm trying to implement it with a helper struct that implements opApply. I have disabled copying the file reader struct because it cleans up the resources once it goes out of scope, however now I need to temporarily save the resources in the helper struct to be able to read from it.

How can I make sure that the foreach helper struct (and with that the copies of the resources) cannot be used once the owning struct goes out of scope?

ByChunk helper;
{
    auto file = FileReader(x);
    helper = file.byChunk;
}
helper.popFront; // crash - I want the compiler to disallow this

is this currently possible or maybe possible with DIP1000?

November 15, 2021

On 11/15/21 10:56 AM, WebFreak001 wrote:

>

I have an API with some struct like a file reader. I want to add byChunks-like functionality to it, so I'm trying to implement it with a helper struct that implements opApply. I have disabled copying the file reader struct because it cleans up the resources once it goes out of scope, however now I need to temporarily save the resources in the helper struct to be able to read from it.

How can I make sure that the foreach helper struct (and with that the copies of the resources) cannot be used once the owning struct goes out of scope?

ByChunk helper;
{
     auto file = FileReader(x);
     helper = file.byChunk;
}
helper.popFront; // crash - I want the compiler to disallow this

is this currently possible or maybe possible with DIP1000?

Or maybe just use reference counting to avoid the problem altogether. That's what iopipe/std.io does.

-Steve

November 15, 2021
On Mon, Nov 15, 2021 at 03:56:57PM +0000, WebFreak001 via Digitalmars-d-learn wrote:
> I have an API with some struct like a file reader. I want to add byChunks-like functionality to it, so I'm trying to implement it with a helper struct that implements opApply. I have disabled copying the file reader struct because it cleans up the resources once it goes out of scope, however now I need to temporarily save the resources in the helper struct to be able to read from it.
> 
> How can I make sure that the foreach helper struct (and with that the copies of the resources) cannot be used once the owning struct goes out of scope?
> 
> ```d
> ByChunk helper;
> {
>     auto file = FileReader(x);
>     helper = file.byChunk;
> }
> helper.popFront; // crash - I want the compiler to disallow this
> ```
> 
> is this currently possible or maybe possible with DIP1000?

What about make ByChunk do the construction of the File in its ctor instead?  The problem with constructing it separately is that you can't tie the two lifetimes together.  But if you create the File while initializing the object, you ensure that the two lifetimes are tied together, and with @disable this() you can make sure that ByChunk is not constructible unless the code that opens the File also runs.


T

-- 
Computers shouldn't beep through the keyhole.
November 15, 2021

On Monday, 15 November 2021 at 15:56:57 UTC, WebFreak001 wrote:

>

is this currently possible or maybe possible with DIP1000?

Yes it is. But besides -dip1000 and @safe, it requires the use of a pointer:

@safe:

struct ByChunk {
    FileReader* r;
    void popFront() {}
}

struct FileReader {
    ByChunk byChunk() return scope {
        return ByChunk(&this);
    }
}

void main() {
	ByChunk helper;
	{
   		auto file = FileReader();
    	helper = file.byChunk;  // Error: address of variable `file` assigned to `helper` with longer lifetime
	}
	helper.popFront;
}
November 15, 2021

On Monday, 15 November 2021 at 19:24:56 UTC, Sebastiaan Koppe wrote:

>

On Monday, 15 November 2021 at 15:56:57 UTC, WebFreak001 wrote:

>

is this currently possible or maybe possible with DIP1000?

Yes it is. But besides -dip1000 and @safe, it requires the use of a pointer:

@safe:

struct ByChunk {
    FileReader* r;
    void popFront() {}
}

struct FileReader {
    ByChunk byChunk() return scope {
        return ByChunk(&this);
    }
}

void main() {
	ByChunk helper;
	{
   		auto file = FileReader();
    	helper = file.byChunk;  // Error: address of variable `file` assigned to `helper` with longer lifetime
	}
	helper.popFront;
}

awesome, such a simple solution! Also saves me the pain of copying the struct data and avoiding copy constructor and stuff by using a pointer.

November 15, 2021

On Monday, 15 November 2021 at 19:24:56 UTC, Sebastiaan Koppe wrote:

>

On Monday, 15 November 2021 at 15:56:57 UTC, WebFreak001 wrote:

>

is this currently possible or maybe possible with DIP1000?

Yes it is. But besides -dip1000 and @safe, it requires the use of a pointer:

@safe:

struct ByChunk {
    FileReader* r;
    void popFront() {}
}

struct FileReader {
    ByChunk byChunk() return scope {
        return ByChunk(&this);
    }
}

void main() {
	ByChunk helper;
	{
   		auto file = FileReader();
    	helper = file.byChunk;  // Error: address of variable `file` assigned to `helper` with longer lifetime
	}
	helper.popFront;
}

Maybe a candidate for the "d idioms" page

November 15, 2021
On 11/15/21 1:58 PM, WebFreak001 wrote:
> On Monday, 15 November 2021 at 19:24:56 UTC, Sebastiaan Koppe wrote:
>> On Monday, 15 November 2021 at 15:56:57 UTC, WebFreak001 wrote:
>>> is this currently possible or maybe possible with DIP1000?
>>
>> Yes it is. But besides `-dip1000` and `@safe`, it requires the use of
>> a pointer:
>>
>> ```D
>> @safe:
>>
>> struct ByChunk {
>>     FileReader* r;
>>     void popFront() {}
>> }
>>
>> struct FileReader {
>>     ByChunk byChunk() return scope {
>>         return ByChunk(&this);
>>     }
>> }
>>
>> void main() {
>>     ByChunk helper;
>>     {
>>            auto file = FileReader();
>>         helper = file.byChunk;  // Error: address of variable `file`
>> assigned to `helper` with longer lifetime
>>     }
>>     helper.popFront;
>> }
>> ```
>
> awesome, such a simple solution! Also saves me the pain of copying the
> struct data and avoiding copy constructor and stuff by using a pointer.
I don't see how it solves the problem. Sebastiaan Koppe might have intended to allocate the object dynamically with 'new' as well?

import std.stdio;

@safe:

struct ByChunk {
  FileReader* r;

  ~this() {
    writeln(__FUNCTION__);
  }

  void popFront() {
    writeln("popFront on ", r);
  }
}

struct FileReader {
  ~this() {
    writeln(__FUNCTION__, " on ", &this);
  }

  ByChunk byChunk() return scope {
    return ByChunk(&this);
  }
}

void main() {
  ByChunk helper;
  {
    auto file = new FileReader();  // <-- NOTE new
    helper = file.byChunk;
  }
  writeln("back in main");
  helper.popFront;
}

This is the current output:

deneme.ByChunk.~this
back in main
popFront on 7F12B377E000
deneme.ByChunk.~this
deneme.FileReader.~this on 7F12B377E000

But without that 'new', FileReader is destroyed before popFront:

deneme.ByChunk.~this
deneme.FileReader.~this on 7FFD8231D4B8   <-- BAD
back in main
popFront on 7FFD8231D4B8
deneme.ByChunk.~this

I think I am misunderstanding something here. :)

Ali

November 15, 2021
On Monday, 15 November 2021 at 22:27:24 UTC, Ali Çehreli wrote:
> On 11/15/21 1:58 PM, WebFreak001 wrote:
> > [...]
> wrote:
> >> [...]
> wrote:
> >> [...]
> the use of
> >>         [...]
> variable `file`
> > [...]
> copying the
> > [...]
> a pointer.
> I don't see how it solves the problem. Sebastiaan Koppe might have intended to allocate the object dynamically with 'new' as well?
>
> [...]

Are you compiling with preview=dip1000?
November 15, 2021
On 11/15/21 2:33 PM, Imperatorn wrote:
> On Monday, 15 November 2021 at 22:27:24 UTC, Ali Çehreli wrote:
>> On 11/15/21 1:58 PM, WebFreak001 wrote:
>> > [...]
>> wrote:
>> >> [...]
>> wrote:
>> >> [...]
>> the use of
>> >>         [...]
>> variable `file`
>> > [...]
>> copying the
>> > [...]
>> a pointer.
>> I don't see how it solves the problem. Sebastiaan Koppe might have intended to allocate the object dynamically with 'new' as well?
>>
>> [...]
> 
> Are you compiling with preview=dip1000?

Trying with it produces an error when 'new' is not used:

Error: reference to local variable `file` assigned to non-scope parameter `p` calling deneme.ByChunk.opAssign

So, I either misunderstand or understand very well :) that a different way of lifetime management (like adding 'new') is needed there.

Ali

November 16, 2021
On Monday, 15 November 2021 at 22:49:12 UTC, Ali Çehreli wrote:
> Trying with it produces an error when 'new' is not used:
>
> Error: reference to local variable `file` assigned to non-scope parameter `p` calling deneme.ByChunk.opAssign

The error is what the OP wanted, so that is expected.

Although, he did ask for it to be on the next line, but this is better since it points exactly to the line where he was escaping a reference to the scoped object.

> I don't see how it solves the problem. Sebastiaan Koppe might have intended to allocate the object dynamically with 'new' as well?

No I didn't. Anything created with new has automatic lifetime. Here the OP wanted to (have the compiler) destroy the FileReader when it left the scope, while disallowing any use after free.
« First   ‹ Prev
1 2