Re: #dbugfix 17592

2018-03-23 Thread Jonathan M Davis via Digitalmars-d
On Friday, March 23, 2018 16:18:14 H. S. Teoh via Digitalmars-d wrote:
> On Fri, Mar 23, 2018 at 10:40:36PM +, 12345swordy via Digitalmars-d 
wrote:
> > On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
> > > On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d 
wrote:
> > > > [...]
> > >
> > > Walter and Andrei have been discussing putting together a DIP with a
> > > "ProtoObject" which will be the new root class below Object where
> > > ProtoObject itself has only the bare minimum required to work as a
> > > class (not monitor object, no toString, no opEquals, etc.). Classes
> > > could then derive from ProtoObject directly instead of from Object,
> > > and then they could define any of the functions that are currently
> > > on Object with whatever attributes they wanted (or not define them
> > > at all). The DIP has not yet been written, and the details still
> > > need to be ironed out, but that's the gist of the direction that's
> > > currently being considered.
> > >
> > > - Jonathan M Davis
> >
> > That what I have read from github. However the disadvantage of this is
> > that you can not longer make assumptions of what default methods that
> > they support.
>
> I don't think that's a problem.  I presume the default would still be to
> inherit from Object when the class declaration doesn't explicitly
> specify ProtoObject.  The assumption that any Object has toString, etc.,
> would still hold for all existing code. ProtoObject would (almost) be
> like a separate hierarchy altogether.

Yeah. The fact that Object has those functions has been a huge liability,
and with templates, it's completely unnecessary to have them on Object for
stuff like containers to work. Any code that needed to depend on a
particular set of functions in a base class would need to use whatever that
base class was, but then each code base could define that hierarchy base on
what made sense for it rather than forcing one set of attributes on the
entire language. Existing code that used Object in that fashion would
continue to work.

> The only potential problem I can see is that some code that used to test
> for `is(T == class)` may now have to be changed to `is(T : Object)` if
> the purpose of the test was to check whether Object methods like
> toString, etc., are available.

Presumably, that will have to be covered as part of the DIP. I don't know
how big a risk such issues pose, but they will have to be explored.

Overall though, if we go with something like ProtoObject, it will solve a
lot of the problems that we've had with Object. Several years ago, we
decided that the various functions on Object should be removed, because they
were causing too much trouble, but for various reasons, that's never
happened even though it was agreed that that was the best way to go.
ProtoObject would essentially be a way to go that route without actually
breaking Object.

Regardless, remember that nothing here is definitive yet. ProtoObject is
just the direction that Andrei would like to take things, and Walter has
agreed that we should have a DIP that explores the options appropriately.
The details are still very much in flux. So, we'll have to wait and see, but
I think that this is a promising turn of events.

- Jonathan M Davis



Re: #dbugfix 17592

2018-03-23 Thread Jonathan M Davis via Digitalmars-d
On Friday, March 23, 2018 22:33:53 jmh530 via Digitalmars-d wrote:
> On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
> > [snip]
> >
> > Walter and Andrei have been discussing putting together a DIP
> > with a "ProtoObject" which will be the new root class below
> > Object where ProtoObject itself has only the bare minimum
> > required to work as a class (not monitor object, no toString,
> > no opEquals, etc.). Classes could then derive from ProtoObject
> > directly instead of from Object, and then they could define any
> > of the functions that are currently on Object with whatever
> > attributes they wanted (or not define them at all). The DIP has
> > not yet been written, and the details still need to be ironed
> > out, but that's the gist of the direction that's currently
> > being considered.
> >
> > - Jonathan M Davis
>
> Object would derive from ProtoObject, right?

That would be the idea. That way, if all goes well, no code would break, and
hopefully, over time, Object would be treated as legacy and phased out of
use (though Andrei has stated that it's not his plan that Object actually be
deprecated). Newer code would derive from ProtoObject rather than Object,
and we'd have the flexibility with the functions that come from Object that
we've wanted for years, because then they can be defined as appropriate by
sub-classes of ProtoObject.

- Jonathan M Davis



Re: #dbugfix 17592

2018-03-23 Thread H. S. Teoh via Digitalmars-d
On Fri, Mar 23, 2018 at 10:40:36PM +, 12345swordy via Digitalmars-d wrote:
> On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
> > On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d wrote:
> > > [...]
> > 
> > Walter and Andrei have been discussing putting together a DIP with a
> > "ProtoObject" which will be the new root class below Object where
> > ProtoObject itself has only the bare minimum required to work as a
> > class (not monitor object, no toString, no opEquals, etc.). Classes
> > could then derive from ProtoObject directly instead of from Object,
> > and then they could define any of the functions that are currently
> > on Object with whatever attributes they wanted (or not define them
> > at all). The DIP has not yet been written, and the details still
> > need to be ironed out, but that's the gist of the direction that's
> > currently being considered.
> > 
> > - Jonathan M Davis
> 
> That what I have read from github. However the disadvantage of this is
> that you can not longer make assumptions of what default methods that
> they support.

I don't think that's a problem.  I presume the default would still be to
inherit from Object when the class declaration doesn't explicitly
specify ProtoObject.  The assumption that any Object has toString, etc.,
would still hold for all existing code. ProtoObject would (almost) be
like a separate hierarchy altogether.

