View mode: basic / threaded / horizontal-split · Log in · Help
December 15, 2012
Re: Voldemort structs no longer work?
On Saturday, 15 December 2012 at 21:10:19 UTC, Jonathan M Davis 
wrote:
> On Saturday, December 15, 2012 12:18:21 H. S. Teoh wrote:
>> It seems that the only clean way to do this is to use a class 
>> instead of
>> a struct, since the .init value will conveniently just be 
>> null, thereby
>> sidestepping the problem.
>
> That would incur unnecessary overhead and probably break all 
> kinds of code,
> because they're then reference types instead of value types, 
> and a _lot_ of
> code doesn't use save propperly. If structs can't do what we 
> need as Voldemort
> types, it's just better to make it so that they're not 
> Voldemort types.
> Voldemort types are a cute idea, and in principle are great, 
> but I don't think
> that it's worth fighting to keep them if they have problems.
>
> - Jonathan M Davis

I always found them inconsistent with the behavior they have in 
classes (where no outer pointer is created).

This is a lot of work to do in the standard lib however.
December 15, 2012
Re: Voldemort structs no longer work?
On Sat, Dec 15, 2012 at 01:09:33PM -0800, Jonathan M Davis wrote:
> On Saturday, December 15, 2012 12:18:21 H. S. Teoh wrote:
> > It seems that the only clean way to do this is to use a class
> > instead of a struct, since the .init value will conveniently just be
> > null, thereby sidestepping the problem.
> 
> That would incur unnecessary overhead and probably break all kinds of
> code, because they're then reference types instead of value types, and
> a _lot_ of code doesn't use save propperly. If structs can't do what
> we need as Voldemort types, it's just better to make it so that
> they're not Voldemort types.  Voldemort types are a cute idea, and in
> principle are great, but I don't think that it's worth fighting to
> keep them if they have problems.
[...]

Well, the current way many Phobos ranges work, they're kind of
pseudo-Voldemort types (except they don't actually need/use the context
pointer):

	auto cycle(R)(R range) {
		struct CycleImpl {
			R r;
			this(R _r) { r = _r; }
			... // range methods
		}
		return CycleImpl(range);
	}

	auto r = cycle(myRange);

While it's true that you can write:

	typeof(cycle(myRange)) s;

and thereby break encapsulation, if someone is desperate enough to do
such things they probably have a good reason for it, and they should be
able to deal with the consequences too.

But anyway, thinking a bit more about the .init problem, couldn't we
just say that .init is not accessible outside the scope of the function
that defines the type, and therefore you cannot declare a variable of
that type (using typeof or whatever other workaround) without also
assigning it to an already-initialized instance of the type?

This way, the type still has an .init, except that it's only accessible
inside the function itself. Or are there unintended consequences here?


T

-- 
It is impossible to make anything foolproof because fools are so ingenious. -- Sammy
December 15, 2012
Re: Voldemort structs no longer work?
On Saturday, December 15, 2012 13:44:13 H. S. Teoh wrote:
> But anyway, thinking a bit more about the .init problem, couldn't we
> just say that .init is not accessible outside the scope of the function
> that defines the type, and therefore you cannot declare a variable of
> that type (using typeof or whatever other workaround) without also
> assigning it to an already-initialized instance of the type?
> 
> This way, the type still has an .init, except that it's only accessible
> inside the function itself. Or are there unintended consequences here?

That's pretty much how it is now. The problem is all of the stuff that requires 
.init. For instance, lots of template constraints and static if use .init to 
check stuff about a type. Not having an .init gets in the way of a lot of 
template metaprogramming. And sometimes, you have to have .init or some things 
are impossible.

