July 24, 2016
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.



July 24, 2016
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.
July 24, 2016
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.
July 24, 2016
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.
July 24, 2016
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)

July 25, 2016
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
July 31, 2016
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.




July 31, 2016
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.

July 31, 2016
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.
August 02, 2016
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.



1 2 3
Next ›   Last »