www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Cannot compare object.opEquals is not nogc

reply Rufus Smith <RufusSmith indi.com> writes:
Trying to compare a *ptr value with a value in nogc code results 
in the error:

Error:  nogc function '...' cannot call non- nogc function 
'object.opEquals'		

Shouldn't object opEquals be marked?
Jul 23 2016
next sibling parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 23 July 2016 at 13:18:03 UTC, Rufus Smith wrote:
 Trying to compare a *ptr value with a value in nogc code 
 results in the error:

 Error:  nogc function '...' cannot call non- nogc function 
 'object.opEquals'		

 Shouldn't object opEquals be marked?
If object.opEquals is marked nogc, than all D classes must implement it as nogc, because (of course) you cannot override a nogc method with a not- nogc one (while the opposite is possible, of course). So marking it nogc is not only a big breaking change, but also very limiting.
Jul 23 2016
parent reply Rufus Smith <RufusSmith indi.com> writes:
On Saturday, 23 July 2016 at 14:15:03 UTC, Lodovico Giaretta 
wrote:
 On Saturday, 23 July 2016 at 13:18:03 UTC, Rufus Smith wrote:
 Trying to compare a *ptr value with a value in nogc code 
 results in the error:

 Error:  nogc function '...' cannot call non- nogc function 
 'object.opEquals'		

 Shouldn't object opEquals be marked?
If object.opEquals is marked nogc, than all D classes must implement it as nogc, because (of course) you cannot override a nogc method with a not- nogc one (while the opposite is possible, of course). So marking it nogc is not only a big breaking change, but also very limiting.
Um, this isn't right. GC code can always call non-gc code. If you mark opEquals nogc, it breaks nothing except implementations of opEquals that use the GC. GC code can still call it nogc opequals, it only enforces opEquals code to avoid the GC itself, which isn't a terrible thing. What is terrible is that nogc code can never have any equality comparisons! It is impossible unless one manually tests them, but how? Every method would be brittle. Do a memory test? compare element by element? One can't predict what to do. So, you are trying off laziness to break nogc. As it stands, if nogc code can't compare equality, it is broken and useless. Why put it in the language then? struct S(T) { nogc void test(T t1, T t2) { if (t1 == t2) return true; return false; } } Broke! Even if opEquals of T does not use any GC we can't write test to be nogc, which means we can't have S be nogc or anything that depends on S that is nogc. This must be a dirty trick played by the implementors of nogc to keep everyone on the gc nipple? Equality comparison is more fundamental than the GC in programming. There is no fundamental reason why equality comparison depends on the GC. All I can hope for now is that there is a robust way to compare that I can use that is marked nogc. Else all my nogc code is broke. I guess one has this problem with all opOp's!
Jul 23 2016
next sibling parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 23 July 2016 at 14:53:49 UTC, Rufus Smith wrote:
 Um, this isn't right. GC code can always call non-gc code.

 If you mark opEquals nogc, it breaks nothing except 
 implementations of opEquals that use the GC. GC code can still 
 call it nogc opequals, it only enforces opEquals code to avoid 
 the GC itself, which isn't a terrible thing.
That's what I meant. Sorry for being not clear. IMHO, it is very limiting to forbid the use of the GC in opEquals. And it would definitely break a lot of code.
 What is terrible is that nogc code can never have any equality 
 comparisons! It is impossible unless one manually tests them, 
 but how? Every method would be brittle. Do a memory test? 
 compare element by element? One can't predict what to do.
nogc code can have nogc comparisons, as long as it does not use other objects whose comparison requires the GC. See more below.
 So, you are trying off laziness to break nogc. As it stands, if 
 nogc code can't compare equality, it is broken and useless. Why 
 put it in the language then?

 struct S(T)
 {
     nogc void test(T t1, T t2)
    {
       if (t1 == t2) return true;
       return false;
    }
 }

 Broke! Even if opEquals of T does not use any GC we can't write 
 test to be nogc, which means we can't have S be nogc or 
 anything that depends on S that is nogc. This must be a dirty 
 trick played by the implementors of nogc to keep everyone on 
 the gc nipple?
If opEquals of T does not use the GC, then the compiler will infer the attribute nogc for your test function. Remember: templated functions will be inferred nogc whenever possible. Just, don't put nogc explicitly, so the code will be nogc if T.opEquals is nogc and otherwise it will be not- nogc.
 Equality comparison is more fundamental than the GC in 
 programming. There is no fundamental reason why equality 
 comparison depends on the GC.

 All I can hope for now is that there is a robust way to compare 
 that I can use that is marked nogc. Else all my nogc code is 
 broke. I guess one has this problem with all opOp's!
With templates (as you show in your code) you have no problem, just let the compiler infer the attributes, as I said. With runtime OOP it is more of a trouble, but in D runtime OOP is not used that much, and it is rarely used in critical nogc code.
Jul 23 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/23/16 10:53 AM, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 14:15:03 UTC, Lodovico Giaretta wrote:
 On Saturday, 23 July 2016 at 13:18:03 UTC, Rufus Smith wrote:
 Trying to compare a *ptr value with a value in nogc code results in
 the error:

 Error:  nogc function '...' cannot call non- nogc function
 'object.opEquals'

 Shouldn't object opEquals be marked?
If object.opEquals is marked nogc, than all D classes must implement it as nogc, because (of course) you cannot override a nogc method with a not- nogc one (while the opposite is possible, of course). So marking it nogc is not only a big breaking change, but also very limiting.
Um, this isn't right. GC code can always call non-gc code.
The issue is that for *classes*, the proper way to add an opEquals is to override the base version. The base version existed LONG before nogc did, and so it's not appropriately marked. Not only that, but nogc is too limiting (if I want to use GC in opEquals, I should be able to). The real problem here is that there is a base method at all. We have been striving to remove it at some point, but it is very difficult due to all the legacy code which is written. Almost all the Object base methods need to be removed IMO. You can add them at a higher level if you need them, and then specify your requirements for derived classes. Including opHash, opCmp, toString, etc.
 If you mark opEquals nogc, it breaks nothing except implementations of
 opEquals that use the GC. GC code can still call it nogc opequals, it
 only enforces opEquals code to avoid the GC itself, which isn't a
 terrible thing.
It breaks all classes which use GC in opEquals. Note that you can't really compare two immutable or const objects either! (well, actually you can, but that's because the runtime just casts away const and lets you have undefined behavior).
 What is terrible is that nogc code can never have any equality
 comparisons! It is impossible unless one manually tests them, but how?
 Every method would be brittle. Do a memory test? compare element by
 element? One can't predict what to do.
