Re: D RAII with postblit disabled

2018-03-28 Thread Norm via Digitalmars-d-learn

On Thursday, 29 March 2018 at 04:16:55 UTC, Adam D. Ruppe wrote:

On Thursday, 29 March 2018 at 04:12:38 UTC, Norm wrote:
Is there a way to do this in D, or does it require special 
"create" functions for every struct that has a RAII-like 
struct as a member?


You'll have to do it all the way up (unless you can use a 
constructor with an argument and call that instead)


OK, thanks.


Re: D RAII with postblit disabled

2018-03-28 Thread Adam D. Ruppe via Digitalmars-d-learn

On Thursday, 29 March 2018 at 04:12:38 UTC, Norm wrote:
Is there a way to do this in D, or does it require special 
"create" functions for every struct that has a RAII-like struct 
as a member?


You'll have to do it all the way up (unless you can use a 
constructor with an argument and call that instead)


Re: D RAII with postblit disabled

2018-03-28 Thread Norm via Digitalmars-d-learn

On Tuesday, 27 March 2018 at 02:43:15 UTC, Adam D. Ruppe wrote:

On Tuesday, 27 March 2018 at 02:35:23 UTC, Norm wrote:

What's the best way to do this in D?


I'd also add `@disable this();` and then a `static O make() { 
return O(theAllocator.make!int(99)); }`


than you construct it with that static make function.


OK, that got me over the first hurdle but I still cannot use RAII 
with struct member vars. E.g.


---
struct Resource {
  this() {allocate_something();}
  ~this() {release_something();}
}

struct S {
  Resource resource;
}

---

Is there a way to do this in D, or does it require special 
"create" functions for every struct that has a RAII-like struct 
as a member?



Thanks,
Norm


Re: D RAII with postblit disabled

2018-03-26 Thread Norm via Digitalmars-d-learn

On Tuesday, 27 March 2018 at 02:43:15 UTC, Adam D. Ruppe wrote:

On Tuesday, 27 March 2018 at 02:35:23 UTC, Norm wrote:

What's the best way to do this in D?


I'd also add `@disable this();` and then a `static O make() { 
return O(theAllocator.make!int(99)); }`


than you construct it with that static make function.


Perfect, thanks.


Re: D RAII with postblit disabled

2018-03-26 Thread Adam D. Ruppe via Digitalmars-d-learn

On Tuesday, 27 March 2018 at 02:35:23 UTC, Norm wrote:

What's the best way to do this in D?


I'd also add `@disable this();` and then a `static O make() { 
return O(theAllocator.make!int(99)); }`


than you construct it with that static make function.


D RAII with postblit disabled

2018-03-26 Thread Norm via Digitalmars-d-learn

Hi All,

What's the best way to do this in D?

E.g.

---
struct O
{
  int* value;
  @disable this(this);
/+
  this()
  {
this.value = theAllocator.make!int(99);
  }
+/
  ~this()
  {
theAllocator.dispose(this.value);
  }
}

O obj = O(); // Ideally this would be allocated but it simply run 
O.init

---

Thanks
Norm


Re: D structs weak identity and RAII

2017-06-19 Thread Boris-Barboris via Digitalmars-d-learn

On Monday, 19 June 2017 at 06:34:49 UTC, Ali Çehreli wrote:
It's unreliable because structs are value types in D, which 
means that they can be moved around freely. This is why 
self-referencing structs are illegal in D.


I guess it's more like the spec states, that they can be moved 
vithout notice. Value type semantics themselves do not mean 
spontaneous uncontrolled mobility.


I can't claim expertise but here is a quick and dirty proof of 
concept that Vittorio Romeo and I had played with a few weeks 
ago:


...

shared byte b; // to prevent compiler optimizations

struct UniquePtr {
void * p;

this(void * p) {
this.p = p;
import core.atomic;
core.atomic.atomicOp!"+="(b, 1);
}


Very interesting hack, thank you.

Note how post-blit is disabled there. In addition to a 
moveFrom(), that's exactly what Atila Neves had to do in this 
automem library as well:


  https://github.com/atilaneves/automem


Nice, thanks.




Re: D structs weak identity and RAII

2017-06-18 Thread Ali Çehreli via Digitalmars-d-learn

On 06/18/2017 06:22 PM, Boris-Barboris wrote:

> https://dpaste.dzfl.pl/d77c72198095
>
> 1). line 47 and 76 together mean, that there is basically no reliable
> way to write uniqueptr method wich returns WeakPointer, registered by
> the correct pointer in it's constructor. Or is there? Is usage of &this
> in constructor (or in struct methods in general) fundamentally
> unreliable in D?

It's unreliable because structs are value types in D, which means that 
they can be moved around freely. This is why self-referencing structs 
are illegal in D.


> 2). postblit was never called when returning struct from function.

Rvalues are automatically moved and there is also RVO.

> 3). Is there a way to reliably encapsulate all assignments?

I think so.

> 4). Any suggested workarounds? I never tried it in C++, but, IIRC,
> struct life cycle is much more consistent there ang gives the strict
> control I desire.

Yes, C++ has a very well defined object lifecycle.

> 5). If all this is a design choice, what is the reason behind it?

Some are design choices and some are bugs. For example, a fundamental 
bug has just been fixed: When a constructor threw, the destructors of 
already-constructed members were not being called. I think the fix is in 
git head but not released yet.


I can't claim expertise but here is a quick and dirty proof of concept 
that Vittorio Romeo and I had played with a few weeks ago:


import core.stdc.stdio;
import core.stdc.stdlib;
import std.algorithm;
import std.stdio;

shared byte b; // to prevent compiler optimizations

struct UniquePtr {
void * p;

this(void * p) {
this.p = p;
import core.atomic;
core.atomic.atomicOp!"+="(b, 1);
}

~this() {
free(p);
}

@disable this(this);

UniquePtr move() {
void * old = p;
p = null;
return UniquePtr(old);
}
}

void consumer(UniquePtr u) {
}

UniquePtr producer(int i) {
auto u = UniquePtr(malloc(42));
return i ? UniquePtr(malloc(56)) : u.move();
}

void main() {
consumer(UniquePtr(malloc(2)));

auto u = UniquePtr(malloc(5));
consumer(u.move());

auto u2 = producer(43);
}

Note how post-blit is disabled there. In addition to a moveFrom(), 
that's exactly what Atila Neves had to do in this automem library as well:


  https://github.com/atilaneves/automem

Ali



D structs weak identity and RAII

2017-06-18 Thread Boris-Barboris via Digitalmars-d-learn

Hello, I was trying to write some templated unique pointers.
Idea was simple: struct UniquePointer that handles underlying 
pointer in RAII-style and WeakPointer struct that is spawned by 
UniquePointer. Weak pointer is handled differently in my 
collections, wich subscribe to the event of UniquePointer 
destruction, so that there are no dangling references left all 
over the heap (I use Mallocator). Collection's insertFront\Back 
methods register callbacks in Weak pointer itself, and all 
existing weak pointers are registered in Unique pointer.


That, unfortunately, failed at the very beginning. Then I wrote a 
unit test to investigate:


https://dpaste.dzfl.pl/d77c72198095

1). line 47 and 76 together mean, that there is basically no 
reliable way to write uniqueptr method wich returns WeakPointer, 
registered by the correct pointer in it's constructor. Or is 
there? Is usage of &this in constructor (or in struct methods in 
general) fundamentally unreliable in D?
2). postblit was never called when returning struct from 
function. I noticed it was called once on line 91, if i removed 
opAssign with ref argument. What are the rules? Why is it always 
called when passing struct to function and creating local copy of 
the parameter (lines 113, 127, 139), and why is opAssign not 
called?
3). Is there a way to reliably encapsulate all assignments? Looks 
like complete mess will happen should I apply some std.algorithm 
functions on array of structs with overloaded operators.
4). Any suggested workarounds? I never tried it in C++, but, 
IIRC, struct life cycle is much more consistent there ang gives 
the strict control I desire.

5). If all this is a design choice, what is the reason behind it?


OT: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 21:46:45 UTC, Stanislav Blinov wrote:

On Saturday, 3 June 2017 at 21:39:54 UTC, Moritz Maxeiner wrote:
It's always true, because I explicitly wrote *might*, not 
*will*, to indicate that it depends on your use case. Your 
example is a common use case where you can't skip the check.


Programmers and their tight-binding logic...

- Honey, please buy a loaf of bread. If there are eggs, buy a 
dozen.

...
- Hello, do you have eggs?
- Yes.
- Dozen loaves of bread, please.

;)


That usually happens when two sides interpret an ambiguous 
statement ;)


Re: RAII pointers

2017-06-03 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 3 June 2017 at 21:39:54 UTC, Moritz Maxeiner wrote:
On Saturday, 3 June 2017 at 21:16:08 UTC, Stanislav Blinov 
wrote:
On Saturday, 3 June 2017 at 20:53:05 UTC, Moritz Maxeiner 
wrote:


Quite, but if you backtrack to my initial statement, it was 
about ptr not being/becoming null (implicitly) in the first 
place, which *might* allow you to skip the check (if you 
don't set it to null via external means, such as memcpy, 
move, etc).


It's only true as long as you have full control of the source.
Once you're using libraries and generic code, it's possible 
that it's out of your hands:


It's always true, because I explicitly wrote *might*, not 
*will*, to indicate that it depends on your use case. Your 
example is a common use case where you can't skip the check.


Programmers and their tight-binding logic...

- Honey, please buy a loaf of bread. If there are eggs, buy a 
dozen.

...
- Hello, do you have eggs?
- Yes.
- Dozen loaves of bread, please.

;)


Re: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 21:16:08 UTC, Stanislav Blinov wrote:

On Saturday, 3 June 2017 at 20:53:05 UTC, Moritz Maxeiner wrote:


Quite, but if you backtrack to my initial statement, it was 
about ptr not being/becoming null (implicitly) in the first 
place, which *might* allow you to skip the check (if you don't 
set it to null via external means, such as memcpy, move, etc).


It's only true as long as you have full control of the source.
Once you're using libraries and generic code, it's possible 
that it's out of your hands:


It's always true, because I explicitly wrote *might*, not *will*, 
to indicate that it depends on your use case. Your example is a 
common use case where you can't skip the check.


Re: RAII pointers

2017-06-03 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 3 June 2017 at 20:53:05 UTC, Moritz Maxeiner wrote:
On Saturday, 3 June 2017 at 20:25:22 UTC, Stanislav Blinov 
wrote:
On Saturday, 3 June 2017 at 20:13:30 UTC, Moritz Maxeiner 
wrote:


Calling std.algorithm.move is explicit programmer intent, I 
consider that about as accidental as calling memcpy with a 
source full of zeroes.
In any case, having that check in the destructor is fairly 
cheap, so better safe than sorry (and include it).


Yes, it's explicit. Destructor call is still implicit though, 
and it better not be performing null dereference or something 
equally nasty :)


Quite, but if you backtrack to my initial statement, it was 
about ptr not being/becoming null (implicitly) in the first 
place, which *might* allow you to skip the check (if you don't 
set it to null via external means, such as memcpy, move, etc).


It's only true as long as you have full control of the source. 
Once you're using libraries and generic code, it's possible that 
it's out of your hands:


import core.stdc.stdio;
import std.exception;

// external library
struct RingBuffer(T,size_t size) {
T[size] values = T.init; // the culprit
// interface snipped...
}

// own code
struct FileWrapper {
FILE* file;

@disable this();
@disable this(this);

this(FILE* file) {
enforce(file);
this.file = file;
}

~this() {
fclose(file);
}
}

void main() {
// whoops, segfault
RingBuffer!(FileWrapper,8) container;
}



Re: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 20:25:22 UTC, Stanislav Blinov wrote:

On Saturday, 3 June 2017 at 20:13:30 UTC, Moritz Maxeiner wrote:

Calling std.algorithm.move is explicit programmer intent, I 
consider that about as accidental as calling memcpy with a 
source full of zeroes.
In any case, having that check in the destructor is fairly 
cheap, so better safe than sorry (and include it).


Yes, it's explicit. Destructor call is still implicit though, 
and it better not be performing null dereference or something 
equally nasty :)


Quite, but if you backtrack to my initial statement, it was about 
ptr not being/becoming null (implicitly) in the first place, 
which *might* allow you to skip the check (if you don't set it to 
null via external means, such as memcpy, move, etc).


Re: RAII pointers

2017-06-03 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 3 June 2017 at 20:13:30 UTC, Moritz Maxeiner wrote:

Calling std.algorithm.move is explicit programmer intent, I 
consider that about as accidental as calling memcpy with a 
source full of zeroes.
In any case, having that check in the destructor is fairly 
cheap, so better safe than sorry (and include it).


Yes, it's explicit. Destructor call is still implicit though, and 
it better not be performing null dereference or something equally 
nasty :)


Re: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 19:55:30 UTC, ag0aep6g wrote:

On 06/03/2017 09:37 PM, Moritz Maxeiner wrote:
Of course, but AFAIK you'd need to explicitly assign it to an 
object, so `ptr` won't null by accident, but only by explicit 
programmer intent (same as overwriting the memory the object 
lives in via things like `memcpy`); and you can always screw 
things intentionally (you could also assign some invalid value 
to the pointer via `memcpy`).


I'd say `.init` can easily happen accidentally. Especially when 
`@disable this(this);` is involved.


When you can't copy, you may have to move sometimes. But 
std.algorithm.move overwrites the old location with `.init`, 
assuming that `.init` can safely be destroyed.


Calling std.algorithm.move is explicit programmer intent, I 
consider that about as accidental as calling memcpy with a source 
full of zeroes.
In any case, having that check in the destructor is fairly cheap, 
so better safe than sorry (and include it).


Re: RAII pointers

2017-06-03 Thread Stanislav Blinov via Digitalmars-d-learn

On Saturday, 3 June 2017 at 19:55:30 UTC, ag0aep6g wrote:

On 06/03/2017 09:37 PM, Moritz Maxeiner wrote:
Of course, but AFAIK you'd need to explicitly assign it to an 
object, so `ptr` won't null by accident, but only by explicit 
programmer intent (same as overwriting the memory the object 
lives in via things like `memcpy`); and you can always screw 
things intentionally (you could also assign some invalid value 
to the pointer via `memcpy`).


I'd say `.init` can easily happen accidentally. Especially when 
`@disable this(this);` is involved.


When you can't copy, you may have to move sometimes. But 
std.algorithm.move overwrites the old location with `.init`, 
assuming that `.init` can safely be destroyed.



struct S
{
void* ptr;
@disable this(this);
~this() { assert(ptr !is null); /* fails */ }
}

void f(S s) {}

void main()
{
auto a = S(new int);
import std.algorithm: move;
f(move(a)); /* overwrites `a` with `S.init` */
}



Yep, that's exactly why I added the null check in the example. If 
the struct has a postblit or a destructor, `move` will be 
destructive, and will overwrite the source with .init. Sometimes 
it doesn't matter (i.e. free() is allowed to take a null 
pointer), but in general, for things like smart pointers where 
you'd do arbitrary access in destructor, it's a good habit to 
check for .init values first, in case the object has been moved.


Re: RAII pointers

2017-06-03 Thread ag0aep6g via Digitalmars-d-learn

On 06/03/2017 09:37 PM, Moritz Maxeiner wrote:
Of course, but AFAIK you'd need to explicitly assign it to an object, so 
`ptr` won't null by accident, but only by explicit programmer intent 
(same as overwriting the memory the object lives in via things like 
`memcpy`); and you can always screw things intentionally (you could also 
assign some invalid value to the pointer via `memcpy`).


I'd say `.init` can easily happen accidentally. Especially when 
`@disable this(this);` is involved.


When you can't copy, you may have to move sometimes. But 
std.algorithm.move overwrites the old location with `.init`, assuming 
that `.init` can safely be destroyed.



struct S
{
void* ptr;
@disable this(this);
~this() { assert(ptr !is null); /* fails */ }
}

void f(S s) {}

void main()
{
auto a = S(new int);
import std.algorithm: move;
f(move(a)); /* overwrites `a` with `S.init` */
}



Re: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 19:21:58 UTC, ag0aep6g wrote:

On 06/03/2017 09:06 PM, Moritz Maxeiner wrote:
- null check in destructor: That's just because I forgot to 
add it. If you add `@disable(this)` (disable the default 
constructor), all elaborate constructors ensure it is not 
null, and no members can set it to null, you might be able to 
skip the check, but I may have missed some corner cases, so 
better be safe.


`.init` is the corner case. `.init` is always there, even with 
`@disable this();`.


Of course, but AFAIK you'd need to explicitly assign it to an 
object, so `ptr` won't null by accident, but only by explicit 
programmer intent (same as overwriting the memory the object 
lives in via things like `memcpy`); and you can always screw 
things intentionally (you could also assign some invalid value to 
the pointer via `memcpy`).

Are there any accidental corner cases?


Re: RAII pointers

2017-06-03 Thread ag0aep6g via Digitalmars-d-learn

On 06/03/2017 09:06 PM, Moritz Maxeiner wrote:
- null check in destructor: That's just because I forgot to add it. If 
you add `@disable(this)` (disable the default constructor), all 
elaborate constructors ensure it is not null, and no members can set it 
to null, you might be able to skip the check, but I may have missed some 
corner cases, so better be safe.


`.init` is the corner case. `.init` is always there, even with `@disable 
this();`.


Re: RAII pointers

2017-06-03 Thread Moritz Maxeiner via Digitalmars-d-learn

On Saturday, 3 June 2017 at 17:40:32 UTC, Russel Winder wrote:

Would one be considered more idiomatic D, or is it a
question of different circumstances different approaches. The
differences are mainly in construction I believe.



Well, the differences I spot are:
- null check in destructor: That's just because I forgot to add 
it. If you add `@disable(this)` (disable the default 
constructor), all elaborate constructors ensure it is not null, 
and no members can set it to null, you might be able to skip the 
check, but I may have missed some corner cases, so better be safe.

- factory functions (Stanislav) vs. elaborate constructors (me):
  + If you don't need to be able to construct the object without 
arguments, it's a stylistic choice and I consider the elaborate 
constructors to be more idiomatic.
  + otherwise (i.e. you need to be able to construct the object 
without arguments), you need the factory functions, because 
elaborate constructors for structs cannot have zero arguments, as 
that would clash with the default constructor that must be 
computable at compile time (for the struct's `.init` value)
- inout: You can use that in what I wrote, as well; that's just a 
shorthand way to write several functions that do the same thing: 
one for `const T`, one for `immutable T`, and one for `T`




Re: RAII pointers

2017-06-03 Thread Russel Winder via Digitalmars-d-learn
Thanks to Moritz and Stanislav for their examples, most useful. There
are similarities (which I have just taken :-) but also some
differences. Would one be considered more idiomatic D, or is it a
question of different circumstances different approaches. The
differences are mainly in construction I believe.
 

On Tue, 2017-05-30 at 00:31 +, Moritz Maxeiner via Digitalmars-d-
learn wrote:
> […]
> 
> struct FrontendParameters_Ptr {
> private:
>  dvb_v5_fe_parms* ptr;
> public:
>  @disable this(this);
>  this(ref const FrontendId fei, const uint verbose = 0, const 
> uint legacy = 0) { ... }
>  ~this() { dvb_fe_close(ptr); }
>  auto c_ptr() const { return ptr; }
>  alias c_ptr this;
> }
> ---

On Tue, 2017-05-30 at 00:32 +, Stanislav Blinov via Digitalmars-d-
learn wrote:
[…]
> 
> struct FrontendParametersPtr
> {
>  // No constructors, initialization with parameters
>  // is done via the frontendParametersPtr function
>  @disable this(this);
> 
>  ~this()
>  {
>  // null check is often useful to detect e.g.
>  // if this object has been `move`d
>  if (_ptr) dvb_fe_close(_ptr);
>  }
> 
>  // with DIP1000, could also return `scope`
>  inout(dvb_v5_fe_parms)* ptr() inout { return _ptr; }
>  alias ptr this;
> package:
> 
>  void construct(/*your args here*/) { /*...*/ }
> 
> private:
>  dvb_v5_fe_parms* _ptr;
> }
> 
> /// Replaces constructor, i.e. can be called with no arguments for
> /// replacing "default" construction of C++
> auto frontendParametersPtr(Args...)(auto ref Args args)
> {
>  import std.functional : forward;
>  FrontendParametersPtr result = void;
>  result.construct(forward!args);
>  return result; // moves result, no copy is made
> }
> 
[…]
-- 
Russel.
=
Dr Russel Winder  t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder

signature.asc
Description: This is a digitally signed message part


Re: RAII pointers

2017-05-29 Thread Stanislav Blinov via Digitalmars-d-learn

On Monday, 29 May 2017 at 23:39:17 UTC, Russel Winder wrote:
C++ allows one to create types that are pointer types but wrap 
a primitive pointer to give RAII handling of resources. For 
example:



class Dvb::FrontendParameters_Ptr {
private:
dvb_v5_fe_parms * ptr;
public:
	FrontendParameters_Ptr(FrontendId const & fei, 
unsigned int const verbose = 0, unsigned int const legacy = 0);
	FrontendParameters_Ptr(FrontendParameters_Ptr const &) 
= delete;
	FrontendParameters_Ptr & 
operator=(FrontendParameters_Ptr const &) = delete;

~FrontendParameters_Ptr() {dvb_fe_close(ptr); }
dvb_v5_fe_parms * c_ptr() const { return ptr; }
dvb_v5_fe_parms * operator->() const { return ptr; }
};


Has anyone any experience of doing the analogous thing 
idiomatically in D.


I just re-realised I manually constructed a C++ abstraction 
layer around some of libdvbv5, so I am going to do the same for 
D. However whilst I (sort of) understand doing the wrapping 
with C++, I am not sure I have seen anyone wrapping C pointers 
with RAII in D.


I've found this pattern works rather well:

module frontendparametersptr;

struct FrontendParametersPtr
{
// No constructors, initialization with parameters
// is done via the frontendParametersPtr function
@disable this(this);

~this()
{
// null check is often useful to detect e.g.
// if this object has been `move`d
if (_ptr) dvb_fe_close(_ptr);
}

// with DIP1000, could also return `scope`
inout(dvb_v5_fe_parms)* ptr() inout { return _ptr; }
alias ptr this;
package:

void construct(/*your args here*/) { /*...*/ }

private:
dvb_v5_fe_parms* _ptr;
}

/// Replaces constructor, i.e. can be called with no arguments for
/// replacing "default" construction of C++
auto frontendParametersPtr(Args...)(auto ref Args args)
{
import std.functional : forward;
FrontendParametersPtr result = void;
result.construct(forward!args);
return result; // moves result, no copy is made
}

///-

module app;

import frontendparametersptr;

void main()
{
auto ptr = frontendParametersPtr(/* your args here */);
}


The main idea is that construction is handled by the `construct` 
function (which could be overloaded), instead of `this(...)` 
constructors: this way client code would either get 
default-initialized (.init) pointers, or those constructed with 
appropriate arguments (even with no arguments, if such is needed).

Disabling copying is obvious.
The rest depends on taste and purpose.


Re: RAII pointers

2017-05-29 Thread Moritz Maxeiner via Digitalmars-d-learn

On Monday, 29 May 2017 at 23:39:17 UTC, Russel Winder wrote:
C++ allows one to create types that are pointer types but wrap 
a primitive pointer to give RAII handling of resources. For 
example:



class Dvb::FrontendParameters_Ptr {
private:
dvb_v5_fe_parms * ptr;
public:
	FrontendParameters_Ptr(FrontendId const & fei, 
unsigned int const verbose = 0, unsigned int const legacy = 0);
	FrontendParameters_Ptr(FrontendParameters_Ptr const &) 
= delete;
	FrontendParameters_Ptr & 
operator=(FrontendParameters_Ptr const &) = delete;

~FrontendParameters_Ptr() {dvb_fe_close(ptr); }
dvb_v5_fe_parms * c_ptr() const { return ptr; }
dvb_v5_fe_parms * operator->() const { return ptr; }
};


Has anyone any experience of doing the analogous thing 
idiomatically in D.


Yes, I generally use structs with `@disable this(this)` and 
std.algorithm.mutation.move for this.


Something like (untested, but general approach):
---
module dvb;

struct FrontendParameters_Ptr {
private:
dvb_v5_fe_parms* ptr;
public:
@disable this(this);
this(ref const FrontendId fei, const uint verbose = 0, const 
uint legacy = 0) { ... }

~this() { dvb_fe_close(ptr); }
auto c_ptr() const { return ptr; }
alias c_ptr this;
}
---

Be aware that the above deliberately prohibits normal struct copy 
construction, so there is always only a single struct object. 
"Borrow" it via ref / ref const or std.algorithm.mutation.move it 
to change the owner. Or wrap this struct itself in a lifetime 
management struct (such as std.typecons.RefCounted) if you need 
multiple owners.


Re: RAII pointers

2017-05-29 Thread Nicholas Wilson via Digitalmars-d-learn

On Monday, 29 May 2017 at 23:39:17 UTC, Russel Winder wrote:
C++ allows one to create types that are pointer types but wrap 
a primitive pointer to give RAII handling of resources. For 
example:


[...]


std.stdio.File does basically the same thing with C's FILE*


RAII pointers

2017-05-29 Thread Russel Winder via Digitalmars-d-learn
C++ allows one to create types that are pointer types but wrap a
primitive pointer to give RAII handling of resources. For example:


class Dvb::FrontendParameters_Ptr {
private:
dvb_v5_fe_parms * ptr;
public:
FrontendParameters_Ptr(FrontendId const & fei, unsigned int const 
verbose = 0, unsigned int const legacy = 0);
FrontendParameters_Ptr(FrontendParameters_Ptr const &) = delete;
FrontendParameters_Ptr & operator=(FrontendParameters_Ptr const &) 
= delete;
~FrontendParameters_Ptr() {dvb_fe_close(ptr); }
dvb_v5_fe_parms * c_ptr() const { return ptr; }
dvb_v5_fe_parms * operator->() const { return ptr; }
};


Has anyone any experience of doing the analogous thing idiomatically in
D.

I just re-realised I manually constructed a C++ abstraction layer
around some of libdvbv5, so I am going to do the same for D. However
whilst I (sort of) understand doing the wrapping with C++, I am not
sure I have seen anyone wrapping C pointers with RAII in D.

-- 
Russel.
=
Dr Russel Winder  t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder

signature.asc
Description: This is a digitally signed message part


Re: RAII

2017-02-23 Thread ketmar via Digitalmars-d-learn

Arun Chandrasekaran wrote:


On Thursday, 23 February 2017 at 09:57:09 UTC, ketmar wrote:

Thanks for your help. NRVO looks interesting. However this may not be 
RAII after all. Or may be too much of C++ has spoiled me. I am not 
familiar enough with D to appreciate/question the language design 
choice. I'll accept this and move forward and see how my code 
evolves. Nevertheless, I'm still learning something new. :)


also, why structs at all? there are another ways! ;-)

 void doWithLock (scope void delegate () action) {
   lockSomething();
   scope(exit) unlockSomething();
   action();
 }

no, wait, this is not so limiting as it may look!

 void foo () {
   int i = 42;
   doWithLock({
 writeln("i=", i); // yay, 42!
   });
 }

this looks *almost* like `synchronized(obj) { ... }`! and if we'll ever 
press D devs to allow us to omit "()" when the only argument is 
arg-less lambda... it will be indistinguishable from built-in! ;-)


Re: RAII

2017-02-23 Thread Arun Chandrasekaran via Digitalmars-d-learn

On Thursday, 23 February 2017 at 21:05:48 UTC, cym13 wrote:
It reminds me of 
https://w0rp.com/blog/post/an-raii-constructor-by-another-name-is-just-as-sweet/ which isn't what you want but may be interesting anyway.


It is interesting, indeed, thanks.


Re: RAII

2017-02-23 Thread Arun Chandrasekaran via Digitalmars-d-learn

On Thursday, 23 February 2017 at 09:57:09 UTC, ketmar wrote:

Arun Chandrasekaran wrote:


I'm trying to write an RAII wrapper on Linux.

I understand struct in D doesn't have default constructor (for 
.init reasons).

I don't want to use `scope`.

Is there an elegant way to achieve this in D?
why not static method or free function that returns struct? due 
to NRVO[0] it won't even be copied.


 auto lock = MyWrapper();

`MyWrapper()` may return voldemort type, so user won't create 
your struct accidentally.



[0] https://dlang.org/glossary.html#nrvo


Thanks for your help. NRVO looks interesting. However this may 
not be RAII after all. Or may be too much of C++ has spoiled me. 
I am not familiar enough with D to appreciate/question the 
language design choice. I'll accept this and move forward and see 
how my code evolves. Nevertheless, I'm still learning something 
new. :)


Re: RAII

2017-02-23 Thread cym13 via Digitalmars-d-learn
On Thursday, 23 February 2017 at 09:52:26 UTC, Arun 
Chandrasekaran wrote:

I'm trying to write an RAII wrapper on Linux.

I understand struct in D doesn't have default constructor (for 
.init reasons).

I don't want to use `scope`.

Is there an elegant way to achieve this in D?

```
import core.sys.posix.pthread;
import core.sys.posix.sys.types;