The only potential problem I can see is that some code that used to test
for `is(T == class)` may now have to be changed to `is(T : Object)` if
the purpose of the test was to check whether Object methods like
toString, etc., are available.


T

-- 
Gone Chopin. Bach in a minuet.


Re: #dbugfix 17592

2018-03-23 Thread 12345swordy via Digitalmars-d

On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:
On Friday, March 23, 2018 21:45:14 12345swordy via 
Digitalmars-d wrote:

[...]


Walter and Andrei have been discussing putting together a DIP 
with a "ProtoObject" which will be the new root class below 
Object where ProtoObject itself has only the bare minimum 
required to work as a class (not monitor object, no toString, 
no opEquals, etc.). Classes could then derive from ProtoObject 
directly instead of from Object, and then they could define any 
of the functions that are currently on Object with whatever 
attributes they wanted (or not define them at all). The DIP has 
not yet been written, and the details still need to be ironed 
out, but that's the gist of the direction that's currently 
being considered.


- Jonathan M Davis


That what I have read from github. However the disadvantage of 
this is that you can not longer make assumptions of what default 
methods that they support.


Re: #dbugfix 17592

2018-03-23 Thread jmh530 via Digitalmars-d

On Friday, 23 March 2018 at 21:55:52 UTC, Jonathan M Davis wrote:

[snip]

Walter and Andrei have been discussing putting together a DIP 
with a "ProtoObject" which will be the new root class below 
Object where ProtoObject itself has only the bare minimum 
required to work as a class (not monitor object, no toString, 
no opEquals, etc.). Classes could then derive from ProtoObject 
directly instead of from Object, and then they could define any 
of the functions that are currently on Object with whatever 
attributes they wanted (or not define them at all). The DIP has 
not yet been written, and the details still need to be ironed 
out, but that's the gist of the direction that's currently 
being considered.


- Jonathan M Davis


Object would derive from ProtoObject, right?


Re: #dbugfix 17592

2018-03-23 Thread H. S. Teoh via Digitalmars-d
On Fri, Mar 23, 2018 at 03:55:52PM -0600, Jonathan M Davis via Digitalmars-d 
wrote:
[...]
> Walter and Andrei have been discussing putting together a DIP with a
> "ProtoObject" which will be the new root class below Object where
> ProtoObject itself has only the bare minimum required to work as a
> class (not monitor object, no toString, no opEquals, etc.). Classes
> could then derive from ProtoObject directly instead of from Object,
> and then they could define any of the functions that are currently on
> Object with whatever attributes they wanted (or not define them at
> all).

Woo!  Now *this* is good news indeed!  A lot of my current code that
uses classes would actually benefit from inheriting directly from
ProtoObject as opposed to Object, since I don't need the monitor object,
and don't really need a unified toString/opEquals/etc., either, since if
they are needed for a particular class hierarchy I'd just declare them
(with the right attributes!) in the base class.  So they can be pure,
@nogc, whatever, without worrying about conflicts with the current
definition of Object.


> The DIP has not yet been written, and the details still need to be
> ironed out, but that's the gist of the direction that's currently
> being considered.
[...]

*This* is going to be a DIP I look forward to!


T

-- 
What do you get if you drop a piano down a mineshaft? A flat minor.


Re: #dbugfix 17592

2018-03-23 Thread Jonathan M Davis via Digitalmars-d
On Friday, March 23, 2018 21:45:14 12345swordy via Digitalmars-d wrote:
> On Friday, 23 March 2018 at 18:40:45 UTC, jmh530 wrote:
> > On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:
> >> [snip]
> >>
> >> I don't say that's the solution. I think there's no solution.
> >
> > I'm not sure there's no solution, but there's definitely no
> > EASY solution. And when I say solution, I don't mean a
> > resolution of this specific issue. I mean to resolve the
> > fundamental issue, which is being able to clean up memory in
> > betterC or @nogc.
>
> Can we create new type of classes that combines system attributes
> with classes?
> Creating new keywords like nogcclass, safeclass by doing this.
> Which, take nogcclass for example, automatically adds @nogc
> attribute to every function including .objects functions, which
> can not be removed. That way we avoid breaking backwards
> compatibility with the usage of default class by introducing new
> strict subset of classes.
>
> I am thinking writing a dip that goes into detail.

Walter and Andrei have been discussing putting together a DIP with a
"ProtoObject" which will be the new root class below Object where
ProtoObject itself has only the bare minimum required to work as a class
(not monitor object, no toString, no opEquals, etc.). Classes could then
derive from ProtoObject directly instead of from Object, and then they could
define any of the functions that are currently on Object with whatever
attributes they wanted (or not define them at all). The DIP has not yet been
written, and the details still need to be ironed out, but that's the gist of
the direction that's currently being considered.

- Jonathan M Davis



Re: #dbugfix 17592

2018-03-23 Thread 12345swordy via Digitalmars-d

On Friday, 23 March 2018 at 18:40:45 UTC, jmh530 wrote:

On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:

[snip]

I don't say that's the solution. I think there's no solution.