It is unfortunate. I hope we can fix it. I'd rather not add another exception like we have for comparing const objects.
 So, you are trying off laziness to break nogc. As it stands, if nogc
 code can't compare equality, it is broken and useless. Why put it in the
 language then?
nogc is not useless, it just cannot handle Objects at the moment.
 Broke! Even if opEquals of T does not use any GC we can't write test to
 be nogc, which means we can't have S be nogc or anything that depends on
 S that is nogc. This must be a dirty trick played by the implementors of
 nogc to keep everyone on the gc nipple?
I assure you, it's not a trick. It's legacy. It needs fixing, but the fix isn't painless or easy. -Steve
Jul 23 2016
next sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Saturday, 23 July 2016 at 15:25:02 UTC, Steven Schveighoffer 
wrote:
 On 7/23/16 10:53 AM, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 14:15:03 UTC, Lodovico Giaretta 
 wrote:
 On Saturday, 23 July 2016 at 13:18:03 UTC, Rufus Smith wrote:
 Trying to compare a *ptr value with a value in nogc code 
 results in
 the error:

 Error:  nogc function '...' cannot call non- nogc function
 'object.opEquals'

 Shouldn't object opEquals be marked?
If object.opEquals is marked nogc, than all D classes must implement it as nogc, because (of course) you cannot override a nogc method with a not- nogc one (while the opposite is possible, of course). So marking it nogc is not only a big breaking change, but also very limiting.
Um, this isn't right. GC code can always call non-gc code.
The issue is that for *classes*, the proper way to add an opEquals is to override the base version. The base version existed LONG before nogc did, and so it's not appropriately marked. Not only that, but nogc is too limiting (if I want to use GC in opEquals, I should be able to). The real problem here is that there is a base method at all. We have been striving to remove it at some point, but it is very difficult due to all the legacy code which is written. Almost all the Object base methods need to be removed IMO. You can add them at a higher level if you need them, and then specify your requirements for derived classes. Including opHash, opCmp, toString, etc.
 If you mark opEquals nogc, it breaks nothing except 
 implementations of
 opEquals that use the GC. GC code can still call it nogc 
 opequals, it
 only enforces opEquals code to avoid the GC itself, which 
 isn't a
 terrible thing.
It breaks all classes which use GC in opEquals. Note that you can't really compare two immutable or const objects either! (well, actually you can, but that's because the runtime just casts away const and lets you have undefined behavior).
 What is terrible is that nogc code can never have any equality
 comparisons! It is impossible unless one manually tests them, 
 but how?
 Every method would be brittle. Do a memory test? compare 
 element by
 element? One can't predict what to do.
It is unfortunate. I hope we can fix it. I'd rather not add another exception like we have for comparing const objects.
 So, you are trying off laziness to break nogc. As it stands, 
 if nogc
 code can't compare equality, it is broken and useless. Why put 
 it in the
 language then?
nogc is not useless, it just cannot handle Objects at the moment.
 Broke! Even if opEquals of T does not use any GC we can't 
 write test to
 be nogc, which means we can't have S be nogc or anything that 
 depends on
 S that is nogc. This must be a dirty trick played by the 
 implementors of
 nogc to keep everyone on the gc nipple?
I assure you, it's not a trick. It's legacy. It needs fixing, but the fix isn't painless or easy. -Steve
I've seen this type of problem many times before when using the nogc attribute. With alot of work, and breaking changes, you could fix it in the case of opEquals, and in the end you still end up with the restriction that you can't use the GC in opEquals, which may be a good thing, but some would disagree. But this is a common problem and I think a more exhaustive solution would be to allow nogc code to call that that is either marked as nogc, or inferred to be nogc. Instead of treating nogc as a special compiler directive to check for GC code, the compiler could check for GC code in all cases, and infer the attribute for all functions. Then nogc would simply be a way for the developer to tell the compiler to make sure they aren't using nogc where they don't intend to. This allows code that is written without nogc to be called from code that does use it. It takes an effort away from the developer and moves it to the compiler. It allows nogc to work with existing code. Maybe this would result in a big performance hit on the compiler because now it would always have to check for GC code, instead of just when it's specified with nogc...not sure. Anyway, this is just a general overview. There's obviously alot of details and specifics that were glossed over but I think the general idea could be a good solution.
Jul 23 2016
parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Saturday, 23 July 2016 at 16:46:20 UTC, Jonathan Marler wrote:
 [...]
Actually Im going to disagree with myself. This technique actually wouldn't work with virtual methods:)
Jul 23 2016
parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 23 July 2016 at 17:04:42 UTC, Jonathan Marler wrote:
 On Saturday, 23 July 2016 at 16:46:20 UTC, Jonathan Marler 
 wrote:
 [...]
Actually Im going to disagree with myself. This technique actually wouldn't work with virtual methods:)
I don't think we have the big problems with nogc that people points out. I mean, we cannot decide that specific methods or opXXX must always be nogc. That's too restrictive. So, what we need to do is: - use templates: with them, we can have our algorithms be safe when applied to safe types, nogc when applied to nogc types, and so on; for example, instead of taking a specific delegate type, we shall always accept a generic type, and use traits to guarantee it is some delegate; in this way, we can accept safe delegate and propagate safety to our algorithm, or accept system and have our algorithm usable in system code; same with nogc et al. - when we use virtual methods, we are giving up all compiler-checked attributes; in this situation we have two options: - we trust what we are doing: e.g. we cannot mark a thing nogc, but we know it is and the profiler confirms that no allocation happens, so we are happy; our aim is having code that doesn't freeze because of collections, and not marking code nogc. - we must have nogc (or whatever): then we know we cannot use certain classes, because they are definitely nogc; so we cast the objects we get to the classes/interfaces that we know are nogc (and are marked as such), and then our code is nogc; as you see, you don't need Object to have nogc methods; you only need the specific classes you use have it; if you want to work on generic objects, and as such cannot do specific casts, then you should definitely be using templates. The only real problems I found till now are: - some things in Phobos that shall be nogc are not; they shall be refactored to have that attribute (but this is not always easy and requires time) - the interface IAllocator is mostly used with nogc allocators, but cannot have the said attribute (as I explained above, it must not restrict the possibility of allocators); it shall have a sub-interface NoGCAllocator, so that code can accept a nogc allocator parameter without using templates (of course templates are fine, and are what we use now, but if everyone uses templates, why have IAllocator in the first place? IMHO we must have or both or none).
Jul 23 2016
parent reply Rufus Smith <RufusSmith indi.com> writes:
On Saturday, 23 July 2016 at 17:27:24 UTC, Lodovico Giaretta 
wrote:
 On Saturday, 23 July 2016 at 17:04:42 UTC, Jonathan Marler 
 wrote:
 On Saturday, 23 July 2016 at 16:46:20 UTC, Jonathan Marler 
 wrote:
 [...]