/// Makes pthread_mutexattr_t cleanup easy when using exceptions
struct mutexattr_wrapper
{
/// Constructor
this(bool _)
{
if (pthread_mutexattr_init(&m_attr) != 0 ||
pthread_mutexattr_setpshared(&m_attr, 
PTHREAD_PROCESS_SHARED)!= 0)

  // may be I will add few more methods here
  throw custom_exception("pthread_mutexattr_ 
failed");

}

/// Destructor
~this() {  pthread_mutexattr_destroy(&m_attr);  }

/// This allows using mutexattr_wrapper as 
pthread_mutexattr_t

alias m_attr this;

pthread_mutexattr_t m_attr;
}
```


It reminds me of 
https://w0rp.com/blog/post/an-raii-constructor-by-another-name-is-just-as-sweet/ which isn't what you want but may be interesting anyway.


Re: RAII

2017-02-23 Thread kinke via Digitalmars-d-learn

On Thursday, 23 February 2017 at 18:46:58 UTC, kinke wrote:

A constructor is just a factory function with a special name...


Wrt. the special name, that's obviously extremely useful for 
generic templates (containers etc.).


Re: RAII

2017-02-23 Thread kinke via Digitalmars-d-learn
On Thursday, 23 February 2017 at 14:24:14 UTC, Adam D. Ruppe 
wrote:

On Thursday, 23 February 2017 at 10:48:38 UTC, kinke wrote:
That's not elegant. You need a factory function for each type 
containing one of these structs then.


A constructor is just a factory function with a special name... 
it is almost equal amount of work.


Sorry but this is just completely wrong. RAII is all about me NOT 
having to call special functions all over the place.


struct S
{
this() { /* initialize */ }
}

S[123] myArray; // hooray, no need to invoke a factory in a loop

struct Container
{
S s;
// hooray, implicit this() automatically calls s.this()
}


Re: RAII

2017-02-23 Thread Adam D. Ruppe via Digitalmars-d-learn

On Thursday, 23 February 2017 at 10:48:38 UTC, kinke wrote:
That's not elegant. You need a factory function for each type 
containing one of these structs then.


A constructor is just a factory function with a special name... 
it is almost equal amount of work.


Re: RAII

2017-02-23 Thread Adrian Matoga via Digitalmars-d-learn
On Thursday, 23 February 2017 at 09:52:26 UTC, Arun 
Chandrasekaran wrote:

I'm trying to write an RAII wrapper on Linux.

I understand struct in D doesn't have default constructor (for 
.init reasons).

I don't want to use `scope`.

Is there an elegant way to achieve this in D?



static opCall() is the way to emulate an argumentless struct 
constructor. You still need to call it explicitly, though:


```
import std.stdio : writefln;
struct Foo {
int a;
static Foo opCall() {
Foo foo;
foo.a = 42;
return foo;
}
~this() {
writefln("destroyed with a=%d", a);
}
@disable this(this);
@disable void opAssign(Foo);
}

void main()
{
auto foo1 = Foo(); // ok
Foo foo2;  // == Foo.init
}
```




Re: RAII

2017-02-23 Thread kinke via Digitalmars-d-learn

On Thursday, 23 February 2017 at 09:57:09 UTC, ketmar wrote:

Arun Chandrasekaran wrote:

Is there an elegant way to achieve this in D?
why not static method or free function that returns struct? due 
to NRVO[0] it won't even be copied.


That's not elegant. You need a factory function for each type 
containing one of these structs then.


Re: RAII

2017-02-23 Thread ketmar via Digitalmars-d-learn

Arun Chandrasekaran wrote:


I'm trying to write an RAII wrapper on Linux.

I understand struct in D doesn't have default constructor (for .init 
reasons).

I don't want to use `scope`.

Is there an elegant way to achieve this in D?
why not static method or free function that returns struct? due to 
NRVO[0] it won't even be copied.


 auto lock = MyWrapper();

`MyWrapper()` may return voldemort type, so user won't create your 
struct accidentally.



[0] https://dlang.org/glossary.html#nrvo


RAII

2017-02-23 Thread Arun Chandrasekaran via Digitalmars-d-learn

I'm trying to write an RAII wrapper on Linux.

I understand struct in D doesn't have default constructor (for 
.init reasons).

I don't want to use `scope`.

Is there an elegant way to achieve this in D?

```
import core.sys.posix.pthread;
import core.sys.posix.sys.types;

/// Makes pthread_mutexattr_t cleanup easy when using exceptions
struct mutexattr_wrapper
{
/// Constructor
this(bool _)
{
if (pthread_mutexattr_init(&m_attr) != 0 ||
pthread_mutexattr_setpshared(&m_attr, 
PTHREAD_PROCESS_SHARED)!= 0)

  // may be I will add few more methods here
  throw custom_exception("pthread_mutexattr_ failed");
}

/// Destructor
~this() {  pthread_mutexattr_destroy(&m_attr);  }

/// This allows using mutexattr_wrapper as pthread_mutexattr_t
alias m_attr this;

pthread_mutexattr_t m_attr;
}
```


Re: RAII and classes

2016-03-09 Thread John Colvin via Digitalmars-d-learn

On Wednesday, 9 March 2016 at 10:48:30 UTC, cym13 wrote:

On Wednesday, 9 March 2016 at 10:28:06 UTC, John Colvin wrote:
Potential for leaking references from alias this aside, is 
there some reason that I shouldn't do this for all my C++-like 
RAII needs:


class A
{
~this(){ import std.stdio; writeln("hello"); }
}

auto RAII(T)()
if (is(T == class))
{
struct Inner
{
private ubyte[__traits(classInstanceSize, T)] buff;
T c;
alias c this;

~this()
{
destroy(c);
}
}
Inner tmp;
import std.conv : emplace;
tmp.c = tmp.buff.emplace!T;
return tmp;
}

void main()
{
    auto a = RAII!A;
}


That's almost literally what std.typecons.scoped does.


Ok, I forgot std.typecons.scoped, nothing to see here .


Re: RAII and classes

2016-03-09 Thread cym13 via Digitalmars-d-learn

On Wednesday, 9 March 2016 at 10:28:06 UTC, John Colvin wrote:
Potential for leaking references from alias this aside, is 
there some reason that I shouldn't do this for all my C++-like 
RAII needs:


class A
{
~this(){ import std.stdio; writeln("hello"); }
}

auto RAII(T)()
if (is(T == class))
{
struct Inner
{
private ubyte[__traits(classInstanceSize, T)] buff;
T c;
alias c this;

~this()
{
destroy(c);
}
}
Inner tmp;
import std.conv : emplace;
tmp.c = tmp.buff.emplace!T;
return tmp;
}

void main()
{
    auto a = RAII!A;
}


That's almost literally what std.typecons.scoped does.


RAII and classes

2016-03-09 Thread John Colvin via Digitalmars-d-learn
Potential for leaking references from alias this aside, is there 
some reason that I shouldn't do this for all my C++-like RAII 
needs:


class A
{
~this(){ import std.stdio; writeln("hello"); }
}

auto RAII(T)()
if (is(T == class))
{
struct Inner
{
private ubyte[__traits(classInstanceSize, T)] buff;
T c;
alias c this;

~this()
{
destroy(c);
}
}
Inner tmp;
import std.conv : emplace;
tmp.c = tmp.buff.emplace!T;
return tmp;
}

void main()
{
    auto a = RAII!A;
}


Re: RAII trouble

2015-11-20 Thread Spacen Jasset via Digitalmars-d-learn

On Friday, 20 November 2015 at 23:35:50 UTC, Spacen Jasset wrote:

On Friday, 20 November 2015 at 23:21:03 UTC, anonymous wrote:

[...]
FT_Init_FreeType must be read at compile time, because 
freeType is a module level variable, and initializers for 
module variables must be static values. The initializer is run 
through CTFE (Compile Time Function Evaluation).
Put the initialization/assignment in a function and it should 
work. That function can be a static constructor or the main 
function:



[...]


Yes, I see. I made a mistake. I need to initialize it 
elsewhere. It was quite confusing.


Thanks.


I Just noticed this trick you posted, that's interesting. Of 
course I couldn't get it working without the void to discard the 
initialization;


FreeType freeType = void; /* 'void' prevents default 
initialization */
static this() {freeType = FreeType.initialise();} /* should work 
*/


Re: RAII trouble

2015-11-20 Thread Spacen Jasset via Digitalmars-d-learn

On Friday, 20 November 2015 at 23:21:03 UTC, anonymous wrote:

[...]
FT_Init_FreeType must be read at compile time, because freeType 
is a module level variable, and initializers for module 
variables must be static values. The initializer is run through 
CTFE (Compile Time Function Evaluation).
Put the initialization/assignment in a function and it should 
work. That function can be a static constructor or the main 
function:



[...]


Yes, I see. I made a mistake. I need to initialize it elsewhere. 
It was quite confusing.


Thanks.


Re: RAII trouble

2015-11-20 Thread anonymous via Digitalmars-d-learn

On 20.11.2015 23:56, Spacen Jasset wrote:

The ideal would be to have a struct that can be placed inside a function
scope, or perhaps as a module global variable. Why does Ft_Init_FreeType
have to be read at compile time?


text.d(143,15): Error: static variable FT_Init_FreeType cannot be read
at compile time
text.d(174,43):called from here: initialise()

struct FreeType
{
 @disable this();

 static FreeType initialise()
 {
 return FreeType(0);
 }

 this(int)
 {
 int error = FT_Init_FreeType(&library); /// ERROR
 enforce(!error);
 }

 alias library this;

 ~this()
 {
 FT_Done_FreeType(library);
 }
 FT_Library library;
}

FreeType   freeType = FreeType.initialise();



FT_Init_FreeType must be read at compile time, because freeType is a 
module level variable, and initializers for module variables must be 
static values. The initializer is run through CTFE (Compile Time 
Function Evaluation).


Put the initialization/assignment in a function and it should work. That 
function can be a static constructor or the main function:


FreeType freeType = void; /* 'void' prevents default initialization */
static this() {freeType = FreeType.initialise();} /* should work */
void main() {freeType = FreeType.initialise();} /* too */



Re: RAII trouble

2015-11-20 Thread Ali Çehreli via Digitalmars-d-learn

On 11/20/2015 02:56 PM, Spacen Jasset wrote:

> FT_Init_FreeType is a static which is set at some previous time to a
> function entry point in the FreeType library.

> text.d(143,15): Error: static variable FT_Init_FreeType cannot be read
> at compile time

The compiler seems to think that FT_Init_FreeType is a variable. Is that 
really a function pointer? Can you show how it's defined.


My simple test works:

extern (C) int init_func(double){
return 42;
}

static auto my_func = &init_func;

struct S {
static S init() {
return S(0);
}

this(int) {
my_func(1.5);
}
}

void main() {
auto s = S.init();
}

Ali



RAII trouble

2015-11-20 Thread Spacen Jasset via Digitalmars-d-learn
I have the following code in attempt to create an RAII object 
wrapper, but it seems that it might be impossible. The problem 
here is that FT_Init_FreeType is a static which is set at some 
previous time to a function entry point in the FreeType library.


I could use a scope block, but would rather have a self contained 
thing to do the work. Perhaps some sort of mixin is the other 
solution?


The ideal would be to have a struct that can be placed inside a 
function scope, or perhaps as a module global variable. Why does 
Ft_Init_FreeType have to be read at compile time?



text.d(143,15): Error: static variable FT_Init_FreeType cannot be 
read at compile time

text.d(174,43):called from here: initialise()

struct FreeType
{
@disable this();

static FreeType initialise()
{
return FreeType(0);
}

this(int)
{
int error = FT_Init_FreeType(&library); /// ERROR
enforce(!error);
}

alias library this;

~this()
{
FT_Done_FreeType(library);
}
FT_Library library;
}

FreeType   freeType = FreeType.initialise();



Re: RAII and Deterministic Destruction

2015-08-26 Thread Jim Hewes via Digitalmars-d-learn

Thanks. I had not looked at some of those yet.

Jim


Re: RAII and Deterministic Destruction

2015-08-26 Thread Jim Hewes via Digitalmars-d-learn
Thanks for all the info. It's a good comparison of structs and classes 
to keep handy. Actually, I'm fine with the GC. I don't mean to avoid it. 
I just would like some way to also have non-memory resources 
automatically released in a timely, predictable way.


One common thing to do in C++ is to manage the lifetime of an object 
with std::unique_ptr but then use its .get() function to get a native 
pointer to use temporarily. You just have to ensure that the native 
pointer doesn't outlive the unique_ptr, which isn't that difficult. 
True, if the unique_ptr gets destructed the native pointer is invalid 
and that could be risky, but you limit its use.
Unique in D doesn't seem to have anything like a get() function but I 
wonder if it could. That is, it would get another "native" reference to 
the Unique resource that is managed by the garbage collector. So if the 
Unique went out of scope and got destructed, the reference would at 
least refer to valid memory although not a valid object because its 
destructor had already been called. Not perfectly safe, but no worse 
than the C++ case. Just a thought.


Jim


Re: RAII and Deterministic Destruction

2015-08-26 Thread Jim Hewes via Digitalmars-d-learn
Thanks for the thorough response. I'm aware of some of what you 
explained. Maybe I should have asked differently. Rather than asking 
what RAII facilities do exist, I guess I was looking for the answer, 
"Here's what you typically do in C++ RAII that you can't do in D." I 
could probably find out things by experimenting too (and not be too 
lazy). I just didn't want to rely on my assumptions only.


For example, say object A is a member of object B which is in turn a 
member of object C. If C is deleted or goes out of scope, does the 
destructor of A get called? If all three are classes, obviously not. But 
if all three are structs? What if they are classes but are all managed 
by Unique? If I use Unique for all of my heap-allocated classes (as I 
would with std::unique_ptr in C++)  am I assured of destructors being 
called when the owning classes get destructed? I'm wondering about these 
various nesting/owning combinations.


Jim


Re: RAII and Deterministic Destruction

2015-08-26 Thread kink via Digitalmars-d-learn
A serious bug affecting RAII is 
https://issues.dlang.org/show_bug.cgi?id=14903, but apparently 
its importance hasn't been properly acknowledged yet. Improving 
the performance of binaries produced by dmd's backend is 
obviously way more important than fixing serious bugs or 
commenting on related PRs.


Re: RAII and Deterministic Destruction

2015-08-25 Thread Mike via Digitalmars-d-learn

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages like 
C# is because I like deterministic destruction so much. My 
question is whether D can REALLY handle this or not. I've not 
been sure about this for some time so now I'm just going to 
come out and finally ask.


You may also find http://wiki.dlang.org/Memory_Management useful. 
 It shows a number of different patterns one can employ for 
deterministic memory management.  The one which you'll probably 
find most C++-like is 
http://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation


Mike




Re: RAII and Deterministic Destruction

2015-08-25 Thread ZombineDev via Digitalmars-d-learn

On Wednesday, 26 August 2015 at 01:18:43 UTC, ZombineDev wrote:

On Wednesday, 26 August 2015 at 01:09:15 UTC, ZombineDev wrote:

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages 
like C# is because I like deterministic destruction so much. 
My question is whether D can REALLY handle this or not. I've 
not been sure about this for some time so now I'm just going 
to come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having 
classes as member variables of other classes. (Do the members 
get destructors called too?)


Then there is std.typecons.Unique and  
std.typecons.RefCounted. With these, can I really get 
deterministic destruction for all cases like I would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would 
be looking for this.


Jim


Structs in D behave like in C++ - they are created on the 
stack (unless you use new or malloc), passed by value and are 
automatically destroyed at the end of the scope. All their 
members are destroyed recursively after the user defined 
destructor is called.


Just try it out in a toy program and see if it works as you 
expect.


Classes on the other hand are reference types and are created 
on the garbage-collected heap by default (though you can do 
your own memory management). Similarly, structs created by new 
are also allocated on the GC heap. During collections the GC 
will call destructors, but it is not guaranteed and you should 
not rely on it. For example (depending on your GC usage and 
configuration) only a single collection may occur at the end of 
the program.


Generally a very tutorial and reference is Ali's book [1], which 
is listed under Books and Articles in the sidebar of dlang.org.
You should check the chapters Constructor and Other Special 
Functions [2] and Memory Management [3] (even though it covers 
mostly the GC).


If you wish to avoid the GC, you can annotate your functions with 
the @nogc attribute [4] which enforces at compile-time that the 
annotated function won't use the GC. It is transitive which means 
that if you annotate your main() function with it, you shouldn't 
be allowed to use anything that allocates memory from the GC in 
your whole program.
Since this feature was added there is an ongoing effort to 
minimize GC usage in the standard library, but there's still 
stuff that require it. That said the recommended approach is to 
build your data processing on ranges [5] (see the linked article 
by Andrei Alexandrescu) because it allows you to encapsulate 
memory usage more strategically. This is enabled by the lazy 
nature of ranges - they process data only when needed and so they 
don't need to allocate memory.


Probably the best introduction to this technique is Walter 
Bright's keynote at DConf 2015 [6]: 
https://www.youtube.com/watch?v=znjesAXEEqw


Be sure to check the DConf website as there's lots of great 
content from 2013 [7], 2014 [8] and 2015 [9].


[1]: http://ddili.org/ders/d.en/index.html
[2]: http://ddili.org/ders/d.en/special_functions.html
[3]: http://ddili.org/ders/d.en/memory.html
[4]: http://dlang.org/attribute.html#nogc
[5]: http://dlang.org/phobos/std_range.html
[6]: https://www.youtube.com/watch?v=znjesAXEEqw
[7]: http://dconf.org/2013/
[8]: http://dconf.org/2014/
[9]: http://dconf.org/2015/


Re: RAII and Deterministic Destruction

2015-08-25 Thread rsw0x via Digitalmars-d-learn

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages like 
C# is because I like deterministic destruction so much. My 
question is whether D can REALLY handle this or not. I've not 
been sure about this for some time so now I'm just going to 
come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having 
classes as member variables of other classes. (Do the members 
get destructors called too?)


Then there is std.typecons.Unique and  std.typecons.RefCounted. 
With these, can I really get deterministic destruction for all 
cases like I would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would be 
looking for this.


Jim


To add to what the other people said,
there exists scoped!T in std.typecons to allocate a class on the 
stack, and Unique/RefCounted as you mentioned. AFAIK refcounted 
is in the process of being overhauled, but the user should notice 
no differences.


Re: RAII and Deterministic Destruction

2015-08-25 Thread cym13 via Digitalmars-d-learn

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages like 
C# is because I like deterministic destruction so much. My 
question is whether D can REALLY handle this or not. I've not 
been sure about this for some time so now I'm just going to 
come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having 
classes as member variables of other classes. (Do the members 
get destructors called too?)


Then there is std.typecons.Unique and  std.typecons.RefCounted. 
With these, can I really get deterministic destruction for all 
cases like I would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would be 
looking for this.


Jim


Hi Jim. RAII in D is a common issue for people coming from C++. I 
don't know everything on the subject and would be glad to be 
corrected if I write a mistake but here is my share on the 
subject.


There are two very different kind of objects in D and memory 
management is different for each: structs and classes. I think 
you mostly want to hear about classes, but I think each should be 
studied nonetheless.


Structs:
=

Why would you use structs?

- They are stack-allocated by default (but can be heap-allocated 
at will)
- They are destroyed at the end of the scope, hence supporting 
RAII properly

- They provide rather nice idioms for RAII [1]
- They support single-inheritance through “alias this”
- They support compile-time polymorphism through templates
- They support complex object composition through template mixins 
[2]


Why wouldn't you use structs?

- You want to plug yourself on an already existing class-based 
system

- You want to use interfaces
- You need runtime-polymorphism

Classes:
=

Why would you use classes?

- They are heap-based and managed by the GC: lazy destruction
- They provide full support for inheritance and OOP (including 
interfaces)

- They support compile-time polymorphism through templates
- They support complex object composition through template mixins 
[2]


Why wouldn't use classes?

- They are heap-based
- They don't allow deterministic implicit destruction

How to solve these problems?
==

Classes don't have *implicit* deterministic destruction but 
nothing prevents you from calling a destructor explicitely (be it 
~this or another dedicated function). This can be easily done 
using scope(...) statements. If this is cumbersome, 
std.typecons.Unique and std.typecons.RefCounted can be used to 
provide a comportment analogous to that of modern C++. We said 
that structs are scope-based, a solution is to wrap an object 
into a struct and set the structs destructor to destroy the 
object as well at the end of the scope. std.typecons.scoped 
provides a nice wrapper arround this behaviour. The destruction 
of an object doesn't mean the destruction of the objects that it 
referenced. That can also be done explicitely.


A word on the GC
===

I see a lot of C++ programmer who come to D with a single thought 
in mind: “Avoid the GC at all cost, let me manage my damn 
memory”. This is understandable, yet biaised. True, a GC isn't 
for all applications, but it has its place. Instead of fearing 
it, learning to use it well is important. One often doesn't need 
deterministic destruction. Lazy destruction has its benefits. I 
strongly advise not to rush trying to avoid the GC, instead 
profile profile profile.


Conclusion
===

Doing RAII is possible for structs and for classes, but it is 
*really* easier with structs. D structs are really powerful and 
often underestimated by newcommers who rush on the "class" 
keyword. D classes aren't C++ classes. My advice would be to use 
structs as much as possible, to use classes where needed relying 
on the GC, and after profiling to introduce RAII behaviour into 
problematic classes.


[1] 
https://w0rp.com/blog/post/an-raii-constructor-by-another-name-is-just-as-sweet/
[2] 
https://blog.dicebot.lv/posts/2015/08/OOP_composition_with_mixins


Re: RAII and Deterministic Destruction

2015-08-25 Thread ZombineDev via Digitalmars-d-learn

On Wednesday, 26 August 2015 at 01:09:15 UTC, ZombineDev wrote:

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages like 
C# is because I like deterministic destruction so much. My 
question is whether D can REALLY handle this or not. I've not 
been sure about this for some time so now I'm just going to 
come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having 
classes as member variables of other classes. (Do the members 
get destructors called too?)


Then there is std.typecons.Unique and  
std.typecons.RefCounted. With these, can I really get 
deterministic destruction for all cases like I would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would 
be looking for this.


Jim


Structs in D behave like in C++ - they are created on the stack 
(unless you use new or malloc), passed by value and are 
automatically destroyed at the end of the scope. All their 
members are destroyed recursively after the user defined 
destructor is called.


Just try it out in a toy program and see if it works as you 
expect.


Classes on the other hand are reference types and are created on 
the garbage-collected heap by default (though you can do your own 
memory management). Similarly, structs created by new are also 
allocated on the GC heap. During collections the GC will call 
destructors, but it is not guaranteed and you should not rely on 
it. For example (depending on your GC usage and configuration) 
only a single collection may occur at the end of the program.


Re: RAII and Deterministic Destruction

2015-08-25 Thread ZombineDev via Digitalmars-d-learn

On Tuesday, 25 August 2015 at 22:35:57 UTC, Jim Hewes wrote:
Although C++ can be ugly, one reason I keep going back to it 
rather then commit more time to reference-based languages like 
C# is because I like deterministic destruction so much. My 
question is whether D can REALLY handle this or not. I've not 
been sure about this for some time so now I'm just going to 
come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having 
classes as member variables of other classes. (Do the members 
get destructors called too?)


Then there is std.typecons.Unique and  std.typecons.RefCounted. 
With these, can I really get deterministic destruction for all 
cases like I would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would be 
looking for this.


Jim


Structs in D behave like in C++ - they are created on the stack 
(unless you use new or malloc), passed by value and are 
automatically destroyed at the end of the scope. All their 
members are destroyed recursively after the user defined 
destructor is called.


Just try it out in a toy program and see if it works as you 
expect.


RAII and Deterministic Destruction

2015-08-25 Thread Jim Hewes via Digitalmars-d-learn
Although C++ can be ugly, one reason I keep going back to it rather then 
commit more time to reference-based languages like C# is because I like 
deterministic destruction so much. My question is whether D can REALLY 
handle this or not. I've not been sure about this for some time so now 
I'm just going to come out and finally ask.


I know about this RAII section in the documentation: 
http://dlang.org/cpptod.html#raii
But I don't believe that handles all cases, such as having classes as 
member variables of other classes. (Do the members get destructors 
called too?)


Then there is std.typecons.Unique and  std.typecons.RefCounted. With 
these, can I really get deterministic destruction for all cases like I 
would in C++?


If so, it might be a good idea to emphasize this more in the 
documentation because I'd think people coming from C++ would be looking 
for this.


Jim


Re: RAII limitations in D?

2014-08-22 Thread Russel Winder via Digitalmars-d-learn
On Thu, 2014-08-21 at 19:22 -0700, Timothee Cour via Digitalmars-d-learn
wrote:
> What would be a good answer to this article?
> http://swiftcoder.wordpress.com/2009/02/18/raii-why-is-it-unique-to-c/
> 
> Especially the part mentioning D:{
> D’s scope keyword, Python’s with statement and C#’s using declaration all
> provide limited RAII, by allowing resources to have a scoped lifetime, but
> none of them readily or cleanly support the clever tricks allowed by C++’s
> combination of smart pointers and RAII, such as returning handles from
> functions, multiple handles in the same scope, or handles held by multiple
> clients.
> }

The author has clearly not actually used Python. There is nothing that C
++ can do with RAII that you cannot do with Python/context managers/with
statement. Nothing.

-- 
Russel.
=
Dr Russel Winder  t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
41 Buckmaster Roadm: +44 7770 465 077   xmpp: rus...@winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder



Re: RAII limitations in D?

2014-08-21 Thread Kagamin via Digitalmars-d-learn
On Friday, 22 August 2014 at 02:22:16 UTC, Timothee Cour via 
Digitalmars-d-learn wrote:

Especially the part mentioning D:{
D’s scope keyword, Python’s with statement and C#’s using 
declaration all
provide limited RAII, by allowing resources to have a scoped 
lifetime, but
none of them readily or cleanly support the clever tricks 
allowed by C++’s
combination of smart pointers and RAII, such as returning 
handles from
functions, multiple handles in the same scope, or handles held 
by multiple

clients.
}


Even for C# those are not really problems. Returning from 
functions is not a problem: you just return it and that's it, 
because resource management is decoupled from types, the types 
have no RAII semantics and you can move them around however you 
want. On the other hand, in C# it's very easy to declare a 
resource, while in C++ you would need to learn all the black 
magic of RAII before you can declare a RAII type. Multiple 
handles in the same scope are not frequent, nested if's cause 
much more trouble. Handles held by multiple clients are even more 
rare, and it's usually easy to figure out lifetime for non-memory 
resources.


Re: RAII limitations in D?

2014-08-21 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, 22 August 2014 at 03:00:01 UTC, Timothee Cour via 
Digitalmars-d-learn wrote:
On Thu, Aug 21, 2014 at 7:26 PM, Dicebot via 
Digitalmars-d-learn <

digitalmars-d-learn@puremagic.com> wrote:


http://dlang.org/phobos/std_typecons.html#.RefCounted



That doesn't work with classes though; is there any way to get 
a ref

counted class?

(and btw RefCounted should definitely appear in
http://dlang.org/cpptod.html#raii)


It can be made to work with classes and probably should be. 
There's no fundamental reason why it can't. It's probably just 
more complicated.


- Jonathan M Davis


Re: RAII limitations in D?

2014-08-21 Thread Timothee Cour via Digitalmars-d-learn
On Thu, Aug 21, 2014 at 7:26 PM, Dicebot via Digitalmars-d-learn <
digitalmars-d-learn@puremagic.com> wrote:

> http://dlang.org/phobos/std_typecons.html#.RefCounted


That doesn't work with classes though; is there any way to get a ref
counted class?

(and btw RefCounted should definitely appear in
http://dlang.org/cpptod.html#raii)


Re: RAII limitations in D?

2014-08-21 Thread Adam D. Ruppe via Digitalmars-d-learn
On Friday, 22 August 2014 at 02:22:16 UTC, Timothee Cour via 
Digitalmars-d-learn wrote:

What would be a good answer to this article?


It's own publication date: Feb 2009. The D struct has changed a 
lot since then, getting new features (@disable, postblit, more 
reliable destructor) and bugs notwithstanding is pretty well on 
point nowadays.


All the stuff mentioned in there works now.


Re: RAII limitations in D?

2014-08-21 Thread Dicebot via Digitalmars-d-learn

http://dlang.org/phobos/std_typecons.html#.RefCounted


RAII limitations in D?

2014-08-21 Thread Timothee Cour via Digitalmars-d-learn
What would be a good answer to this article?
http://swiftcoder.wordpress.com/2009/02/18/raii-why-is-it-unique-to-c/

Especially the part mentioning D:{
D’s scope keyword, Python’s with statement and C#’s using declaration all
provide limited RAII, by allowing resources to have a scoped lifetime, but
none of them readily or cleanly support the clever tricks allowed by C++’s
combination of smart pointers and RAII, such as returning handles from
functions, multiple handles in the same scope, or handles held by multiple
clients.
}

This morning I was pointing to some deprecated usage of scope mentioned in
docs (EMAIL:scope classes mentioned in tutorials, but deprecated). The pull
request (https://github.com/D-Programming-Language/dlang.org/pull/637/files)
mentions using struct or classes allocated on the stack via
typecons.scoped. However what about the RAII usage mentioned in the above
article that allows C++ to return handles for eg (impossible via scope),
that get deterministically destroyed?


Re: Sparse Aggregate Assignment/Initialization (RAII)

2014-07-08 Thread via Digitalmars-d-learn

On Monday, 7 July 2014 at 21:49:22 UTC, Justin Whear wrote:

On Mon, 07 Jul 2014 21:34:05 +, Nordlöw wrote:


However using this function through UFCS

 auto cx = new C().set!"x"(11);

fails as

algorithm_ex.d(1257,17): Error: template algorithm_ex.set 
cannot deduce

function from argument types !("x")(C, int), candidates are:
algorithm_ex.d(1242,7):algorithm_ex.set(string member, 
T,

U)(ref T a, in U value) if (isAggregateType!T && hasMember!(T,
member))

Instead I have to use

 auto c = new C(); set!"x"(c, 11);

which is not as elegant.

Why doesn't UCFS work here and is there a solution using DMD 
git master?


You need to use `auto ref` to have this work with both classes 
and
structs.  A working version of your code here: auto dx = 
D().set!"x"(11);

assert(dx.x == 11);


To elaborate:
`new C()` is an r-value, and references can only be taken from 
l-values.


Re: Sparse Aggregate Assignment/Initialization (RAII)

2014-07-07 Thread Nordlöw

On Monday, 7 July 2014 at 21:50:22 UTC, Justin Whear wrote:

Copy and paste gone astray; should be this link:
http://dpaste.dzfl.pl/3c33ad70040f


Thx!


Re: Sparse Aggregate Assignment/Initialization (RAII)

2014-07-07 Thread Justin Whear via Digitalmars-d-learn
On Mon, 07 Jul 2014 21:49:22 +, Justin Whear wrote:

> On Mon, 07 Jul 2014 21:34:05 +, Nordlöw wrote:
> 
>> However using this function through UFCS
>> 
>>  auto cx = new C().set!"x"(11);
>> 
>> fails as
>> 
>> algorithm_ex.d(1257,17): Error: template algorithm_ex.set cannot deduce
>> function from argument types !("x")(C, int), candidates are:
>> algorithm_ex.d(1242,7):algorithm_ex.set(string member, T,
>> U)(ref T a, in U value) if (isAggregateType!T && hasMember!(T,
>> member))
>> 
>> Instead I have to use
>> 
>>  auto c = new C(); set!"x"(c, 11);
>> 
>> which is not as elegant.
>> 
>> Why doesn't UCFS work here and is there a solution using DMD git
>> master?
> 
> You need to use `auto ref` to have this work with both classes and
> structs.  A working version of your code here: auto dx =
> D().set!"x"(11);
>   assert(dx.x == 11);

Copy and paste gone astray; should be this link:
http://dpaste.dzfl.pl/3c33ad70040f


Re: Sparse Aggregate Assignment/Initialization (RAII)

2014-07-07 Thread Justin Whear via Digitalmars-d-learn
On Mon, 07 Jul 2014 21:34:05 +, Nordlöw wrote:

> However using this function through UFCS
> 
>  auto cx = new C().set!"x"(11);
> 
> fails as
> 
> algorithm_ex.d(1257,17): Error: template algorithm_ex.set cannot deduce
> function from argument types !("x")(C, int), candidates are:
> algorithm_ex.d(1242,7):algorithm_ex.set(string member, T,
> U)(ref T a, in U value) if (isAggregateType!T && hasMember!(T,
> member))
> 
> Instead I have to use
> 
>  auto c = new C(); set!"x"(c, 11);
> 
> which is not as elegant.
> 
> Why doesn't UCFS work here and is there a solution using DMD git master?

You need to use `auto ref` to have this work with both classes and 
structs.  A working version of your code here: auto dx = D().set!"x"(11);
assert(dx.x == 11);

On Mon, 07 Jul 2014 21:34:05 +, Nordlöw wrote:
> Further Is there a cleverer way to do this without resorting to mixins?

__traits(getMember, ...) is useful here, see this version of your code: 
http://dpaste.dzfl.pl/75e03fbec020


Sparse Aggregate Assignment/Initialization (RAII)

2014-07-07 Thread Nordlöw
Because D currently doesn't support RAII using named parameters 
like in Python I tried the following.


Say I have an aggregate

class C { int x,y,z,w; }

or similarly

struct C { int x,y,z,w; }

I know define a generic _free_ function

ref T set(string member, T, U)(ref T a, in U value) if 
(isAggregateType!T &&

hasMember!(T, member))

{
mixin(`a.` ~ member ~ ` = value;`);
return a;
}

which I want to use for flexible initialization of several 
members at once.


However using this function through UFCS

auto cx = new C().set!"x"(11);

fails as

algorithm_ex.d(1257,17): Error: template algorithm_ex.set cannot 
deduce function from argument types !("x")(C, int), candidates 
are:
algorithm_ex.d(1242,7):algorithm_ex.set(string member, T, 
U)(ref T a, in U value) if (isAggregateType!T && hasMember!(T, 
member))


Instead I have to use

auto c = new C(); set!"x"(c, 11);

which is not as elegant.

Why doesn't UCFS work here and is there a solution using DMD git 
master?


Further Is there a cleverer way to do this without resorting to 
mixins?


This old post

http://forum.dlang.org/thread/mailman.2966.1301533296.4748.digitalmars-d-le...@puremagic.com

talks about opDispatch() but, to my knowledge, it requires the 
aggregate to have extra members doing the initialization.


I want this because I've identified in some parts of my code that 
I have large structures were only a few of the elements are 
initialized to non-default values.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2012-01-06 Thread Stewart Gordon

On 06/01/2012 14:44, Andrej Mitrovic wrote:

Just implement your own exception type, e.g. ExitException, and then use:


That's more or less what people have already said.  What's more, Ashish has already 
suggested a further improvement whereby the custom exception carries an exit code.



void main() { try { realMain(); } catch (ExitException e) { return 0; }



That should have been int main.


That's not the only typo - you've forgotten to finish that function with a return for if 
ExitException is never thrown and a closing }.


Stewart.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2012-01-06 Thread Andrej Mitrovic
That should have been int main.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2012-01-06 Thread Andrej Mitrovic
Just implement your own exception type, e.g. ExitException, and then use:

void main() { try { realMain(); } catch (ExitException e) { return 0; }
void exit() { throw ExitException(); }

where realMain is the actual main function. Then just call exit()
whenever you want to.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2012-01-06 Thread Stewart Gordon

On 29/12/2011 19:09, Jacob Carlborg wrote:


Could druntime hook up on the atexit function to run destructors and similar 
when the
program exits?


I'm not sure.  Maybe it could be called upon to run static destructors and destruct 
heap-allocated objects.  But in order to call scope guards and RAII, it would need to 
unwind the call stack, which could get complicated if you're trying to do it from within a 
function.


It's much simpler not to use exit() and throw a custom exception instead.

Stewart.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-30 Thread Ashish Myles
Thanks, Jonathan, for your detailed answer.

Ashish


On Fri, Dec 30, 2011 at 1:41 PM, Jonathan M Davis  wrote:
> On Friday, December 30, 2011 10:45:43 Ashish Myles wrote:
>> Ok, now there are two issues here:
>> IMPLEMENTATION: Implementation of a safe_exit() without an explicit
>> Exception seems to be easy to do at the language level for a
>> single-threaded program -- you simply have a hidden/system class like,
>> say, __SystemException from which Exception derives that be comes the
>> base class of all throwable objects.  __ExitException could then
>> derive from __SystemException and store the exit value.  But it is not
>> clear how this would work for multithreaded programs, with which I
>> have little experience in the context of C++ exceptions. Presumably,
>> the __ExitException would have to be thrown in all threads and could
>> interrupt functions that would otherwise not throw exceptions -- I
>> can't say I understand all the implications.
>
> It's more complicate than that. The base class of all throwable objects is
> Throwable. Error and Exception are derived from Throwable. Destructors, 
> finally
> blocks, and scope statements are all skipped when a Throwable is thrown unless
> it is derived from Exception. So, there is no proper cleanup unless an
> Exception is thrown. Right now, the compiler, the runtime, and programmers can
> all assume that
>
> try
> {
>    //code
>    //1
> }
> catch(Exception e)
> {
>    //2
> }
>
> either #1 or #2 will be hit in that code if proper cleanup is occuring. In
> fact nothrow relies on this. If you wrap a function call in a try-catch block
> which catches Exception, then the function it's called in can be nothrow even
> if the function being called throws an exception. If we tried to have another
> exception type which was for exiting, then you'd  get this weird situation
> where nothrow functions _can_ throw when the program is being shutdown
> properly, and that could be a big problem.
>
> Functions in D are set up around the idea that the only way to exit a function
> and have proper cleanup occur is to either return from it or have an Exception
> thrown from it. You're trying to have another way added. It's not that it's
> necessarily impossible, but it would likely require the redesign of several
> features and would break the assumptions made by a lot of code.
>
>> For cleanup that needs to be done no matter what the exception, I
>> would just use a finally{} block.
>
> Yes and no. finally gets hit whether an Exception is thrown or the try block 
> is
> exited normally, but it isn't run when a non-Exception Throwable (generally an
> Error) is thrown, so it gurantees nothing on unsafe shutdown. And if you were
> using exit, what would be the proper behavior? Neither the remainder of the
> try block nor the catch block would be run (since exit would skip the rest of
> the try block and skip the catch block entirely), which would likely break the
> assumptions made by a lot of code. It would certainly break scope. All of a
> sudden, you have something other than Error which won't hit scope(success) or
> scope(failure) but _will_ hit scope(exit), and that something is trying to be
> exiting _cleanly_ - unlike Error.
>
>> UTILITY: Now, the actual utility of having a safe exit seems to be in
>> question here. A common use of this is in OpenGL programs (that may be
>> implicitly multithreaded) where the keyboard handler exit()s when I
>> hit 'q' or ESC (which is quite common). Moreover, the underlying GUI
>> framework or other APIs being used may conceivably have multiple
>> threads and abstract this out for the user.  Is this an unreasonable
>> use case for a safe exit? Or would this be too difficult to implement
>> cleanly?
>
> Exceptions only affect a single thread, so they're not going to help you
> terminate a multi-threaded program regardless. And to terminate another
> thread, you need a way to terminate it. The only ways to do that are to tell
> them to terminate themselves or to kill them. There is no way that I'm aware
> of built into threads to tell them that it's time to shutdown and then let
> them do it cleanly (which is what you'd need for a clean shutdown). You could
> use std.concurrency to inform them to shutdown or have a shared flag which
> indicates that it's time for all threads to shutdown, but you couldn't use
> pthreads or the Windows equivalent to tell a thread to shutdown cleanly. So,
> the only means generally available to terminate a thread is to forcibly kill
> it (as C's exit does), making automatic cleanup impossible.
>
> _

Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-30 Thread Jonathan M Davis
On Friday, December 30, 2011 10:45:43 Ashish Myles wrote:
> Ok, now there are two issues here:
> IMPLEMENTATION: Implementation of a safe_exit() without an explicit
> Exception seems to be easy to do at the language level for a
> single-threaded program -- you simply have a hidden/system class like,
> say, __SystemException from which Exception derives that be comes the
> base class of all throwable objects.  __ExitException could then
> derive from __SystemException and store the exit value.  But it is not
> clear how this would work for multithreaded programs, with which I
> have little experience in the context of C++ exceptions. Presumably,
> the __ExitException would have to be thrown in all threads and could
> interrupt functions that would otherwise not throw exceptions -- I
> can't say I understand all the implications.

It's more complicate than that. The base class of all throwable objects is 
Throwable. Error and Exception are derived from Throwable. Destructors, finally 
blocks, and scope statements are all skipped when a Throwable is thrown unless 
it is derived from Exception. So, there is no proper cleanup unless an 
Exception is thrown. Right now, the compiler, the runtime, and programmers can 
all assume that

try
{
//code
//1
}
catch(Exception e)
{
//2
}

either #1 or #2 will be hit in that code if proper cleanup is occuring. In 
fact nothrow relies on this. If you wrap a function call in a try-catch block 
which catches Exception, then the function it's called in can be nothrow even 
if the function being called throws an exception. If we tried to have another 
exception type which was for exiting, then you'd  get this weird situation 
where nothrow functions _can_ throw when the program is being shutdown 
properly, and that could be a big problem.

Functions in D are set up around the idea that the only way to exit a function 
and have proper cleanup occur is to either return from it or have an Exception 
thrown from it. You're trying to have another way added. It's not that it's 
necessarily impossible, but it would likely require the redesign of several 
features and would break the assumptions made by a lot of code.

> For cleanup that needs to be done no matter what the exception, I
> would just use a finally{} block.

Yes and no. finally gets hit whether an Exception is thrown or the try block is 
exited normally, but it isn't run when a non-Exception Throwable (generally an 
Error) is thrown, so it gurantees nothing on unsafe shutdown. And if you were 
using exit, what would be the proper behavior? Neither the remainder of the 
try block nor the catch block would be run (since exit would skip the rest of 
the try block and skip the catch block entirely), which would likely break the 
assumptions made by a lot of code. It would certainly break scope. All of a 
sudden, you have something other than Error which won't hit scope(success) or 
scope(failure) but _will_ hit scope(exit), and that something is trying to be 
exiting _cleanly_ - unlike Error.

> UTILITY: Now, the actual utility of having a safe exit seems to be in
> question here. A common use of this is in OpenGL programs (that may be
> implicitly multithreaded) where the keyboard handler exit()s when I
> hit 'q' or ESC (which is quite common). Moreover, the underlying GUI
> framework or other APIs being used may conceivably have multiple
> threads and abstract this out for the user.  Is this an unreasonable
> use case for a safe exit? Or would this be too difficult to implement
> cleanly?

Exceptions only affect a single thread, so they're not going to help you 
terminate a multi-threaded program regardless. And to terminate another 
thread, you need a way to terminate it. The only ways to do that are to tell 
them to terminate themselves or to kill them. There is no way that I'm aware 
of built into threads to tell them that it's time to shutdown and then let 
them do it cleanly (which is what you'd need for a clean shutdown). You could 
use std.concurrency to inform them to shutdown or have a shared flag which 
indicates that it's time for all threads to shutdown, but you couldn't use 
pthreads or the Windows equivalent to tell a thread to shutdown cleanly. So, 
the only means generally available to terminate a thread is to forcibly kill 
it (as C's exit does), making automatic cleanup impossible.

_Some_ cleanup can be done when exit is called using atexit and on_exit, but 
the stack won't be unwound properly, so RAII, scope statements, and finally 
blocks aren't going to be run properly. So, critical, global stuff can be 
potentially cleaned up, but you can't get a fully clean shutdown without 
actually returning or having an Exception thrown from every function in every 
thread.

So, in general, the best way to handle taking down a multi

Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-30 Thread Ashish Myles
On Fri, Dec 30, 2011 at 5:43 AM, Jonathan M Davis  wrote:
> On Thursday, December 29, 2011 23:03:23 Ashish Myles wrote:
>> Since D
>> could conceivably implement a very safe exit() without an explicit use
>> of Exceptions to get around the "catch Exception() {}" problem you
>> mentioned above, does it make sense to request a safer exit() feature
>> for D?
>
> And how would it do that? The only way in the language to properly unwind the
> stack without returning from each and every function is to throw an Exception.
> If you wanted to do an exit function, it would somehow have to do the exact
> same thing that happens when you throw an Exception except that it's not an
> Exception and isn't caught by catch(Exception) {}. That may not be impossible,
> but I expect that it would complicate things quite a bit. And scope statements
> are designed around exceptions such that if you didn't throw an Exception,
> they wouldn't work properly. The same goes for finally blocks. Also, what is
> the correct thing to do in a situation like this
>

Ok, now there are two issues here:
IMPLEMENTATION: Implementation of a safe_exit() without an explicit
Exception seems to be easy to do at the language level for a
single-threaded program -- you simply have a hidden/system class like,
say, __SystemException from which Exception derives that be comes the
base class of all throwable objects.  __ExitException could then
derive from __SystemException and store the exit value.  But it is not
clear how this would work for multithreaded programs, with which I
have little experience in the context of C++ exceptions. Presumably,
the __ExitException would have to be thrown in all threads and could
interrupt functions that would otherwise not throw exceptions -- I
can't say I understand all the implications.

> try
> {
>    //code
> }
> catch(Exception e)
> {
>    //do stuff
> }
>
> The code in the catch  block assumes that it's always going to be run when the
> code in the try block is not properly completed. If an exit call were made
> from within the try block (be it directly in it or in a function that was
> called inside it), how would the catch block be handled? Without an Exception,
> it would be skipped, what's in that catch block wouldn't be run, and there
> would be no proper cleanup.
>

For cleanup that needs to be done no matter what the exception, I
would just use a finally{} block.

UTILITY: Now, the actual utility of having a safe exit seems to be in
question here. A common use of this is in OpenGL programs (that may be
implicitly multithreaded) where the keyboard handler exit()s when I
hit 'q' or ESC (which is quite common). Moreover, the underlying GUI
framework or other APIs being used may conceivably have multiple
threads and abstract this out for the user.  Is this an unreasonable
use case for a safe exit? Or would this be too difficult to implement
cleanly?


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-30 Thread Jonathan M Davis
On Thursday, December 29, 2011 23:03:23 Ashish Myles wrote:
> Since D
> could conceivably implement a very safe exit() without an explicit use
> of Exceptions to get around the "catch Exception() {}" problem you
> mentioned above, does it make sense to request a safer exit() feature
> for D?

And how would it do that? The only way in the language to properly unwind the 
stack without returning from each and every function is to throw an Exception. 
If you wanted to do an exit function, it would somehow have to do the exact 
same thing that happens when you throw an Exception except that it's not an 
Exception and isn't caught by catch(Exception) {}. That may not be impossible, 
but I expect that it would complicate things quite a bit. And scope statements 
are designed around exceptions such that if you didn't throw an Exception, 
they wouldn't work properly. The same goes for finally blocks. Also, what is 
the correct thing to do in a situation like this

try
{
//code
}
catch(Exception e)
{
//do stuff
}

The code in the catch  block assumes that it's always going to be run when the 
code in the try block is not properly completed. If an exit call were made 
from within the try block (be it directly in it or in a function that was 
called inside it), how would the catch block be handled? Without an Exception, 
it would be skipped, what's in that catch block wouldn't be run, and there 
would be no proper cleanup.

The very concept of exit violates how the language functions with regards to 
stack unwinding. Stack unwinding is built around how exceptions function. 
exit, on the other hand, tries to avoid the whole exception thing and just 
kill your program. But ultimately, you _can't_ ignore the fact that in order 
to ensure proper stack unwinding, you either need to return from each function 
on the stack, or throw an Exception from them. Anything else is going to fail 
to unwind the stack properly.

And honestly, I would generally consider it bad practice to use an exit 
function. It violates the proper flow of the program - as the issues with stack 
unwinding illustrate.

If you want to do the equivalent of an exit function and have proper cleanup 
occur, you really need to be throw an Exception designated for that and have 
your code let it pass all the way through to main so that it can exit properly 
after having unwound the stack.

- Jonathan M Davis


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Ashish Myles
On Thu, Dec 29, 2011 at 7:16 PM, Jonathan M Davis  wrote:
>
> A D exit function would have to do essentially the same thing as throw an
> exception and catch it in main anyway. The only way that the stack is going to
> be unwound properly is if you actually unwind it. The only way in the language
> to do that without actually returning from each and every function on the
> stack is to throw an exception.
>
> How many modern languages do you know of with an exit function that cleans
> everything up properly? C++ won't for the same reasons that D won't. Java gets
> away with it because it doesn't have destructors or scope statements or
> anything else that would actually require unwinding the stack.
>
> All a D exit function _could_ do would be to throw an exception and then have
> the runtime catch it - which still wouldn't work if the programmer was foolish
> enough to do something like
>
> catch(Exception) {}
>
> in their code. So, throwing an exception and catching it _is_ the way to do
> it, and it really makes more sense if you're doing it yourself, since then
> you're less likely to make that mistake and catch all Exceptions somewhere in
> your code and eat the one which is supposed to exit the program.
>
> - Jonathan M Davis

Hm...embarassingly, it didn't occur to me that C++ didn't clean up
either; but sure enough, the following code shows that exit() breaks
C++ RAII.

#include 
#include 

struct SafeExit {
~SafeExit() {
std::cout << "Safely exit with destructor." << std::endl;
}
};

int main(int argc, char** argv)
{
SafeExit safeExit;

std::cout << "Test if std.c.stdlib.exit() breaks RAII." << std::endl;
std::cout << "Pre-exit!" << std::endl;
exit(0);
std::cout << "Post-exit! Should not get here!" << std::endl;

return 0;
}

On the other hand, ruby happily *does* unwind the stack properly on exit().

def safe_exit
begin
yield
ensure
puts "Safely exit with ensure."
end
end

safe_exit do
puts "Test if std.c.stdlib.exit() breaks RAII."
puts "Pre-exit!"
exit(0);
puts "Post-exit! Should not get here!"
end

Honestly, I would rather have the latter robustness. While I have
always thought of abort() as being a dirty exit, I had, until now,
always thought of exit() as being very safe.  Violating RAII on a
safely-intended exit() is a really Bad Thing, I would think.  Since D
could conceivably implement a very safe exit() without an explicit use
of Exceptions to get around the "catch Exception() {}" problem you
mentioned above, does it make sense to request a safer exit() feature
for D?

Ashish


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Jonathan M Davis
On Thursday, December 29, 2011 13:43:36 Ashish Myles wrote:
> On Thu, Dec 29, 2011 at 1:26 PM, Andrej Mitrovic
> 
>  wrote:
> > Probably the easiest thing to do is to throw a custom exception and
> > catch it somewhere in main() to return your status code. Unlike
> > exit(), throwing will take care of RAII stuff.
> 
> Thanks, Andrej. That option had occurred to me, but I figured that
> shouldn't be the way to do things given that most other languages have
> a native exit function. Given that this code transformation isn't
> particularly difficult (put main in a try/catch, have a custom
> exception storing exit code, return the exit code in the catch block),
> would it be reasonable to do a feature request for a
> D-language-supported exit()?

A D exit function would have to do essentially the same thing as throw an 
exception and catch it in main anyway. The only way that the stack is going to 
be unwound properly is if you actually unwind it. The only way in the language 
to do that without actually returning from each and every function on the 
stack is to throw an exception.

How many modern languages do you know of with an exit function that cleans 
everything up properly? C++ won't for the same reasons that D won't. Java gets 
away with it because it doesn't have destructors or scope statements or 
anything else that would actually require unwinding the stack.

All a D exit function _could_ do would be to throw an exception and then have 
the runtime catch it - which still wouldn't work if the programmer was foolish 
enough to do something like

catch(Exception) {}

in their code. So, throwing an exception and catching it _is_ the way to do 
it, and it really makes more sense if you're doing it yourself, since then 
you're less likely to make that mistake and catch all Exceptions somewhere in 
your code and eat the one which is supposed to exit the program.

- Jonathan M Davis


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread AaronP

On 12/29/2011 12:43 PM, Ashish Myles wrote:

On Thu, Dec 29, 2011 at 1:26 PM, Andrej Mitrovic
  wrote:

Probably the easiest thing to do is to throw a custom exception and
catch it somewhere in main() to return your status code. Unlike
exit(), throwing will take care of RAII stuff.


Thanks, Andrej. That option had occurred to me, but I figured that
shouldn't be the way to do things given that most other languages have
a native exit function. Given that this code transformation isn't
particularly difficult (put main in a try/catch, have a custom
exception storing exit code, return the exit code in the catch block),
would it be reasonable to do a feature request for a
D-language-supported exit()?


Yeah, really. I'd been using the C exit() as well. Seems like a pretty 
fundamental feature. :O


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Jacob Carlborg

On 2011-12-29 18:22, Jakob Ovrum wrote:

On Thursday, 29 December 2011 at 16:27:33 UTC, Ashish Myles wrote:

std.c.stdlib.exit() seems to break RAII. The code below tests this
both using a struct destructor and an explicit scope(exit) {}. Is
this an intentional feature or a bug?

import std.stdio;
import std.c.stdlib;

void main()
{
struct SafeExit {
~this() {
writeln("Safely exit with destructor.");
}
}
SafeExit safeExit;

scope(exit) { writeln("Safely exit with scope(exit)."); }
scope(failure) { writeln("Safely exit with scope(failure)."); }

writeln("Test if std.c.stdlib.exit() breaks RAII.");
writeln("Pre-exit!");
std.c.stdlib.exit(0);
writeln("Post-exit! Should not get here!");
}


The C runtime is beyond D's immediate control. You would have to replace
C's exit function with a custom one or make the compiler recognize calls
to it.

Calling 'exit' doesn't properly shut down the D runtime either, it's not
just constructors.

It's neither a bug or a feature. The bug is arguably in your program.


Could druntime hook up on the atexit function to run destructors and 
similar when the program exits?


--
/Jacob Carlborg


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Ashish Myles
On Thu, Dec 29, 2011 at 1:26 PM, Andrej Mitrovic
 wrote:
> Probably the easiest thing to do is to throw a custom exception and
> catch it somewhere in main() to return your status code. Unlike
> exit(), throwing will take care of RAII stuff.

Thanks, Andrej. That option had occurred to me, but I figured that
shouldn't be the way to do things given that most other languages have
a native exit function. Given that this code transformation isn't
particularly difficult (put main in a try/catch, have a custom
exception storing exit code, return the exit code in the catch block),
would it be reasonable to do a feature request for a
D-language-supported exit()?


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Andrej Mitrovic
Probably the easiest thing to do is to throw a custom exception and
catch it somewhere in main() to return your status code. Unlike
exit(), throwing will take care of RAII stuff.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Ashish Myles
On Thu, Dec 29, 2011 at 12:22 PM, Jakob Ovrum  wrote:
> On Thursday, 29 December 2011 at 16:27:33 UTC, Ashish Myles wrote:
>>
>> std.c.stdlib.exit() seems to break RAII. The code below tests this
>> both using a struct destructor and an explicit scope(exit) {}.  Is
>> this an intentional feature or a bug?
>>
>> import std.stdio;
>> import std.c.stdlib;
>>
>> void main()
>> {
>>  struct SafeExit {
>>      ~this() {
>>          writeln("Safely exit with destructor.");
>>      }
>>  }
>>  SafeExit safeExit;
>>
>>  scope(exit) { writeln("Safely exit with scope(exit)."); }
>>  scope(failure) { writeln("Safely exit with scope(failure)."); }
>>
>>  writeln("Test if std.c.stdlib.exit() breaks RAII.");
>>  writeln("Pre-exit!");
>>  std.c.stdlib.exit(0);
>>  writeln("Post-exit! Should not get here!");
>> }
>
>
> The C runtime is beyond D's immediate control. You would have to replace C's
> exit function with a custom one or make the compiler recognize calls to it.
>
> Calling 'exit' doesn't properly shut down the D runtime either, it's not
> just constructors.
>
> It's neither a bug or a feature. The bug is arguably in your program.

In that case, what is the recommended way to exit a program from a
deeply nested level and also possibly specify a return value?

Ashish


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Jakob Ovrum

On Thursday, 29 December 2011 at 17:22:33 UTC, Jakob Ovrum wrote:
Calling 'exit' doesn't properly shut down the D runtime either, 
it's not just constructors.


I mean destructors*.


Re: Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Jakob Ovrum

On Thursday, 29 December 2011 at 16:27:33 UTC, Ashish Myles wrote:
std.c.stdlib.exit() seems to break RAII. The code below tests 
this
both using a struct destructor and an explicit scope(exit) {}.  
Is

this an intentional feature or a bug?

import std.stdio;
import std.c.stdlib;

void main()
{
  struct SafeExit {
  ~this() {
  writeln("Safely exit with destructor.");
  }
  }
  SafeExit safeExit;

  scope(exit) { writeln("Safely exit with scope(exit)."); }
  scope(failure) { writeln("Safely exit with scope(failure)."); 
}


  writeln("Test if std.c.stdlib.exit() breaks RAII.");
  writeln("Pre-exit!");
  std.c.stdlib.exit(0);
  writeln("Post-exit! Should not get here!");
}


The C runtime is beyond D's immediate control. You would have to 
replace C's exit function with a custom one or make the compiler 
recognize calls to it.


Calling 'exit' doesn't properly shut down the D runtime either, 
it's not just constructors.


It's neither a bug or a feature. The bug is arguably in your 
program.


Bug or feature? std.c.stdlib.exit() breaks RAII

2011-12-29 Thread Ashish Myles
std.c.stdlib.exit() seems to break RAII. The code below tests this
both using a struct destructor and an explicit scope(exit) {}.  Is
this an intentional feature or a bug?

import std.stdio;
import std.c.stdlib;

void main()
{
struct SafeExit {
~this() {
writeln("Safely exit with destructor.");
}
}
SafeExit safeExit;

scope(exit) { writeln("Safely exit with scope(exit)."); }
scope(failure) { writeln("Safely exit with scope(failure)."); }

writeln("Test if std.c.stdlib.exit() breaks RAII.");
writeln("Pre-exit!");
std.c.stdlib.exit(0);
writeln("Post-exit! Should not get here!");
}


Re: How to use structs for RAII?

2011-01-23 Thread Andrej Mitrovic
Ah, I keep forgetting about opCall. Nice tips there.


Re: How to use structs for RAII?

2011-01-23 Thread Jacob Carlborg

On 2011-01-23 01:14, Andrej Mitrovic wrote:

A workaround:

import std.stdio;
import std.exception;

struct A
{
 int x;

 this(void* none)
 {
 if (none !is null)
 {
 enforce(0, "Tried to pass a parameter to A's constructor");
 }

 writeln("in constructor");
 // construction from here..
 x = 5;
 }
}

void main()
{
 auto a = A(null);
}

I think that would be safe, and closest to a "default" constructor.


A static opCall would be better. See my answer to the original post.

--
/Jacob Carlborg


Re: How to use structs for RAII?

2011-01-23 Thread Jacob Carlborg

On 2011-01-23 00:03, Sean Eskapp wrote:

It was recommended to me to use structs for RAII instead of scope classes,
since scope is being removed (?). However, since default-constructors for
structs can't exist, how does one do this?


You can use a static opCall, like this:

struct Foo
{
static Foo opCall ()
{
Foo foo;
// initialize foo
return foo;
}
}

auto foo = Foo();

--
/Jacob Carlborg


Re: How to use structs for RAII?

2011-01-22 Thread Jonathan M Davis
On Saturday 22 January 2011 15:09:29 bearophile wrote:
> Sean Eskapp:
> > It was recommended to me to use structs for RAII instead of scope
> > classes, since scope is being removed (?). However, since
> > default-constructors for structs can't exist, how does one do this?
> 
> Inside the ~this() you may put code, to deallocate resources you have
> allocated in an explicit constructor (or in some creation method). Is this
> enough?

The typical thing to do when you want a default constructor for a struct is to 
use a static opCall(). Then, for struct S, you'd do

auto s = S();

If you did S s(), it still wouldn't work, so you might want to add an assertion 
in the destructor which verifes that the struct wasn't constructor with S.init, 
in which case what the destructor would be doing would likely be wrong. 
Personally, I _always_ declare struct variables in this form

auto s = S();

and never as

S s();

It avoids most of the problem with a struct's init value. But you can still get 
structs initialized to their init when they're in arrays and the like (which is 
a good part of the reason that init exists in the first place).

- Jonathan M Davis


Re: How to use structs for RAII?

2011-01-22 Thread Sean Eskapp
Actually this becomes rather annoying, since I can't use any closures on the
object. Stupidly, I can still use closures with an object which is deleted at 
the
end of the function.


Re: How to use structs for RAII?

2011-01-22 Thread Andrej Mitrovic
A workaround:

import std.stdio;
import std.exception;

struct A
{
int x;

this(void* none)
{
if (none !is null)
{
enforce(0, "Tried to pass a parameter to A's constructor");
}

writeln("in constructor");
// construction from here..
x = 5;
}
}

void main()
{
auto a = A(null);
}

I think that would be safe, and closest to a "default" constructor.


Re: How to use structs for RAII?

2011-01-22 Thread Sean Eskapp
== Quote from bearophile (bearophileh...@lycos.com)'s article
> Sean Eskapp:
> > It was recommended to me to use structs for RAII instead of scope classes,
> > since scope is being removed (?). However, since default-constructors for
> > structs can't exist, how does one do this?
> Inside the ~this() you may put code, to deallocate resources you have 
> allocated
in an explicit constructor (or in some creation method). Is this enough?
> Bye,
> bearophile

By explicit constructor, I assume you mean one with parameters? I guess that's
alright.


Re: How to use structs for RAII?

2011-01-22 Thread bearophile
Sean Eskapp:

> It was recommended to me to use structs for RAII instead of scope classes,
> since scope is being removed (?). However, since default-constructors for
> structs can't exist, how does one do this?

Inside the ~this() you may put code, to deallocate resources you have allocated 
in an explicit constructor (or in some creation method). Is this enough?

Bye,
bearophile


How to use structs for RAII?

2011-01-22 Thread Sean Eskapp
It was recommended to me to use structs for RAII instead of scope classes,
since scope is being removed (?). However, since default-constructors for
structs can't exist, how does one do this?


Re: Recommended way to do RAII cleanly

2010-07-12 Thread Jonathan M Davis
On Monday, July 12, 2010 18:15:04 Nick Sabalausky wrote:
> "torhu"  wrote in message
> news:i1ft84$2h4...@digitalmars.com...
> 
> > I think the conclusion is that RAII is less important in D than in C++.
> > In D you use scope (exit), or even finally, like in Java or Python. The
> > other use of scope, as a storage class, is supposed to go away, and I
> > suspect I'm not the only one who's going to miss it.
> 
> As good as scope guards are, anytime you have an object that has some sort
> of cleanup function that needs to be called when you're done with it, it's
> absurd to think that requiring the *user* of the object to use scope guards
> *by convention* is ever a satisfactory substitute for real RAII.
> 
> And I have to say, I'm rather disappointed to hear that scope objects are
> going away. What is the reason for that?

IIRC, Walter was of the opinion that you could do the same with structs without 
needing scope. And as long as you can default construct them or your RAII 
object 
requires arguments to its constructor, that's more or less true (if arguably 
limiting). The question, therefore is whether there is a means to effectively 
default construct structs which is not going to be deprecated. I'd still like 
scope to stick around (even if all it did was put the class on the heap as 
normal and called clear() on it when it left scope rather than putting it on 
the 
stack like I believe it does at the moment), but if structs can totally take 
care of the RAII issue, then it's not as bad. But the situation with structs 
and 
default constructors is a bit frustrating.

- Jonathan M Davis


Re: Recommended way to do RAII cleanly

2010-07-12 Thread Nick Sabalausky
"torhu"  wrote in message 
news:i1ft84$2h4...@digitalmars.com...
>
> I think the conclusion is that RAII is less important in D than in C++. In 
> D you use scope (exit), or even finally, like in Java or Python. The other 
> use of scope, as a storage class, is supposed to go away, and I suspect 
> I'm not the only one who's going to miss it.

As good as scope guards are, anytime you have an object that has some sort 
of cleanup function that needs to be called when you're done with it, it's 
absurd to think that requiring the *user* of the object to use scope guards 
*by convention* is ever a satisfactory substitute for real RAII.

And I have to say, I'm rather disappointed to hear that scope objects are 
going away. What is the reason for that? 




Re: Recommended way to do RAII cleanly

2010-07-12 Thread bearophile
torhu:
> I think that's supposed to go away, but I'm not 100% sure.  Would make 
> sense, since it was added as a sort of stopgap measure when there were 
> no struct literals.

Well, if you have found a use case for static opCall then it needs to be shown 
to the people that want to deprecate the static opCall, to ask for ways to 
replace its functionality.

Bye,
bearophile


Re: Recommended way to do RAII cleanly

2010-07-12 Thread Jonathan M Davis
On Monday, July 12, 2010 15:40:24 torhu wrote:
> On 13.07.2010 00:09, bearophile wrote:
> > Jonathan M Davis:
> >>  There are lots of cases where using scope(exit) makes sense, and it's a
> >>  great construct. But there are also plenty of cases where using plain
> >>  old RAII with a single declaration is better. It works fine in D as
> >>  long as the struct in question doesn't need a default constructor. But
> >>  if it does, then it becomes a problem.
> > 
> > Can't you use a static opCall (also suggested by Jacob Carlborg)?
> > 
> > Bye,
> > bearophile
> 
> I think that's supposed to go away, but I'm not 100% sure.  Would make
> sense, since it was added as a sort of stopgap measure when there were
> no struct literals.

This would be why I like Berophile's suggestion on the main list of having a 
page which lists deprecated and intended to be deprecated constructs. opCall is 
a good solution and basically fulfills the requirements of a default 
constructor, 
but if it's going away, then it's in the same camp as using scope on a class.

- Jonathan M Davis


Re: Recommended way to do RAII cleanly

2010-07-12 Thread torhu

On 13.07.2010 00:09, bearophile wrote:

Jonathan M Davis:

 There are lots of cases where using scope(exit) makes sense, and it's a great
 construct. But there are also plenty of cases where using plain old RAII with a
 single declaration is better. It works fine in D as long as the struct in
 question doesn't need a default constructor. But if it does, then it becomes a
 problem.


Can't you use a static opCall (also suggested by Jacob Carlborg)?

Bye,
bearophile


I think that's supposed to go away, but I'm not 100% sure.  Would make 
sense, since it was added as a sort of stopgap measure when there were 
no struct literals.


  1   2   >