I'm not sure there's no solution, but there's definitely no 
EASY solution. And when I say solution, I don't mean a 
resolution of this specific issue. I mean to resolve the 
fundamental issue, which is being able to clean up memory in 
betterC or @nogc.


Can we create new type of classes that combines system attributes 
with classes?
Creating new keywords like nogcclass, safeclass by doing this. 
Which, take nogcclass for example, automatically adds @nogc 
attribute to every function including .objects functions, which 
can not be removed. That way we avoid breaking backwards 
compatibility with the usage of default class by introducing new 
strict subset of classes.


I am thinking writing a dip that goes into detail.



Re: #dbugfix 17592

2018-03-23 Thread jmh530 via Digitalmars-d

On Thursday, 22 March 2018 at 21:37:40 UTC, Basile B. wrote:

[snip]

I don't say that's the solution. I think there's no solution.


I'm not sure there's no solution, but there's definitely no EASY 
solution. And when I say solution, I don't mean a resolution of 
this specific issue. I mean to resolve the fundamental issue, 
which is being able to clean up memory in betterC or @nogc.


There was a discussion last year [1] about adding destructors. 
According to the spec, class destructors were deprecated in D2, 
though confusingly I can't write a void delete() {} function, 
only delete(void*) {}. The delete function (outside of a class) 
is deprecated in 2.079 though. I'd guess that if deterministic 
destructors are added to the language, then this() and this() 
@nogc inheritance becomes much less of an issue.



[1]https://forum.dlang.org/thread/blbydqiupdtmgdunj...@forum.dlang.org?page=1


Re: #dbugfix 17592

2018-03-22 Thread Basile B. via Digitalmars-d

On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
This is very important to me as I am very interested in using 
the language for game development.


Yes I know that it's marked as "Duplicated", but I strongly 
disagree as it is different enough to consider is own issue.


Alex