Actually Im going to disagree with myself. This technique actually wouldn't work with virtual methods:)
I don't think we have the big problems with nogc that people points out. I mean, we cannot decide that specific methods or opXXX must always be nogc. That's too restrictive. So, what we need to do is: - use templates: with them, we can have our algorithms be safe when applied to safe types, nogc when applied to nogc types, and so on; for example, instead of taking a specific delegate type, we shall always accept a generic type, and use traits to guarantee it is some delegate; in this way, we can accept safe delegate and propagate safety to our algorithm, or accept system and have our algorithm usable in system code; same with nogc et al. - when we use virtual methods, we are giving up all compiler-checked attributes; in this situation we have two options: - we trust what we are doing: e.g. we cannot mark a thing nogc, but we know it is and the profiler confirms that no allocation happens, so we are happy; our aim is having code that doesn't freeze because of collections, and not marking code nogc.
This is bad. It only creates a faulty foundation. The whole point of nogc is to enforce nogc behavior. If you don't use it your not enforcing anything and then things slip by only to create problems later. This mentality is completely wrong and leads to decay. This is exactly why we are discussing this right now, because someone decided that it was ok to ignore other use cases which eventually turn out to be quite important. If, say, D was built without the GC, then adding the GC would be much easier and more logical than what has been done, which is built with GC and trying to remove it.
     - we must have  nogc (or  whatever): then we know we cannot 
 use certain classes, because they are definitely  nogc; so we 
 cast the objects we get to the classes/interfaces that we know 
 are  nogc (and are marked as such), and then our code is  nogc; 
 as you see, you don't need Object to have  nogc methods; you 
 only need the specific classes you use have it; if you want to 
 work on generic objects, and as such cannot do specific casts, 
 then you should definitely be using templates.

 The only real problems I found till now are:
 - some things in Phobos that shall be  nogc are not; they shall 
 be refactored to have that attribute (but this is not always 
 easy and requires time)
 - the interface IAllocator is mostly used with  nogc 
 allocators, but cannot have the said attribute (as I explained 
 above, it must not restrict the possibility of allocators); it 
 shall have a sub-interface NoGCAllocator, so that code can 
 accept a  nogc allocator parameter without using templates (of 
 course templates are fine, and are what we use now, but if 
 everyone uses templates, why have IAllocator in the first 
 place? IMHO we must have or both or none).
Templates are not the end all be all. They don't allow for run-time polymorphism, which is an important aspect of software. What we should have is that when something is added or removed we are 100%(or close as we can get) that the feature is correct and causes no side effects. D's GC causes side effects because it was assumed that there would not be any. Now the future is hear and it's up to us to try and unravel the mess the past created. It's always best to just do it right in the first place, it saves everyone from the headache. DMD should probably be branched, and all GC stuff removed, then built back up to have the proper features that the GC version has. I think someone has essentially done this on their own, but never built it up to full capacity.
Jul 23 2016
next sibling parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 23 July 2016 at 21:44:05 UTC, Rufus Smith wrote:
 Templates are not the end all be all. They don't allow for 
 run-time polymorphism, which is an important aspect of software.
Ok, so you need runtime polymorphism. And you want it in nogc code. That's not difficult. Just have the base class of your hierarchy declare its opXXX nogc. This is possible, because non- nogc functions can be overridden by nogc ones (as logical). Now you can have your function accept parameters of your base class, and it will be nogc. And without forcing every class of the D world to have opXXX nogc. I don't see why this wouldn't be enough...
Jul 23 2016
prev sibling next sibling parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Saturday, 23 July 2016 at 21:44:05 UTC, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 17:27:24 UTC, Lodovico Giaretta 
 wrote:
     - we trust what we are doing: e.g. we cannot mark a thing 
  nogc, but we know it is and the profiler confirms that no 
 allocation happens, so we are happy; our aim is having code 
 that doesn't freeze because of collections, and not marking 
 code  nogc.
This is bad. It only creates a faulty foundation. The whole point of nogc is to enforce nogc behavior. If you don't use it your not enforcing anything and then things slip by only to create problems later. This mentality is completely wrong and leads to decay.
While you are right on this, we must be pragmatical: we currently do not enforce that pointers point to valid memory locations, that private members are not accessed outside the module with tricky arithmetics, we have tons of things that work by convention, because the compiler simply can't check them all and some are even intrinsically uncheckable. In this environment of "code by trust", nogc is the least of the problems, also because, I insist, it can be checked with the profiler, or you can plug a custom GC to druntime that asserts every time you try to call its functions (work is being made to make the GC independent and pluggable).
 This is exactly why we are discussing this right now, because 
 someone decided that it was ok to ignore other use cases which 
 eventually turn out to be quite important.
Well, I think that deciding that opXXX must always be nogc, ignoring other use cases that may need the GC, is blatantly wrong. By asking that Object.opXXX be nogc, you are making the error the error you said others made.
Jul 23 2016
parent reply Rufus Smith <RufusSmith indi.com> writes:
On Saturday, 23 July 2016 at 22:48:07 UTC, Lodovico Giaretta 
wrote:
 On Saturday, 23 July 2016 at 21:44:05 UTC, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 17:27:24 UTC, Lodovico Giaretta 
 wrote:
     - we trust what we are doing: e.g. we cannot mark a thing 
  nogc, but we know it is and the profiler confirms that no 
 allocation happens, so we are happy; our aim is having code 
 that doesn't freeze because of collections, and not marking 
 code  nogc.
This is bad. It only creates a faulty foundation. The whole point of nogc is to enforce nogc behavior. If you don't use it your not enforcing anything and then things slip by only to create problems later. This mentality is completely wrong and leads to decay.
While you are right on this, we must be pragmatical: we currently do not enforce that pointers point to valid memory locations, that private members are not accessed outside the module with tricky arithmetics, we have tons of things that work by convention, because the compiler simply can't check them all and some are even intrinsically uncheckable. In this environment of "code by trust", nogc is the least of the problems, also because, I insist, it can be checked with the profiler, or you can plug a custom GC to druntime that asserts every time you try to call its functions (work is being made to make the GC independent and pluggable).
 This is exactly why we are discussing this right now, because 
 someone decided that it was ok to ignore other use cases which 
 eventually turn out to be quite important.
