Conversation
Wow! Even in my |
{ | ||
enum bool _isStaticArray = true; | ||
} | ||
static if(is(T == struct) || is(typeof(typeid(T)) == TypeInfo_StaticArray)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this work for e.g. const(int)[32]
? And for that matter, did the old code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neither new nor old code works for const
.
It looks like it's impossible to work correct with shared
because of this:
int i = 0;
struct S
{
~this ()
{ ++i; }
}
struct SS
{
shared ~this ()
{ ++i; }
}
void main()
{
S s;
typeid(S).destroy(&s);
assert(i == 1); i = 0; // ok
typeid(shared S).destroy(&s);
assert(i == 1); i = 0; // failed
// can't use S here because of compiler bug (but can use in `shared S[1] sarr`)
shared SS ss;
typeid(SS).destroy(cast(void*) &ss);
assert(i == 1); i = 0; // ok
typeid(shared SS).destroy(cast(void*) &ss);
assert(i == 1); i = 0; // failed
}
Anyway, I completely forget about shared
. Will change to mimic old destroy
shared
-rejecting behavior.
I don't see any compelling reason to rename this function to |
Also, I think these functions should take their arguments as |
Why would we make it not work for other types? If it needs further tweaking to work appropriately for them, then fine, but I see no reason to remove the functionality. |
I deleted that comment. I misunderstood what he was trying to do. |
So, you're trying to make it so that |
Added |
As For 2 comments with:
You do not understand me, I do not understand you. Looks like your comments means:
What can I answer then? Probably I can give you code example: import std.typecons: destruct;
class C { ... }
void main()
{
C c = new C(...);
destroy(c); // to call runtime finalize
destruct(c); // to clear the reference
assert(c is null); // be happy
} So having both |
Edited description to make clearer Now the worst thing with |
Dude, no. What it means is that it wasn't clear to us why a rename was warranted. That just means we wanted clarification. Let us step back for a bit. How about we just make |
I clarified as clear as possible. It is in description.
Now the worst thing with
As I'm still sure we need |
And actually, from your description, I'd say that For a class, that's the object that you give it. As far as the type system is concerned, the reference is the class. There is no separation of the reference and the class. You can't dereference it or otherwise indicate that you want to do something to the object rather than the reference. So, calling For pointers, there is a separation between the pointer and the type being pointed to. So, having For structs, there's no indirection of any kind involved. Destroying the object should call its destructor and set it to its init value. The result should be identical to what happens when you pass a struct to an For dynamic arrays, they're pointers with length, so it should be essentially the same as calling For static arrays, like structs, there's no indirection, so it's basically the same. Any value types that they hold should have their destructors called and be set to init (which means setting the whole static array to its init value). What you're trying to do seems to be to have It seems to me that the problem is that you have a fundamental misunderstanding of |
Actually, I should correct myself. The Regardless, as far as I can tell, |
Semantic changes like in this pull need to be discussed in the newsgroup first, not split out across multiple pull requests. |
buf[] = 0; | ||
else | ||
{ | ||
TypeInfo el = typeid(T), info = el; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't depend on the order of evaluation of arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Order of evaluation of initializations is defined as left to right. Never heard about compiler bugs in this area. List it here if any.
By the way, order of evaluation of function arguments is also defined as left to right but currently isn't supported by dmd
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not about compiler semantics, It's bad coding style because you have to remember the rule.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not about compiler semantics, It's bad coding style because you have to remember the rule.
Looks like your personal opinion as I have never heard this before.
But lets think about it. If behavior here is undefined, the compiler will obviously reject such code just like it rejects int a = b, b = 2;
. This rule is same even in C++. And for the reader this code is having a single meaning so, if the reader didn't know about this rule, such code will just help him to learn it and be happy. So I see no reasons against this code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@denis-sh: A large number of coding guidelines require/recommend to have only one declaration by line, so I'm somewhat surprised you have never heard of it before. I agree with Andrej here – don't write needlessly confusing code, especially if it can be trivially avoided.
Fixed comments and style issues pointed out by @AndrejMitrovic. |
To @jmdavis (sorry for the delay):
Wow! You want to say that
You misunderstood my change. My change is:
In the pull description I didn't want to go by refs and destroy everything. I just noted that is is inconsistent that it goes by ref in one particular case.
Looks like you just proved that you are confused how Sorry, but as you see, I think it is you who is incorrect here. So I want somebody third to point out who is incorrect. @alexrp, @AndrejMitrovic, anybody else, tell me that I'm blaming good people and show me my mistakes, please. |
And in fewer words about what I want to do is: 1 . I want to have a T t = ...;
...
// Should be equivalent to `destruct(t);`:
destruct(*cast(T[1]*) t); As we can always assume that 2 . I want to have a function to finalize class instance. |
I corrected myself with regards to |
|
||
static if(is(T == struct) || is(T U : U[n], size_t n)) | ||
{ | ||
// Note: old `destroy` version just fills shared static arrays with its `init`, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes no sense to kick the old horse. Let the bones rest and the history stay in commits of the master branch.
If this doesn't do what it takes, then there's a problem elsewhere: void destroy(T : U[n], U, size_t n)(ref T obj)
{
obj = T.init;
} People will routinely assign one array to another, and if that doesn't work properly then we have a bigger problem on our hands. |
It would definitely be bad to call the finalizers of all of the elements of a static array, because they could be referred to elsewhere. For instance, if you had
Why doesn't it just do The only thing that I can think of would be that someone was worried about an overloaded So, there may very well be a bug with how static arrays are handled. But Denis has never explained what he thought was buggy about destroying static arrays. Rather, he's complained about how |
So do the structs as there are possible pointers to them. It's expected that caller has knowledge showing it's safe to destroy/finalize something explicitly. It's always unsafe on its own. The thought about finalizing each instance of array is along the lines of:
I expect that assigning static array is equivivalent to an element-wise assignment and then overloaded opAssign can hijack the supposed destruction. |
That's fundamentally different from what Ideally, you'd have to dereference the class to destroy it (as happens with pointers to structs), but because references aren't separated from what they point to in the type system (they're exactly the same type - there is no concept of the type being pointed to), that doesn't work, and At this point, I think that it's clear that
The question then that you bring up is destroying the elements in a static array. You're proposing that each element be destroyed individually, but that would be inconsistent with both
then the objects referred to by It may make sense to look into adding a function which recursively destroys an object rather than just its outer layer, but I don't think it makes sense to make |
I completely disagree. I see 0 point in destroy not recursively destroying its internal stuff by default. Can you name a single usecase where it would make sense for When I write I also think that
But do you realize how involved that is? How bug prone it is? No-one should have to write that himself. Not to mention, you'd have to iterate, checking that the sub elements are not classes, and only selectively destroy certain stuff... Even if the library provides a special
Then I'd say it's ether fundamentally broken, or fundamentally useless :/ Long story short, I fully support the intent of this pull (but I can't judge on the details). Related: I just realized and am super-surprised that |
Pretty much the only reason that The fact that Image the havoc that you'll cause if your object (which is arbitrarily complex) suddenly finalizes all of its reference members when being destroyed. They could be pointed to by who-knows-what, and there's a good chance that you don't have any way of knowing what. It's also fundamentally different from what the GC does when finalizing objects, which completely goes against the goal of Now, given that The GC never recursively destroys any reference types, and neither should |
To @monarchdodra:
Everything you need is in pull dlang/phobos#928! To @jmdavis:
I can only repeat: classes and class references has the same type and that's all. In any other view it differ. Examples: only class reference is passed by value,
As I answered to @monarchdodra, is see no reason for it but I see a strong reason to have a function that equals to go out of scope.
The fact that destroy works with anything other than classes is dangerous as it is confusing and error-prone. I will be very happy once it will work only for classes. I also would like it to be called |
I think there may be some confusion about what you and I call recursive. In particular, I just realized that EDIT: Yes, as @denis-sh said, there was some confusion. I never even imagined to fetch out reference types and destroy those. You say:
This is what is confusing me, because it isn't true: import std.stdio;
struct A
{
~this(){"bla".writeln();}
}
struct B
{
this(this){};
A a;
}
void main()
{
B b;
B[2] bb;
C[2] cc = [new C(), new C()];
typeid(B).destroy(&b);
writeln("1");
typeid(B[2]).destroy(&bb);
writeln("2");
typeid(C[2]).destroy(&cc);
writeln("3");
}
As you can see, destroying So while I understand what is going on better now, and don't have any deep issues anymore, I still have to agree with @denis-sh that putting both structs and classes in the same bag in regards to Proof that it's weird? class instances are not destroyed when called from some encapsulating object (structs containing a class, static array containing a class), yet if you call destroy on a class, it finalizes it...? I'd have expected it just sets the reference to 0. Related: I found |
To @monarchdodra:
NO! Don't use it in your code! |
To @alexrp and @blackwhale:
|
To @andralex:
Destroying isn't an assignment. It must work where assignment will not. Se my previous post. |
To @blackwhale:
Posted
Andrei is here and always can say that his expectations differ. I will then change my post and that's all so I see no problem here.
I described |
To @jmdavis, @blackwhale, @monarchdodra: That question post has nothing to do with insulting of Andrei and you can ignore "Andrei expectations" (but I really think that it is his opinion). So, please, give me the answers! |
A part of the discussion above boils down to the question: what does it mean to call
I understand there are other possible designs and design variations. The rationale for this design is that it has simple semantics and consistently handles static arrays similarly to structs, and dynamic arrays similarly to classes. @denis-sh could you please rework this pull request into implementing this semantics? Let's get this done and make progress. Thanks. |
Do you mean to destory every array element? If so, Anyway, your proposed semantics doesn't look simple at all. This semantics is what I think error prone, dangerous and inconstant. |
The purpose of
Understood. This pull is not acceptable in its current form, and seeing as this has become a time sink without much chance to make progress, I will close it now. Thanks for your work, and apologies for the trouble. Feel free to reopen if new arguments come on the table. |
I'm not against this definition of |
Forms follows function. To destroy things one calls |
So you are against that it is obviousness how |
Everybody like function overloading but there are some situations it can't be used. This is such situation because:
What in this two statements not obvious? |
By the way, I filled Issue 9137 - A function that equals to "out of scope" action for manual lifetime management to allow you all to destroy me there and mark it as |
And I also filled Issue 9139 - |
Thanks. My purpose is not to mark valid concerns as invalid, so the sarcasm is unwarranted there. On the other hand, please understand I can't accept a design I disagree with just to be nice. You have made an argument. It has been well understood and debated at length. Past this point rehashing the issue without fresh perspectives becomes a net loss of time for those involved. There is something to be said about picking one's fights and doing the best possible with one's free time. Above that, a collegial attitude is always appreciated and respected. Thanks. |
I haven't seen this mentioned here: is it ok that currently It's a bit error-prone to have no-ops like this. @andralex thoughts? |
|
Then it should be documented, I don't see any mention of pointers in the code. |
I think it's implemented as designed, but I think there should be an appropriate "destroyRef" function, which destroys classes, and destroys the target of pointers, depending on the arg. Currently, it is possible, and quite simple, to create a type that keeps a reference to a type, and not care whether it is a class or a struct pointer, since a.b works on both. But destroy will not work correctly on the struct pointer. Consider that |
[EDITED] 3 times
Let us have
finalizeClassInstance
(a function finalizing a class instance referenced by its argument) anddestruct
(a function destroying its argument equivalent as if it goes out of scope). Combining these two functions in one (currentdestroy
) is needless, error-prone, and inconsistent.It is needless because having one name assumes is is used in templated code but there is no common uses for such combined function.
It is error-prone because e.g. when
destroy
is used in templated code like creating an analog of a struct with manual memory management:it is easy to forget about the fact that
destroy
behaves different for class references. As this is the common situation,destroy
require a redundantstatic if
branch in the bast case and causes nasty bugs in the worst.It is inconsistent, because druntime isn't a place for template code at all and really fast and CTFE-able destructing function use templates heavily (see
destruct
proposal for example).This is a good time to deprecate
object.destroy
because:shared
structsAnd yes, current
destroy
is just as bad as if we were have.sizeof
property returning for classes its instance size instead of__traits(classInstanceSize, ...)
.See also:
Pull dlang/phobos#929 with
destruct
proposal.