For instance, takeNone will attempt to return an empty range of the given type 
(something which some algorithms need, or they won't work), and if the range 
doesn't have init or slicing, then it's forced to return the result of 
takeExactly, which is then a different range type. For some stuff, that's fine, 
for other stuff, that renders it unusable. I think that the only place that 
that affects Phobos at the moment is that you lose an optimization path in one 
of find's overloads, but I've been in other situations where I've had to make a 
range empty without changing its type and popping all of the elements off was 
unacceptable, and Voldemort types make that impossible.

We may be able to work around enough of the problems caused by a lack of a 
usable init property to be able to continue to use Voldemort types, but some 
issues can't be fixed with them (like that of takeNone), and until we do find a 
solution for even the problems that we can fix, the lack of an init property 
tends to be crippling for metaprogramming.

- Jonathan M Davis
December 15, 2012
Re: Voldemort structs no longer work?
On 12/15/2012 10:36 AM, H. S. Teoh wrote:
> With latest git dmd:
>
> 	auto makeVoldemort(int x) {
> 		struct Voldemort {
> 			@property int value() { return x; }
> 		}
> 		return Voldemort();
> 	}
> 	void main() {
> 		auto v = makeVoldemort();
> 		writeln(v.value);
> 	}
>
> Compile error:
>
> 	test.d(3): Error: function test.makeVoldemort.Voldemort.value cannot access frame of function test.makeVoldemort

This compiles if the @property is elided.

Definitely a bug.
December 16, 2012
Re: Voldemort structs no longer work?
Good finds.

The definition of a "nested struct" is not consistently or well 
defined, so there's no wonder it's not working as anyone expects.

--rt
December 16, 2012
Re: Voldemort structs no longer work?
On 12/15/2012 10:44 PM, H. S. Teoh wrote:
> ...
> This way, the type still has an .init, except that it's only accessible
> inside the function itself. Or are there unintended consequences here?
>

Lazy initialization of a member of such a type would require unsafe 
language features and not work in CTFE.
December 16, 2012
Re: Voldemort structs no longer work?
On Saturday, 15 December 2012 at 20:20:10 UTC, H. S. Teoh wrote:
> On Sat, Dec 15, 2012 at 12:02:16PM -0800, Jonathan M Davis 
> wrote:
>> On Saturday, December 15, 2012 11:45:10 H. S. Teoh wrote:
>> > Ironically enough, Andrei in the subsequent paragraph 
>> > discourages
>> > the use of such nested structs, whereas Walter's article 
>> > promotes
>> > the use of such Voldemort types as a "happy discovery". :)
>> 
>> No, the real irony is that it's Andrei who promoted them in 
>> the first
>> place. :)
>
> Heh. :)
>
>
>> We _are_ finding some serious issues with them though (e.g. 
>> they don't
>> work with init and apparently can't work with init), and there 
>> has
>> been some discussion of ditching them due to such issues, but 
>> no
>> consensus has been reached on that.
> [...]
>
> Hmm, that's true. They can't possibly work with init: if you do
> something like:
>
> 	auto func(int x) {
> 		struct V {
> 			@property int value() { return x; }
> 		}
> 		return V();
> 	}
> 	auto v = func(123);
> 	auto u = v.init;	// <-- what happens here?
> 	writeln(u.value);	// <-- and here?
>
> It seems that we'd have to make .init illegal on these Voldemort
> structs. But that breaks consistency with the rest of the 
> language that
> every type must have an .init value.
>
> Alternatively, .init can implicitly create a context where the 
> value of
> x is set to int.init. But this is unnecessary (it's supposed to 
> be a
> *Voldemort* type!) and very ugly (why are we creating a 
> function's local
> context when it isn't even being called?), not to mention 
> useless
> (u.value will return a nonsensical value).
>
> Or, perhaps a less intrusive workaround, is to have .init set 
> the hidden
> context pointer to null, and you'll get a null deference when 
> accessing
> u.value. Which is not pretty either, since no pointers or 
> references are
> apparent in V.value; it's implicit.
>
> It seems that the only clean way to do this is to use a class 
> instead of
> a struct, since the .init value will conveniently just be null, 
> thereby
> sidestepping the problem.
>
>
> T


	auto func(int x) {
		struct V {
			int value() { return x; }

			@property V init() { return this; }
		}

		return V();
	}
	auto v = func(123);
	auto u = v.init;	// <-- what happens here?
	auto x = u.value;
	writeln(x);

If you add an init property then it is not null. I'm not sure if 
this is the correct behavior as I just jumped into this 
discussion and I'm not sure if I understand exactly what the 
problem with these types of structs are. (as far as I can tell 
they simply let you pass "sets" of data from a function rather 
easily while also keeping the details hidden(impossible to 
directly instantiate the struct since it is hidden inside the 
func)

In any case, when stepping through the code above, I noticed that 
init being called but resulting in u.value throwing a null 
exception. so I added an init property to V and then got the 
expected behavior. Probably too easy to be the correct solution 
but who knows ;)
December 16, 2012
Re: Voldemort structs no longer work?
As an alternative possible solution,

The following allows efficient nested structs in classes:

http://dpaste.dzfl.pl/64025e0a

It is very similar to the idea of voldemort structs except that 
instead of outer being a function it is a class.

Therefore, it makes sense that one could simply use functors in 
replace of the functions to get the same behavior(I'm not sure if 
D supports functors yet as I haven't got that far but I imagine 
it does).

To be useful, of course, one would have to use static functors so 
instantiation would not be necessary and direct replacement could 
be observed only if functor notation is identical to function 
notation.
December 17, 2012
Re: Voldemort structs no longer work?
I have recently added a note about "init property is sometimes unsafe".

https://github.com/D-Programming-Language/d-programming-language.org/pull/201


To reduce the risk, I have proposed an enhancement for .init property usage.

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

Kenji Hara

2012/12/16 js.mdnq <js_adddot+mdng@gmail.com>

> On Saturday, 15 December 2012 at 20:20:10 UTC, H. S. Teoh wrote:
>
>> On Sat, Dec 15, 2012 at 12:02:16PM -0800, Jonathan M Davis wrote:
>>
>>> On Saturday, December 15, 2012 11:45:10 H. S. Teoh wrote:
>>> > Ironically enough, Andrei in the subsequent paragraph > discourages
>>> > the use of such nested structs, whereas Walter's article > promotes
>>> > the use of such Voldemort types as a "happy discovery". :)
>>>
>>> No, the real irony is that it's Andrei who promoted them in the first
>>> place. :)
>>>
>>
>> Heh. :)
>>
>>
>>
>>  We _are_ finding some serious issues with them though (e.g. they don't
>>> work with init and apparently can't work with init), and there has
>>> been some discussion of ditching them due to such issues, but no
>>> consensus has been reached on that.
>>>
>> [...]
>>
>>
>> Hmm, that's true. They can't possibly work with init: if you do
>> something like:
>>
>>         auto func(int x) {
>>                 struct V {
>>                         @property int value() { return x; }
>>                 }
>>                 return V();
>>         }
>>         auto v = func(123);
>>         auto u = v.init;        // <-- what happens here?
>>         writeln(u.value);       // <-- and here?
>>
>> It seems that we'd have to make .init illegal on these Voldemort
>> structs. But that breaks consistency with the rest of the language that
>> every type must have an .init value.
>>
>> Alternatively, .init can implicitly create a context where the value of
>> x is set to int.init. But this is unnecessary (it's supposed to be a
>> *Voldemort* type!) and very ugly (why are we creating a function's local
>> context when it isn't even being called?), not to mention useless
>> (u.value will return a nonsensical value).
>>
>> Or, perhaps a less intrusive workaround, is to have .init set the hidden
>> context pointer to null, and you'll get a null deference when accessing
>> u.value. Which is not pretty either, since no pointers or references are
>> apparent in V.value; it's implicit.
>>
>> It seems that the only clean way to do this is to use a class instead of
>> a struct, since the .init value will conveniently just be null, thereby
>> sidestepping the problem.
>>
>>
>> T
>>
>
>
>         auto func(int x) {
>                 struct V {
>                         int value() { return x; }
>
>                         @property V init() { return this; }
>
>                 }
>
>                 return V();
>         }
>         auto v = func(123);
>         auto u = v.init;        // <-- what happens here?
>         auto x = u.value;
>         writeln(x);
>
> If you add an init property then it is not null. I'm not sure if this is
> the correct behavior as I just jumped into this discussion and I'm not sure
> if I understand exactly what the problem with these types of structs are.
> (as far as I can tell they simply let you pass "sets" of data from a
> function rather easily while also keeping the details hidden(impossible to
> directly instantiate the struct since it is hidden inside the func)
>
> In any case, when stepping through the code above, I noticed that init
> being called but resulting in u.value throwing a null exception. so I added
> an init property to V and then got the expected behavior. Probably too easy
> to be the correct solution but who knows ;)
>
Next ›   Last »
1 2
Top | Discussion index | About this forum | D home