Well, I think that deciding that opXXX must always be nogc, ignoring other use cases that may need the GC, is blatantly wrong. By asking that Object.opXXX be nogc, you are making the error the error you said others made.
This just isn't right. What your saying is that because someone screwed up, we must live with the screw up and build everyone around the screw up. This mentality is why everyone is so screwed up in the first place, do you not see that? And I think you really have a misconception about the GC vs nogc. One can rewrite GC code, such as an GC based opEquals, without limitations. They can allocate on the stack, use malloc and free when done, etc. opEquals generally doesn't have state. So you it is possible to around around. It's probably always possible to rewrite a GC opEquals to use nogc without too much difficulty. BUT, it is impossible to use a GC opEquals in nogc code! This means there is no work around. What you claim is that we accept the impossiblity(which makes nogc useless) just to avoid having to rewrite some GC opEquals code. We can't rewrite the nogc side, it's set in stone. We are screwed from the start when we attempt to do nogc code because at some point we will have to do comparisons. It's the same problem with purity and any other transitive relationship. All "workarounds" are just as limited because basically we added the relationship if A is nogc and A uses B, then B must be nogc. Yet, we start with B is GC. Hence we never ever have A use B, because A's can only use nogc. To see it simpler, What if everything in D was GC based. All code was marked GC(even statements, types, etc). Do you agree that nogc would be absolutely useless? We couldn't build up anything because we couldn't include any code. This is the extreme case. Conversely, if everything was built up using nogc, we could write GC based code just fine, could we not? Therefore, claiming that we stay with GC based code just prevents using more and more nogc code. The more GC based code D gets, the less useful nogc gets and we are back were we started. Since nogc is more critical in the foundational layers, as it affects everything built on it, all core features should be nogc. This way, the user isn't can decide when to break away from the GC code, which will only affect everything after that point. This is a one way street, pretending it is two way only enriches the lawyers and eventually makes everyone unhappy. Making the D dependent on the GC was a mistake that many wasted man hours will go in to trying to unravel. Trying to carry on this mistake just wastes more hours. I understand that it is a mess, but it got that way from the mistake in the first place, not from trying to undo the mistake(which is illogical because there would be no nogc if there wasn't a gc in the first place). I also understand that there is some desire to keep things "backwards compatible". This is also a mistake, not only does it prolong the pain and suffering but is irrational. 1. A fork can be made. Those people that have based their code on the GC can continue using an older version. Their code works at that point, does it not? So just stop going down that dead end path. They have what they need, it's not like they will lose anything(virtually nothing except in most cases). Moving in the correct direction is always better, regardless of who's panties get in a wad.
Jul 23 2016
next sibling parent Jonathan Marler <johnnymarler gmail.com> writes:
On Sunday, 24 July 2016 at 02:17:27 UTC, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 22:48:07 UTC, Lodovico Giaretta 
 wrote:
 [...]
This just isn't right. What your saying is that because someone screwed up, we must live with the screw up and build everyone around the screw up. This mentality is why everyone is so screwed up in the first place, do you not see that? [...]
I pretty much agree and had the same thoughts you've expressed here Rufus. Your arguments are logical and make sense. However, I can already tell you this kind of a change is going to elicit alot of negative feedback. I think you're gonna find yourself frustrated in a losing battle trying to get the community to see reason. I hope Im wrong, but know you got me on your side.
Jul 23 2016
prev sibling parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 24 July 2016 at 02:17:27 UTC, Rufus Smith wrote:
 This just isn't right. What your saying is that because someone 
 screwed up, we must live with the screw up and build everyone 
 around the screw up. This mentality is why everyone is so 
 screwed up in the first place, do you not see that?

 And I think you really have a misconception about the GC vs 
 nogc. One can rewrite GC code, such as an GC based opEquals, 
 without limitations. They can allocate on the stack, use malloc 
 and free when done, etc. opEquals generally doesn't have state. 
 So you it is possible to around around. It's probably always 
 possible to rewrite a GC opEquals to use nogc without too much 
 difficulty.
Now you are telling me to "program by trust", because there's nothing ensuring that I remember to free everything I allocated with malloc/free, while a GC would guarantee no memory leaks. Again there's nothing stopping me from returning pointers to things allocated on the stack. And now there are lots... Before you told me that programming by trust is a wrong attitude, and now you propose me to use it, risking memory leakage in a function that may be executed hundreds of times per second.
 BUT, it is impossible to use a GC opEquals in nogc code! This 
 means there is no work around. What you claim is that we accept 
 the impossiblity(which makes nogc useless) just to avoid having 
 to rewrite some GC opEquals code. We can't rewrite the nogc 
 side, it's set in stone. We are screwed from the start when we 
 attempt to do nogc code because at some point we will have to 
 do comparisons. It's the same problem with purity and any other 
 transitive relationship.

 All "workarounds" are just as limited because basically we 
 added the relationship if A is nogc and A uses B, then B must 
 be nogc. Yet, we start with B is GC. Hence we never ever have A 
 use B, because A's can only use nogc.

 To see it simpler, What if everything in D was GC based. All 
 code was marked GC(even statements, types, etc). Do you agree 
 that nogc would be absolutely useless? We couldn't build up 
 anything because we couldn't include any code. This is the 
 extreme case.

 Conversely, if everything was built up using nogc, we could 
 write GC based code just fine, could we not?
No. If you put a big nogc attribute on Object.opXXX, then nobody can write GC code in his classes. So if everything is nogc, you cannont write GC code, because it woudn't interact with Phobos. Example: if you mark an algorithm that takes a delegate nogc, then you cannot pass GC delegates to it. So you cannot use it in GC code.
 Therefore, claiming that we stay with GC based code just 
 prevents using more and more nogc code. The more GC based code 
 D gets, the less useful nogc gets and we are back were we 
 started.

 Since nogc is more critical in the foundational layers, as it 
 affects everything built on it, all core features should be 
 nogc. This way, the user isn't can decide when to break away 
 from the GC code, which will only affect everything after that 
 point.
Yes. All building blocks must be as much nogc as possible. But customization points (virtual functions, delegate arguments, ...) must not be nogc, otherwise it is no possible to have classes that use the GC or callbacks that use the GC.
 This is a one way street, pretending it is two way only 
 enriches the lawyers and eventually makes everyone unhappy. 
 Making the D dependent on the GC was a mistake that many wasted 
 man hours will go in to trying to unravel.  Trying to carry on 
 this mistake just wastes more hours.

 I understand that it is a mess, but it got that way from the 
 mistake in the first place, not from trying to undo the 
 mistake(which is illogical because there would be no nogc if 
 there wasn't a gc in the first place).  I also understand that 
 there is some desire to keep things "backwards compatible". 
 This is also a mistake, not only does it prolong the pain and 
 suffering but is irrational. 1. A fork can be made. Those 
 people that have based their code on the GC can continue using 
 an older version. Their code works at that point, does it not? 
 So just stop going down that dead end path. They have what they 
 need, it's not like they will lose anything(virtually nothing 
 except in most cases). Moving in the correct direction is 
 always better, regardless of who's panties get in a wad.
I still don't understand why you want Object.opXXX nogc. As I already said, you can still make your functions nogc, just accepting parameters of nogc types. It's obvious. If I wrote a wonderful library that uses the GC, you will not use it. If I have a class that uses the GC in opXXX (and I am free to have it, because maybe I need it, and maybe it's the most efficient way for my use case), you will not use it. The same applies here. You'll have your algorithms work only on classes that declare opXXX as nogc. Not all memory allocation patterns are good for malloc/free. Not all of them are good for stack allocations. Some of them are not even good for reference counting. Every class shall use the best solution for its job. And everybody must still be able to extend the base class. If you want to use a method specific to a subclass, you downcast. If you want to use the nogc opXXX when the base does not enforce it, you downcast. It's the same principle: more advanced functionalities require more derived types (and nogc is more derived, because it is covariant to not- nogc). Basic OOP.
Jul 24 2016
parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Sunday, 24 July 2016 at 09:03:04 UTC, Lodovico Giaretta wrote:
 On Sunday, 24 July 2016 at 02:17:27 UTC, Rufus Smith wrote:
 [...]
Now you are telling me to "program by trust", because there's nothing ensuring that I remember to free everything I allocated with malloc/free, while a GC would guarantee no memory leaks. Again there's nothing stopping me from returning pointers to things allocated on the stack. And now there are lots... Before you told me that programming by trust is a wrong attitude, and now you propose me to use it, risking memory leakage in a function that may be executed hundreds of times per second.
 [...]
No. If you put a big nogc attribute on Object.opXXX, then nobody can write GC code in his classes. So if everything is nogc, you cannont write GC code, because it woudn't interact with Phobos. Example: if you mark an algorithm that takes a delegate nogc, then you cannot pass GC delegates to it. So you cannot use it in GC code.
 [...]
Yes. All building blocks must be as much nogc as possible. But customization points (virtual functions, delegate arguments, ...) must not be nogc, otherwise it is no possible to have classes that use the GC or callbacks that use the GC.
 [...]
I still don't understand why you want Object.opXXX nogc. As I already said, you can still make your functions nogc, just accepting parameters of nogc types. It's obvious. If I wrote a wonderful library that uses the GC, you will not use it. If I have a class that uses the GC in opXXX (and I am free to have it, because maybe I need it, and maybe it's the most efficient way for my use case), you will not use it. The same applies here. You'll have your algorithms work only on classes that declare opXXX as nogc. Not all memory allocation patterns are good for malloc/free. Not all of them are good for stack allocations. Some of them are not even good for reference counting. Every class shall use the best solution for its job. And everybody must still be able to extend the base class. If you want to use a method specific to a subclass, you downcast. If you want to use the nogc opXXX when the base does not enforce it, you downcast. It's the same principle: more advanced functionalities require more derived types (and nogc is more derived, because it is covariant to not- nogc). Basic OOP.
I believe Rufus was only referring to the virtual methods defined in the object class. That would be: toHash (Note: this is already nothrow, that's intersting and quite restrictive) opCmp opEquals I think all 3 of these are good candidates for nogc. However, AFAIK, making them nogc would break any code that implements them because they would have to add the nogc attribute to their implementations (unless I am mistaken? Do subclass overrides need to explicitly have nogc if the parent class does?). If adding nogc is not required in the implementation, then the only code that would break would be implementations that actually do allocate GC memory. Some would think that restricting GC usage inside these virtual methods is a good thing because it has the benefit of discouraging memory allocation for these types of operations. Really, you probably shouldn't be allocating memory to perform a comparison. If you really need to, you can either allocate non GC memory, or use a different mechanism then the opCmp/opEquals methods.
Jul 24 2016
parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 24 July 2016 at 14:54:11 UTC, Jonathan Marler wrote:
 I believe Rufus was only referring to the virtual methods 
 defined in the object class.  That would be:

 toHash (Note: this is already nothrow, that's intersting and 
 quite restrictive)
 opCmp
 opEquals

 I think all 3 of these are good candidates for  nogc.  However, 
 AFAIK, making them  nogc would break any code that implements 
 them because they would have to add the  nogc attribute to 
 their implementations (unless I am mistaken?  Do subclass 
 overrides need to explicitly have  nogc if the parent class 
 does?).  If adding  nogc is not required in the implementation, 
 then the only code that would break would be implementations 
 that actually do allocate GC memory.

 Some would think that restricting GC usage inside these virtual 
 methods is a good thing because it has the benefit of 
 discouraging memory allocation for these types of operations.  
 Really, you probably shouldn't be allocating memory to perform 
 a comparison.  If you really need to, you can either allocate 
 non GC memory, or use a different mechanism then the 
 opCmp/opEquals methods.
Yes, making them nogc would require all existing overrides to be changed (overrides cannot throw away attributes, but must specify them explicitly as in the parent class, or stricter). The real problem making these nogc is that with the current state of things nogc implies nothrow, thus preventing exceptions (of course we should work to change this thing, and I'm personally researching convenient ways of doing it; I'll soon write a post on General about this). Remember that comparison of complex objects may require normalization, which may change the objects themselves and allocate memory. Also, comparisons may throw exceptions that need the GC (see above). So I'm personally against making those methods nogc. But I'm also against a singly-rooted hierarchy. Removing Object and having multiple class hierarchies would entirely solve the issue. But please note that you can already "do" that: if you never use Object, but always subclasses, the fact that Object isn't nogc is no longer an issue. While Object (if it exists) must support any kind of descendant (and thus cannot pose arbitrary limitations like nogc is), the roots of domain-specific hierarchies can exploit the fact that they are domain-specific to impose meaningful limitations, based on the expected usage and behaviour, and can thus be nogc. And you can either limit your algorithm inputs to objects of a specific hierarchy or, if you want it generic, use a template (read as: you don't use Object explicitly, as if it doesn't exists).
Jul 24 2016
next sibling parent reply Jonathan Marler <johnnymarler gmail.com> writes:
On Sunday, 24 July 2016 at 15:09:53 UTC, Lodovico Giaretta wrote:
 Remember that comparison of complex objects may require 
 normalization, which may change the objects themselves and 
 allocate memory.
Sure but this case will be the exception. If an application really needs this they can implement their own normalizedEquals? It wouldn't work with the comparison operators, but I don't really like to use those comparison operators for classes anyway since they do waaay to much in most cases: https://github.com/dlang/druntime/blob/master/src/object.d#L136 auto opEquals(Object lhs, Object rhs) { // If aliased to the same object or both null => equal if (lhs is rhs) return true; // If either is null => non-equal if (lhs is null || rhs is null) return false; // If same exact type => one call to method opEquals if (typeid(lhs) is typeid(rhs) || !__ctfe && typeid(lhs).opEquals(typeid(rhs))) /* CTFE doesn't like typeid much. 'is' works, but opEquals doesn't (issue 7147). But CTFE also guarantees that equal TypeInfos are always identical. So, no opEquals needed during CTFE. */ { return lhs.opEquals(rhs); } // General case => symmetric calls to method opEquals return lhs.opEquals(rhs) && rhs.opEquals(lhs); }
 ...Also, comparisons may throw exceptions that need the GC (see 
 above). So I'm personally against making those methods  nogc.
Definitely true. One thing to note is that toHash is nothrow. Whether or not this is too restrictive is definitely up for debate, but also making opCmp/opEquals nothrow wouldn't be the worst thing in the world. Of course at this point, it would likely break ALOT of code, so probably not worth it pragmatically.
 But I'm also against a singly-rooted hierarchy. Removing Object 
 and having multiple class hierarchies would entirely solve the 
 issue. But please note that you can already "do" that: if you 
 never use Object, but always subclasses, the fact that Object 
 isn't  nogc is no longer an issue.
Whoa wait a second...I didn't know you could do this. I thought everything had to inherit from the object class. Can you share the syntax to define a class that doesn't derive from object? P.S. Talking about throwing exceptions in nogc is preaching to the choir :) https://forum.dlang.org/post/ubtlemuqisxluxftsrks forum.dlang.org I've explored this issue as well, I came up with a way to throw exceptions allocated on the NonGC heap, but to clean up memory the catcher needs to do something to dereference the exception so it gets cleaned up. There is a DIP for natively supporting reference counted memory, I don't remember it, but it would allow such things to be safe to use.
Jul 24 2016
parent reply Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 24 July 2016 at 15:28:53 UTC, Jonathan Marler wrote:
 Whoa wait a second...I didn't know you could do this.  I 
 thought everything had to inherit from the object class.  Can 
 you share the syntax to define a class that doesn't derive from 
 object?
Currently, you cannot. Everything inherits from Object. I personally think this is not the best idea. But it's not that horrible either, so probably not worth a big change. But you can just ignore it. You can put on your opCmp all the attributes you want and forget about it inheriting from Object. You can decide to never write a method that takes Object. Always take the root of your sub-hierarchy, so that you know what attributes you have. If it derives from Object or not, nobody cares as long as your sub-root overrides all opXXX with new (even abstract) declarations that have nogc.
Jul 24 2016
parent Jonathan Marler <johnnymarler gmail.com> writes:
On Sunday, 24 July 2016 at 15:41:55 UTC, Lodovico Giaretta wrote:
 On Sunday, 24 July 2016 at 15:28:53 UTC, Jonathan Marler wrote:
 Whoa wait a second...I didn't know you could do this.  I 
 thought everything had to inherit from the object class.  Can 
 you share the syntax to define a class that doesn't derive 
 from object?
Currently, you cannot. Everything inherits from Object. I personally think this is not the best idea. But it's not that horrible either, so probably not worth a big change. But you can just ignore it. You can put on your opCmp all the attributes you want and forget about it inheriting from Object. You can decide to never write a method that takes Object. Always take the root of your sub-hierarchy, so that you know what attributes you have. If it derives from Object or not, nobody cares as long as your sub-root overrides all opXXX with new (even abstract) declarations that have nogc.
This is one of those problems that are going to have pros and cons either way you go. It's the balance between generality which yields facilities for sharing code, and specificity which inhibits shared code. Templates provide an interesting middle ground for this by allowing you to instantiate an infinite number of implementations that will fit wherever you want on this spectrum. But templates don't work with virtual methods :( Just spitballing here, but why weren't the methods on the Object class defined in interfaces instead? interface Hashable; interface Comparable; interface Stringable; I'm sure there's some big drawback to designing it this way, but the reason is escaping me at the moment. Can someone enlighten me? (Note: if a feature like this (http://forum.dlang.org/post/mrtgipukmwrxbpayuqkt forum.dlang.org) was implemented, the interfaces could still provide default implementations)
Jul 24 2016
prev sibling parent reply lqjglkqjsg <lqjglkqghjghjjsg lkdsf.od> writes:
On Sunday, 24 July 2016 at 15:09:53 UTC, Lodovico Giaretta wrote:
 Yes, making them  nogc would require all existing overrides to 
 be changed (overrides cannot throw away attributes, but must 
 specify them explicitly as in the parent class, or stricter).
 The real problem making these  nogc is that with the current 
 state of things  nogc implies nothrow, thus preventing 
 exceptions (of course we should work to change this thing, and 
 I'm personally researching convenient ways of doing it; I'll 
 soon write a post on General about this).

 Remember that comparison of complex objects may require 
 normalization, which may change the objects themselves and 
 allocate memory. Also, comparisons may throw exceptions that 
 need the GC (see above). So I'm personally against making those 
 methods  nogc.

 But I'm also against a singly-rooted hierarchy. Removing Object 
 and having multiple class hierarchies would entirely solve the 
 issue. But please note that you can already "do" that: if you 
 never use Object, but always subclasses, the fact that Object 
 isn't  nogc is no longer an issue. While Object (if it exists) 
 must support any kind of descendant (and thus cannot pose 
 arbitrary limitations like  nogc is), the roots of 
 domain-specific hierarchies can exploit the fact that they are 
 domain-specific to impose meaningful limitations, based on the 
 expected usage and behaviour, and can thus be  nogc. And you 
 can either limit your algorithm inputs to objects of a specific 
 hierarchy or, if you want it generic, use a template (read as: 
 you don't use Object explicitly, as if it doesn't exists).
Almost off topic but I've recognized a typical error here, I think that many of us have already seen it too. You develop a nice class. You put attributes everywhere safe pure nothrow nogc. Yay the unittest pass. Later you use it for real and you realize then that the attributes must be removed because you can't do anything in the overriden methods.
Jul 24 2016
parent Lodovico Giaretta <lodovico giaretart.net> writes:
On Sunday, 24 July 2016 at 15:31:28 UTC, lqjglkqjsg wrote:
 Almost off topic but I've recognized a typical error here, I 
 think that many of us have already seen it too. You develop a 
 nice class. You put attributes everywhere  safe pure nothrow 
  nogc. Yay the unittest pass.

 Later you use it for real and you realize then that the 
 attributes must be removed because you can't do anything in the 
 overriden methods.
That's why I'm against putting nogc on Object. You must only annotate specific sub-hierarchies that you know will never need the GC (or whatever: system, impure, throwing). This often means that you can only annotate closed hierarchies. This is correct: you must not annotate open ended classes unless you decide that you really NEED (NEED != WANT) these limitations. And your users will probably find them restrictive, so you need a compelling reason that cannot be solved in other ways.
Jul 24 2016
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/23/16 5:44 PM, Rufus Smith wrote:
 On Saturday, 23 July 2016 at 17:27:24 UTC, Lodovico Giaretta wrote:
 On Saturday, 23 July 2016 at 17:04:42 UTC, Jonathan Marler wrote:
 On Saturday, 23 July 2016 at 16:46:20 UTC, Jonathan Marler wrote:
 [...]
Actually Im going to disagree with myself. This technique actually wouldn't work with virtual methods:)
I don't think we have the big problems with nogc that people points out. I mean, we cannot decide that specific methods or opXXX must always be nogc. That's too restrictive. So, what we need to do is: - use templates: with them, we can have our algorithms be safe when applied to safe types, nogc when applied to nogc types, and so on; for example, instead of taking a specific delegate type, we shall always accept a generic type, and use traits to guarantee it is some delegate; in this way, we can accept safe delegate and propagate safety to our algorithm, or accept system and have our algorithm usable in system code; same with nogc et al. - when we use virtual methods, we are giving up all compiler-checked attributes; in this situation we have two options: - we trust what we are doing: e.g. we cannot mark a thing nogc, but we know it is and the profiler confirms that no allocation happens, so we are happy; our aim is having code that doesn't freeze because of collections, and not marking code nogc.
This is bad. It only creates a faulty foundation. The whole point of nogc is to enforce nogc behavior. If you don't use it your not enforcing anything and then things slip by only to create problems later. This mentality is completely wrong and leads to decay. This is exactly why we are discussing this right now, because someone decided that it was ok to ignore other use cases which eventually turn out to be quite important.
Again, I want to stress that Object.opEquals has been around since early D1 days, nogc is only a few years old, it was not a wrong decision. nogc cannot be added without breaking code, and even if you could, it's not correct for opEquals. The issue is one of design, Object should not define which attributes are acceptable on all objects, that should be up to the class designer. The solution is to deprecate and remove all convenience functions from Object.
 DMD should probably be branched, and all GC stuff removed, then built
 back up to have the proper features that the GC version has. I think
 someone has essentially done this on their own, but never built it up to
 full capacity.
This is an extreme solution for a minor problem. -Steve
Jul 25 2016
parent Rufus Smith <RufusSmith indi.com> writes:
On Monday, 25 July 2016 at 12:24:53 UTC, Steven Schveighoffer 
wrote:
 On 7/23/16 5:44 PM, Rufus Smith wrote:
 [...]
Again, I want to stress that Object.opEquals has been around since early D1 days, nogc is only a few years old, it was not a wrong decision. nogc cannot be added without breaking code, and even if you could, it's not correct for opEquals. The issue is one of design, Object should not define which attributes are acceptable on all objects, that should be up to the class designer. The solution is to deprecate and remove all convenience functions from Object.
 [...]
This is an extreme solution for a minor problem.
Minor for you... not for everyone. Some people despise the GC and try to write nogc code. For them it is not extreme. It is extreme for you because you are on the other side. Please don't treat your side as the only side.
Jul 31 2016
prev sibling parent Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, July 23, 2016 11:25:02 Steven Schveighoffer via Digitalmars-d-
learn wrote:
 The real problem here is that there is a base method at all. We have
 been striving to remove it at some point, but it is very difficult due
 to all the legacy code which is written.

 Almost all the Object base methods need to be removed IMO. You can add
 them at a higher level if you need them, and then specify your
 requirements for derived classes.

 Including opHash, opCmp, toString, etc.
https://issues.dlang.org/show_bug.cgi?id=9769 https://issues.dlang.org/show_bug.cgi?id=9770 https://issues.dlang.org/show_bug.cgi?id=9771 https://issues.dlang.org/show_bug.cgi?id=9772 This PR would largely fix the opEquals problem (though it doesn't deal with actually removing opEquals from Object, just making it so that you don't need it): https://github.com/dlang/druntime/pull/1439 However, it's just languished (probably because it's in druntime and not terribly interesting). But actually removing opEquals and replacing the others gets a lot more interesting (e.g. we have to finishing templatizing the built-in AAs as one of the steps), so as critical as that PR is, it's only one small step. - Jonathan M Davis
Jul 23 2016
prev sibling next sibling parent reply Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 23 Jul 2016 13:18:03 +0000
schrieb Rufus Smith <RufusSmith indi.com>:

 Trying to compare a *ptr value with a value in nogc code results 
 in the error:
 
 Error:  nogc function '...' cannot call non- nogc function 
 'object.opEquals'		
 
 Shouldn't object opEquals be marked?
The only situation that you can work around is if the 'object' is actually known to be one of your nogc objects. Then you can simply downcast before calling opEquals. It's certainly limiting, but just an artifact of OOP and I can assure you that making D usable without GC has been high on the priority list (for an community driven open-source project anyways). Phobos got reworked to get rid of unnecessary GC allocations and Andrei Alexandrescu contemplated making object's methods nogc at one point. If you need a restricted object hierarchy, you'll have to write a new "NoGcObject" base class. opEquals would still take "object", though you can avoid a dynamic cast by writing: (cast(NoGcObject)cast(void*)obj).someMethod(); The cast to void* prior to the downcast drops the class type information and a dynamic cast becomes a static cast. -- Marco
Jul 23 2016
parent reply Rufus Smith <RufusSmith indi.com> writes:
On Saturday, 23 July 2016 at 17:23:37 UTC, Marco Leise wrote:
 Am Sat, 23 Jul 2016 13:18:03 +0000
 schrieb Rufus Smith <RufusSmith indi.com>:

 Trying to compare a *ptr value with a value in nogc code 
 results in the error:
 
 Error:  nogc function '...' cannot call non- nogc function
 'object.opEquals'
 
 Shouldn't object opEquals be marked?
The only situation that you can work around is if the 'object' is actually known to be one of your nogc objects. Then you can simply downcast before calling opEquals. It's certainly limiting, but just an artifact of OOP and I can assure you that making D usable without GC has been high on the priority list (for an community driven open-source project anyways). Phobos got reworked to get rid of unnecessary GC allocations and Andrei Alexandrescu contemplated making object's methods nogc at one point. If you need a restricted object hierarchy, you'll have to write a new "NoGcObject" base class. opEquals would still take "object", though you can avoid a dynamic cast by writing: (cast(NoGcObject)cast(void*)obj).someMethod(); The cast to void* prior to the downcast drops the class type information and a dynamic cast becomes a static cast.
I am trying to write some general code that works on arbitrary types. I need to compare, obviously, as that is relatively basic thing on objects. About the only half-ass solution I can think of is to use introspection and require the type to support a nogc version of Equals. Of course, this only passes the buck. The problem is, D was designed with GC in mind, which was flawed from the get go and now trying to undo the tangled mess leads to "We can't do that because it's not backwards compatible". So one crack leads to another to another. From what I gather, this isn't just a problem with nogc but many "after the fact enhancements" that don't work the way they should because of lack of foresight on the designers of D.
Jul 23 2016
parent Jonathan M Davis via Digitalmars-d-learn writes:
On Saturday, July 23, 2016 21:33:29 Rufus Smith via Digitalmars-d-learn wrote:
 I am trying to write some general code that works on arbitrary
 types. I need to compare, obviously, as that is relatively basic
 thing on objects.
That's part of of why attribute inferrence works on templates. That way, the template isn't constrained with regards to which attributes it uses. If it can be nothrow or nogc or whatnot, then the compiler will infer it as such, and it can be used in code that requires those attributes, but if the template can't have those attributes with a particular set of template arguments, then they won't be inferred, and the template will still work, whereas if the attributes had been put on the template, it wouldn't. Templates are straight-up the solution for dealing with an arbitrary mix of attributes. Unfortunately, virtual functions are fundamentally incompatible with templates, so even if the Object is fixed so that it doesn't have opEquals, opCmp, toHash, and toString on it, the ones that are declared on derived classes are still going to have to pick a set up attributes and will restrict what further derived classed do. It's just that the programmer will then have been able to choose those restrictions in their base class rather than being forced by what druntime did with Object. Classes and generic code really don't mix well and can't mix well when the generic code needs to be part of the class instead of a free function. - Jonathan M Davis
Jul 23 2016
prev sibling next sibling parent reply Rufus Smith <RufusSmith indi.com> writes:
On Saturday, 23 July 2016 at 13:18:03 UTC, Rufus Smith wrote:
 Trying to compare a *ptr value with a value in nogc code 
 results in the error:

 Error:  nogc function '...' cannot call non- nogc function 
 'object.opEquals'		

 Shouldn't object opEquals be marked?
So, I need to compare two objects in a no-gc context? How to do this? There are several checks to be done? Memory compare good enough? (not if opEquals is defined for structs, etc...) Unfortunately, regardless of what some people say, There is a need to compare objects in a nogc context... I have the case for one. e.g., I have a nogc container and a remove(T obj). I can't search for obj and remove it because opEquals is not marked nogc. So I need an alternative that is somewhat robust.
Jul 31 2016
parent ag0aep6g <anonymous example.com> writes:
On 07/31/2016 08:43 PM, Rufus Smith wrote:
 e.g., I have a nogc container and a remove(T obj). I can't search for
 obj and remove it because opEquals is not marked nogc. So I need an
 alternative that is somewhat robust.
Jonathan M Davis has already mentioned his plans to templatize object.opEquals, which would help here. In the meantime, you can make your own comparison function and use that instead of the == operator. Note that you can add nogc when overriding Object.opEquals, and you can call such a nogc opEquals directly from nogc code. You just can't use the == operator which is implemented in object.opEquals. In code: ---- class C { override bool opEquals(Object other) const nogc { return false; } } void f(C a, C b) nogc { bool x = a == b; /* doesn't compile */ bool y = a.opEquals(b); /* compiles just fine */ } ---- object.opEquals (i.e. the == operator) does a little more than just calling a.opEquals(b). You can check the source to see what it does exactly: https://github.com/dlang/druntime/blob/master/src/object.d#L136-L156 You'd probably want to mirror that as closely as possible in a custom comparison function, so that the results are consistent with the == operator. As far as I see, you can't do the typeid thing, though, because TypeInfo.opEquals is not nogc. Ugh.
Jul 31 2016
prev sibling parent Mark "J" Twain <Juckleberry Twain.com> writes:
A hack is to create the gc code you in a function want to call, 
say does the "gc" opEquals. Then cast that function to a nogc 
version by first casting to a void*. This way you can call gc 
code from nogc code, by bypassing the compiler's ability to 
check. It will obviously break your code if you disable the gc 
completely and there are no easily ways to find the hacks(have to 
resort to marking and -vgs).


	 nogc void function() foo;
	void* bar = ()
	{        	
            // Use GC
	};
	
         alias A =  nogc void function();
	foo  = cast(A)bar;

now foo, which points to the GC based bar, but is makred nogc and 
callable in nogc code.

One can probably make a template GC2NoGC that does all this and 
to get completely off the GC, one just has to rework the 
anonymous functions(mark them nogc). So it is somewhat of a clean 
solution as it allows you to separate your gc dependencies in to 
well defined blocks that then can be addressed later when one 
truly wants to get off the GC.
Aug 02 2016