Here's something you can study. It's the only solution i've found 
so far and it's implemented in my user library called "IZ" 
(https://github.com/BBasile/iz). You can run the stuff simply by 
passing it as a file name to DUB (aka single file package):


```
/+dub.sdl:
name "destruct_demo"
dependency "iz" version="*"
+/
module runnable;

import std.stdio, iz.memory, iz.enumset;

enum Foo {f1,f2,f3}
alias SetOfFoo = EnumSet!(Foo,Set8);
SetOfFoo foos;

class Foo1
{
this() @nogc {foos = 0;}
mixin inheritedDtor;
~this() @nogc
{
foos.include(Foo.f1);
callInheritedDtor();
}
}

class Foo2 : Foo1
{
mixin inheritedDtor;
~this() @nogc
{
foos.include(Foo.f2);
callInheritedDtor();
}
}

class Foo3 : Foo2
{
mixin inheritedDtor;
~this() @nogc
{
foos.include(Foo.f3);
callInheritedDtor();
}
}

void testTrustedStaticType() @nogc
{
Foo1 f1 = construct!Foo3;
assert(foos.none);
destruct(f1);
// destruct trusts f1 static type, which is wrong
// with a dynamic destruct() we should get [Foo.f1, Foo.f2, 
Foo.f3]

assert(foos == SetOfFoo(Foo.f1));

Foo3 f3 = construct!Foo3;
assert(foos.none);
destruct(f3);
// destruct trusts f3 static type, which is right
assert(foos == SetOfFoo(Foo.f1, Foo.f2, Foo.f3));
}

void testDynamicType() // cant be @nogc
{
Foo1 f1 = construct!Foo3;
assert(foos.none);
destruct(cast(Object) f1);
// an Object is passed to "destruct" which means "detect 
dynamic type"

assert(foos == [Foo.f1, Foo.f2, Foo.f3]);

Foo1 f2 = construct!Foo3;
assert(foos.none);
destruct(cast(Object) f2);
// an Object is passed to "destruct" which means "detect 
dynamic type"

assert(foos == [Foo.f1, Foo.f2, Foo.f3]);
}

void main()
{
testTrustedStaticType();
testDynamicType();
}
```

Important points:
- not compatible with D runtime
- use mixins to overcome the fact that destructor are not virtual 
(it's a lie)

- to be @nogc, the static type has to be known, really.


Re: #dbugfix 17592

2018-03-22 Thread Basile B. via Digitalmars-d

On Thursday, 22 March 2018 at 20:25:28 UTC, jmh530 wrote:
On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe 
wrote:


In Simen's example, the child information is not available at 
compile time. This line here:


A a = new B();

discards the static type. The compiler could probably cheat 
and figure it out anyway in this example, but suppose:


[snip]


There are a few interesting things in the class destructor part 
of the spec.


For instance:
"There can be only one destructor per class, the destructor 
does not have any parameters, and has no attributes. It is 
always virtual."


Reality is very different. The __ctbl is NOT USED AT ALL to call 
the __dtor.



If the destructor has no attributes, how can it be @nogc?

Also:
"The destructor for the super class automatically gets called 
when the destructor ends. There is no way to call the super 
destructor explicitly."


Reality is different. One can play with the __dtor member.
This is what i do in IZ.

- `destruct!(MyDerived)(myDerived)`: this has for effect to trust 
the static type that's passed to destruct(). That way destruct 
can be really @nogc.
- `destruct!(Object)(cast(Object)myDerived)`: this has for effect 
to use the dunamic type (i.e with typeid() i get the type info 
that contains a pointer to the __dtor, which CANT be @nogc. This 
is equivalent to official destroy().


In both case i also use a mixin called `inheritedDtor` which, 
contrary to what is stated in the specs, allowd to call 
explicitly the super __dtor.


I don't say that's the solution. I think there's no solution. 
What i do is not clean. It only works with displine and inside a 
particular library.

I'm gonna post a DUB script as POC later.



Re: #dbugfix 17592

2018-03-22 Thread 12345swordy via Digitalmars-d

On Thursday, 22 March 2018 at 19:52:43 UTC, Adam D Ruppe wrote:

On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:

"C++ classes and COM classes will still work"


Because they have external runtimes that get used.

You are moving goal post here.



I can tell that you're being snarky at me.


If you change .destroy without changing the destructor rule, 
the type system has been BROKEN. They MUST change together or 
all the "guarantees" are shot.


A warning doesn't change this. The code is still broken.


Ok fine, I admit my solution have it's own set of problems. 
Still, the lack of @nogc @pure etc class deallocation is a severe 
issue for which is a major blocking point for me on creating 
video games without using the GC on the d language. I am 
certainly not going to resorting to hacking by forcing my custom 
dealloaction function for classes a @nogc attribute as that 
undermines the verification aspect of the attribute.


Re: #dbugfix 17592

2018-03-22 Thread jmh530 via Digitalmars-d

On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe wrote:


In Simen's example, the child information is not available at 
compile time. This line here:


A a = new B();

discards the static type. The compiler could probably cheat and 
figure it out anyway in this example, but suppose:


[snip]


There are a few interesting things in the class destructor part 
of the spec.


For instance:
"There can be only one destructor per class, the destructor does 
not have any parameters, and has no attributes. It is always 
virtual."

If the destructor has no attributes, how can it be @nogc?

Also:
"The destructor for the super class automatically gets called 
when the destructor ends. There is no way to call the super 
destructor explicitly."
This means that you can't write something like below. Actually 
below gives the correct error. The problem is that if you remove 
the @nogc on A, then the result is wonky (and no compile-time 
error) and if they both have @nogc then you can't call destroy.


import std.stdio : writeln;

class A
{
@nogc ~this()
{
writeln("destroy A");
}
}

class B : A
{
~this()
{
writeln("destroy B");
destroy(super);
}
}

void main()
{
A a = new B;
}


Re: #dbugfix 17592

2018-03-22 Thread Adam D Ruppe via Digitalmars-d

On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:

"C++ classes and COM classes will still work"


Because they have external runtimes that get used.


I can tell that you're being snarky at me.


If you change .destroy without changing the destructor rule, the 
type system has been BROKEN. They MUST change together or all the 
"guarantees" are shot.


A warning doesn't change this. The code is still broken.


Re: #dbugfix 17592

2018-03-22 Thread 12345swordy via Digitalmars-d

On Thursday, 22 March 2018 at 19:21:57 UTC, Basile B. wrote:

No D classes requires D TypeInfo, not available in BetterC.
It's well C++ classes ;)


I was referring to the consequence section in the betterC article 
that he had linked.


Re: #dbugfix 17592

2018-03-22 Thread Basile B. via Digitalmars-d

On Thursday, 22 March 2018 at 19:20:14 UTC, 12345swordy wrote:

On Thursday, 22 March 2018 at 17:02:43 UTC, Adam D. Ruppe wrote:

On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
That is not a runtime version of system/user attributes! That 
is custom checking for destructor! Hardly the same.


How would your idea work?


I thought it was your idea.

Classes in fact do not work with -betterC. 
https://dlang.org/spec/betterc.html#consequences


"C++ classes and COM classes will still work"
https://dlang.org/blog/2017/08/23/d-as-a-better-c/
A bit misleading in that statement. It should be "D Classes".



No D classes requires D TypeInfo, not available in BetterC.
It's well C++ classes ;)

Warning: your code is fundamentally broken and cannot work the 
way you want it to work.


I can tell that you're being snarky at me.





Re: #dbugfix 17592

2018-03-22 Thread 12345swordy via Digitalmars-d

On Thursday, 22 March 2018 at 17:02:43 UTC, Adam D. Ruppe wrote:

On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
That is not a runtime version of system/user attributes! That 
is custom checking for destructor! Hardly the same.


How would your idea work?


I thought it was your idea.

Classes in fact do not work with -betterC. 
https://dlang.org/spec/betterc.html#consequences


"C++ classes and COM classes will still work"
https://dlang.org/blog/2017/08/23/d-as-a-better-c/
A bit misleading in that statement. It should be "D Classes".


Warning: your code is fundamentally broken and cannot work the 
way you want it to work.


I can tell that you're being snarky at me.


Re: #dbugfix 17592

2018-03-22 Thread Simen Kjærås via Digitalmars-d

On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:

On Thursday, 22 March 2018 at 02:35:41 UTC, Adam D. Ruppe wrote:

On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
Are you suggesting that we need runtime version of 
system/user attributes?


We already have that in a sense - InvalidMemoryOperationError 
is thrown if you try to GC allocate from inside a GC 
destructor. The attributes are supposed to render such runtime 
errors impossible, catching them at compile time instead.


That is not a runtime version of system/user attributes! That 
is custom checking for destructor! Hardly the same.


If I understand correctly, you envision a system where all or 
some GC operations would check the call stack to see if there are 
any @nogc functions there (the implementation might be different, 
but that would be my conceptual design). This seems like a 
possible design, but one that pessimizes the happy path to the 
detriment of everyone.



This is the reason why all D classes have a vtable attached 
(with attached runtime type info).
C++ classes also have vtables which are typically implemented 
as static arrays at compile time.


Again I do not see it anywhere in the specification that 
support your claim that all classes are dynamic. Otherwise if 
what your saying is true then you should unable to use classes 
in Better C mode, as that involves runtime.


Classes in D are dynamic in the same case that classes in C++, 
Java, C# or many other languages are dynamic - a reference to a 
base class might actually point to a derived class, and there's 
no way to know at compile-time what's actually hiding behind that 
reference. That's how it's been meant all through this thread, 
but it seems a misunderstanding has crept in.


In this case:

class A {}
class B : A {}

A var = new B();

var's *static* type is A. That's what typeof(var) will return, 
and it's the type the compiler knows about. It's the type for 
which we can look at the destructor at compile-time and say 'we 
cannot do this in a @nogc function'.


On the other side, var's *dynamic* type is B. If instead of 'new 
B()', there was an opaque function call, it's impossible to know 
the dynamic type until run-time, and there's not even a point 
where we can give the warning message you suggest.


--
  Simen


Re: #dbugfix 17592

2018-03-22 Thread Adam D. Ruppe via Digitalmars-d

On Thursday, 22 March 2018 at 14:48:04 UTC, 12345swordy wrote:
That is not a runtime version of system/user attributes! That 
is custom checking for destructor! Hardly the same.


How would your idea work?

Again I do not see it anywhere in the specification that 
support your claim that all classes are dynamic. Otherwise if 
what your saying is true then you should unable to use classes 
in Better C mode, as that involves runtime.


Classes in fact do not work with -betterC. 
https://dlang.org/spec/betterc.html#consequences


(Note that you CAN make D classes work with a minimal runtime 
though... but a runtime nonetheless.)



I am asking to produce a WARNING message here.


Warning: your code is fundamentally broken and cannot work the 
way you want it to work.


Re: #dbugfix 17592

2018-03-22 Thread 12345swordy via Digitalmars-d

On Thursday, 22 March 2018 at 02:35:41 UTC, Adam D. Ruppe wrote:

On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
Are you suggesting that we need runtime version of system/user 
attributes?


We already have that in a sense - InvalidMemoryOperationError 
is thrown if you try to GC allocate from inside a GC 
destructor. The attributes are supposed to render such runtime 
errors impossible, catching them at compile time instead.


That is not a runtime version of system/user attributes! That is 
custom checking for destructor! Hardly the same.

All classes are dynamic types


I do not see it anywhere in the dlang specification that 
supports your claim.

https://dlang.org/spec/class.html


This is the reason why all D classes have a vtable attached 
(with attached runtime type info).
C++ classes also have vtables which are typically implemented as 
static arrays at compile time.


Again I do not see it anywhere in the specification that support 
your claim that all classes are dynamic. Otherwise if what your 
saying is true then you should unable to use classes in Better C 
mode, as that involves runtime.
Why can't it produce a warning message regarding implied 
classes conversion if it detects mismatch attributes?


The entire purpose of OOP inheritance
I think you do not understand the question that I am asking. I am 
not asking to produce an ERROR message here, I am asking to 
produce a WARNING message here. We are dealing with the 
possibility of mismatch attributes, which  seriously can cause 
some nasty bugs to leak, without the programmer noticing.




Re: #dbugfix 17592

2018-03-21 Thread Adam D. Ruppe via Digitalmars-d

On Thursday, 22 March 2018 at 01:55:48 UTC, 12345swordy wrote:
Are you suggesting that we need runtime version of system/user 
attributes?


We already have that in a sense - InvalidMemoryOperationError is 
thrown if you try to GC allocate from inside a GC destructor. The 
attributes are supposed to render such runtime errors impossible, 
catching them at compile time instead.



All classes are dynamic types


I do not see it anywhere in the dlang specification that 
supports your claim.

https://dlang.org/spec/class.html


This is the reason why all D classes have a vtable attached (with 
attached runtime type info). *All* class-specific features are 
centered around this - casts use rtti, inheritance and interfaces 
use the vtable. It is the reason why D classes are reference 
types - otherwise, when you substitute it, you'd risk slicing the 
object.


If you took the dynamic aspect out of classes, you'd have an 
entirely different animal... the thing D calls a "struct".


Why can't it produce a warning message regarding implied 
classes conversion if it detects mismatch attributes?


The entire purpose of OOP inheritance existing is the 
substitution principle, that subclasses can take the place of 
base classes transparently. This is an either-or situation: if we 
want to keep the current definition of classes, bug 17592 MUST be 
closed as "wontfix" as it is by design to maintain 
substitutiability.


If we want to fix #17592, we MUST redefine the language's 
definition of class destructors to follow inheritance-style rules 
on matching attribute (even if they are actually implemented as a 
chain), again to guarantee substitutability is not broken.


There's no middle ground possible.


Re: #dbugfix 17592

2018-03-21 Thread Adam D. Ruppe via Digitalmars-d

On Thursday, 22 March 2018 at 02:16:56 UTC, SimonN wrote:

Does the compiler infer nogc-ness of `emplace` at instantiation?


Yes, it does with all templates, actually. Since their nogcness 
(and other attributes like nothrow, pure, etc) frequently depend 
on what arguments they are passed, the compiler will infer it at 
instantiation.


Putting the explicit attribute on a template forces it to be such 
- then it will reject non-matching arguments (e.g. @nogc emplace 
would be a compile error if passed a gc constructor, regardless 
of if it is used in a gc or nogc context. without the explicit 
attribute, the compiler infers it and thus only throws the error 
if used in an actual nogc context).


My first hunch was that B's yes-gc-destructor should be illegal 
when A's descructor is `@nogc`, but it can be legal because 
destructors in a hierarchy are chained, not overridden. Seems 
like there is no way to ensure at child-class-compile-time that 
all child classes of A must be designed `@nogc`.


Right. That's the key problem to @nogc destroy and why we can't 
fix it in the library - it would require a language chance to 
force subclass dtors to have the same attribute set as the base 
class, as if they were overridden virtual inherited members.


Re: #dbugfix 17592

2018-03-21 Thread SimonN via Digitalmars-d

On Wednesday, 21 March 2018 at 13:55:16 UTC, Adam D. Ruppe wrote:
`emplace` is ALREADY `@nogc`

Interesting -- I checked the phobos source, and none of the 
`emplace` or `emplaceRef` are declared `@nogc`, yet the unittests 
marked as `@nogc` pass.


Does the compiler infer nogc-ness of `emplace` at instantiation?


class A { @nogc ~this() {} }
class B : A { ~this() {} }


My first hunch was that B's yes-gc-destructor should be illegal 
when A's descructor is `@nogc`, but it can be legal because 
destructors in a hierarchy are chained, not overridden. Seems 
like there is no way to ensure at child-class-compile-time that 
all child classes of A must be designed `@nogc`.


-- Simon


Re: #dbugfix 17592

2018-03-21 Thread 12345swordy via Digitalmars-d

On Thursday, 22 March 2018 at 01:09:56 UTC, Adam D. Ruppe wrote:


But @nogc is a compile time thing, meaning it cannot work here.


Are you suggesting that we need runtime version of system/user 
attributes?



All classes are dynamic types


I do not see it anywhere in the dlang specification that supports 
your claim.

https://dlang.org/spec/class.html

Why can't it produce a warning message regarding implied classes 
conversion if it detects mismatch attributes? The risk of 
information exist when making certain dynamic type conversion. I 
do not see for any reason why they can't be warning messages 
regarding the possibility of losing information when making 
implied type conversions. There even a DIP pull request consist 
of deprecating a certain type conversion, because of certain bugs 
detected.


Re: #dbugfix 17592

2018-03-21 Thread Adam D. Ruppe via Digitalmars-d

On Wednesday, 21 March 2018 at 19:21:15 UTC, 12345swordy wrote:
That seems to be it's own separate problem, as it involves 
generating dynamic types at run-time, which it needs run-time 
equivalent of attribute checking.


But @nogc is a compile time thing, meaning it cannot work here.

My example assumes that the classes created are static types 
not dynamic types. Besides I do not like implied conversions 
when it comes classes, as I believe it is a horrible idea.


All classes are dynamic types, this is their reason for existing!


Re: #dbugfix 17592

2018-03-21 Thread 12345swordy via Digitalmars-d

On Wednesday, 21 March 2018 at 14:04:58 UTC, Adam D. Ruppe wrote:

On Wednesday, 21 March 2018 at 13:39:28 UTC, 12345swordy wrote:
You can simply check the .dtor symbols at compile time to see 
if every .dtor symbol from child to root have a .dtor that 
have the @nogc attribute


In Simen's example, the child information is not available at 
compile time. This line here:


A a = new B();

discards the static type. The compiler could probably cheat and 
figure it out anyway in this example, but suppose:


---
class A {
 @nogc ~this() {}
 }

class B : A {
~this() {}
}

class C : A {
@nogc ~this() {}
}


A build(string name) {
   if(name == "B") return new B();
   else return new C();
}

void main() {
A a = build(readln());
destroy(a);
}
---


This is very clearly a runtime decision: whether it is B or C 
is determined by user input. But B's dtor is not @nogc... and 
there's thus no way to tell for sure if destroy(a) is or not, 
since it will call the child class based on the runtime 
decision.


so it is impossible for the compiler to know which child class 
is actually called until runtime... too late for a compile-time 
nogc check.


That seems to be it's own separate problem, as it involves 
generating dynamic types at run-time, which it needs run-time 
equivalent of attribute checking. My example assumes that the 
classes created are static types not dynamic types. Besides I do 
not like implied conversions when it comes classes, as I believe 
it is a horrible idea.


Re: #dbugfix 17592

2018-03-21 Thread Adam D. Ruppe via Digitalmars-d

On Wednesday, 21 March 2018 at 13:39:28 UTC, 12345swordy wrote:
You can simply check the .dtor symbols at compile time to see 
if every .dtor symbol from child to root have a .dtor that have 
the @nogc attribute


In Simen's example, the child information is not available at 
compile time. This line here:


A a = new B();

discards the static type. The compiler could probably cheat and 
figure it out anyway in this example, but suppose:


---
class A {
 @nogc ~this() {}
 }

class B : A {
~this() {}
}

class C : A {
@nogc ~this() {}
}


A build(string name) {
   if(name == "B") return new B();
   else return new C();
}

void main() {
A a = build(readln());
destroy(a);
}
---


This is very clearly a runtime decision: whether it is B or C is 
determined by user input. But B's dtor is not @nogc... and 
there's thus no way to tell for sure if destroy(a) is or not, 
since it will call the child class based on the runtime decision.


so it is impossible for the compiler to know which child class is 
actually called until runtime... too late for a compile-time nogc 
check.


Re: #dbugfix 17592

2018-03-21 Thread Adam D. Ruppe via Digitalmars-d

On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin wrote:

Step 1.  Make `emplace` @nogc
So we need to attribute `std.conv.emplace` as @nogc.


No, do not do that! `emplace` is ALREADY `@nogc` when given 
appropriate arguments. Adding the explicit annotation will limit 
its flexibility without enabling any new uses.


This compiles right now:

---
import std.conv;

class Foo {
this() @nogc {}
}

@nogc void main() {
char[__traits(classInstanceSize, Foo)] buffer;
emplace!Foo(buffer[]);
}
---


`emplace` is `@nogc` if the constructor it calls is `@nogc`.



The real bug with nogc and things like emplace are the error 
messages. They should tell you the item in the call chain where 
@nogc is NOT inferred. So if the ctor there was not annotated 
right now it says:


 Error: @nogc function D main cannot call non-@nogc function 
std.conv.emplace!(Foo).emplace


Well, it should say:

 Error: @nogc function D main cannot call non-@nogc function 
std.conv.emplace!(Foo).emplace
   >>  emplace was not inferred because it calls non-@nogc 
function `Foo.this()`



That supplemental bit with the >> indicates the ACTUAL reason 
nogc failed. Change that and the rest of the call tree becomes 
nogc automatically.


I seem to remember filing this to bugzilla sometime but bugzilla 
search is so unbelievably bad I can never find anything on there 
so idk for sure.


But this error message change would be my #1 request for nogc. 
It'd keep others from chasing false leads.




Step 2. Make `destroy` @nogc
`destroy` simply calls `rt_finalize` in the runtime, at least 
for classes.  I declared it as `@nogc` in the code above, but 
that's a cheat, though I think `rt_finalize` can be made 
`@nogc` in the runtime.


This cannot be proven at compile time since it calls destructors 
based on a dynamic type which may or may not keep the nogc 
promise.


Of course, dtors that gc allocate are usually broken anyway... 
but it isn't a compile time guarantee in the current language and 
a library change cannot fix that alone.


Re: #dbugfix 17592

2018-03-21 Thread 12345swordy via Digitalmars-d

On Wednesday, 21 March 2018 at 11:13:41 UTC, Simen Kjærås wrote:
On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin 
wrote:



I think `rt_finalize` can be made `@nogc` in the runtime.


And this is where you're wrong. Consider this:

class A {
@nogc ~this() {}
}

class B : A {
~this() {}
}

A a = new B();
destroy(a); // Is this @nogc?


Essentially, since @nogc and other qualifiers aren't inherited 
on dtors, it's impossible to know if destroying an instance of 
a non-final class is @nogc.


There's one case where you can: final classes where no 
superclass and no member defines a non-@nogc destructor.


In order for this to be done in the general case, dtors need to 
inherit their qualifiers somehow. That's at the very least a 
DIP, and any chosen path is highly likely to break existing 
code.


--
  Simen


You can simply check the .dtor symbols at compile time to see if 
every .dtor symbol from child to root have a .dtor that have the 
@nogc attribute(and other attributes as well). If it does, add 
that attribute to destroy.


Re: #dbugfix 17592

2018-03-21 Thread Simen Kjærås via Digitalmars-d

On Wednesday, 21 March 2018 at 08:49:11 UTC, Mike Franklin wrote:


I think `rt_finalize` can be made `@nogc` in the runtime.


And this is where you're wrong. Consider this:

class A {
@nogc ~this() {}
}

class B : A {
~this() {}
}

A a = new B();
destroy(a); // Is this @nogc?


Essentially, since @nogc and other qualifiers aren't inherited on 
dtors, it's impossible to know if destroying an instance of a 
non-final class is @nogc.


There's one case where you can: final classes where no superclass 
and no member defines a non-@nogc destructor.


In order for this to be done in the general case, dtors need to 
inherit their qualifiers somehow. That's at the very least a DIP, 
and any chosen path is highly likely to break existing code.


--
  Simen


Re: #dbugfix 17592

2018-03-21 Thread Mike Franklin via Digitalmars-d

On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
This is very important to me as I am very interested in using 
the language for game development.


Yes I know that it's marked as "Duplicated", but I strongly 
disagree as it is different enough to consider is own issue.


Alex


https://issues.dlang.org/show_bug.cgi?id=17592

Yeah that's pretty poopy.  I looked into this and I think this is 
fixable.  Here's my proof of concept:


-
import core.stdc.stdio;
import std.traits;

/***
* This code was copied right out of druntime and
* attributed with @nogc
***/
extern (C) void rt_finalize(void *data, bool det=true) @nogc;
void destroy(T)(T obj) @nogc if (is(T == class))
{
rt_finalize(cast(void*)obj);
}

/***
* This emplace implementation below was copied
* right out of std.conv and attributed with @nogc
***/
@nogc pure nothrow @safe
void testEmplaceChunk(void[] chunk, size_t typeSize, size_t 
typeAlignment, string typeName)

{
assert(chunk.length >= typeSize, "emplace: Chunk size too 
small.");
assert((cast(size_t) chunk.ptr) % typeAlignment == 0, 
"emplace: Chunk is not aligned.");

}

T emplace(T, Args...)(T chunk, auto ref Args args) @nogc
if (is(T == class))
{
static assert(!isAbstractClass!T, T.stringof ~
" is abstract and it can't be emplaced");

// Initialize the object in its pre-ctor state
enum classSize = __traits(classInstanceSize, T);
(() @trusted => (cast(void*) chunk)[0 .. classSize] = 
typeid(T).initializer[])();


static if (isInnerClass!T)
{
static assert(Args.length > 0,
"Initializing an inner class requires a pointer to 
the outer class");

static assert(is(Args[0] : typeof(T.outer)),
"The first argument must be a pointer to the outer 
class");


chunk.outer = args[0];
alias args1 = args[1..$];
}
else alias args1 = args;

// Call the ctor if any
static if (is(typeof(chunk.__ctor(args1
{
// T defines a genuine constructor accepting args
// Go the classic route: write .init first, then call ctor
chunk.__ctor(args1);
}
else
{
static assert(args1.length == 0 && !is(typeof(__ctor)),
"Don't know how to initialize an object of type "
~ T.stringof ~ " with arguments " ~ 
typeof(args1).stringof);

}
return chunk;
}

T emplace(T, Args...)(void[] chunk, auto ref Args args) @nogc
if (is(T == class))
{
enum classSize = __traits(classInstanceSize, T);
testEmplaceChunk(chunk, classSize, classInstanceAlignment!T, 
T.stringof);

return emplace!T(cast(T)(chunk.ptr), args);
}

/***
* This code was copied from 
https://wiki.dlang.org/Memory_Management#Explicit_Class_Instance_Allocation

* and attributed with @nogc
***/
class TestClass
{
int x;

this(int x) @nogc
{
puts("TestClass's constructor called");
this.x = x;
}

~this() @nogc
{
puts("TestClass's destructor called");
}
}

T heapAllocate(T, Args...) (Args args) @nogc
{
import core.stdc.stdlib : malloc;
import core.memory : GC;

// get class size of class instance in bytes
auto size = __traits(classInstanceSize, T);

// allocate memory for the object
auto memory = malloc(size)[0..size];
if(!memory)
{
import core.exception : onOutOfMemoryError;
onOutOfMemoryError();
}

puts("Memory allocated");

// notify garbage collector that it should scan this memory
GC.addRange(memory.ptr, size);

// call T's constructor and emplace instance on
// newly allocated memory
return emplace!(T, Args)(memory, args);
}

void heapDeallocate(T)(T obj) @nogc
{
import core.stdc.stdlib : free;
import core.memory : GC;

// calls obj's destructor
destroy(obj);

// garbage collector should no longer scan this memory
GC.removeRange(cast(void*)obj);

// free memory occupied by object
free(cast(void*)obj);

puts("Memory deallocated");
}

void main() @nogc
{
// allocate new instance of TestClass on the heap
auto test = heapAllocate!TestClass(42);
scope(exit)
{
heapDeallocate(test);
}

printf("test.x = %d\n", test.x);
}
-

Step 1.  Make `emplace` @nogc
So we need to attribute `std.conv.emplace` as @nogc.  Based on 
the code above, that looks feasible.  The difficulty, though will 
be writing thorough tests for it.


Step 2. Make `destroy` @nogc
`destroy` simply calls `rt_finalize` in the runtime, at least for 
classes.  I declared it as `@nogc` in the code 

Re: #dbugfix 17592

2018-03-21 Thread Mike Parker via Digitalmars-d

On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
This is very important to me as I am very interested in using 
the language for game development.


Yes I know that it's marked as "Duplicated", but I strongly 
disagree as it is different enough to consider is own issue.


Alex


Noted.


Re: #dbugfix 17592

2018-03-21 Thread bauss via Digitalmars-d

On Tuesday, 20 March 2018 at 21:27:53 UTC, 12345swordy wrote:
This is very important to me as I am very interested in using 
the language for game development.


Yes I know that it's marked as "Duplicated", but I strongly 
disagree as it is different enough to consider is own issue.


Alex


The game development part seems to be irrelevant, because D has 
been used to make plenty of games.


It is however relevant to how your game would be developed, but 
your post make it seem like D can't be used to develop games at 
all.