July 28, 2016
On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:
> On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:
>> On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:
>>>
>>> It's not about running out of memory. It's a performance issue.
>>>
>>> Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.
>>>
>>
>> Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
>
> I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler.
>
> The situation is similar to using @safe. You *could* just write code however you want, wait until it crashes, then try to find the problem using Valgrind or something, but that's bad for obvious reasons.
>
>     Bit

Just my 2 cents on naming: what you want sounds a lot more like @warngc than @assumenogc or whatever was floating around before. What such an attribute should do and if its worth implementing is hard to figure out, though. Presumably you'd have your update() method marked @warngc but then how is the compiler supposed to know that an allocation like this:

class A {
    void update() @warngc {
        if(rareCondition()) {
            // something that allocates
        }
    }
}

is perfectly fine, but something like this

class B {
    void update() @warngc {
        if(almostAlwaysTrue()) {
            // something that allocates
        }
    }
}

is not?
That issue aside, what exactly do you envision the compiler to tell you (examples of error messages and code patterns it should detect, examples of code patterns that it should NOT detect and are fine) incase it automagically finds problematic code?

I'm having trouble putting a thumb on what you want following this thread, because what you are describing feels a bit vague to me.
July 28, 2016
On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:
> On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:
>> On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:
>>>
>>> It's not about running out of memory. It's a performance issue.
>>>
>>> Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.
>>>
>>
>> Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
>
> I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler.

Well, here in my opinion there's the wrong attitude of profiling only when it becomes necessary (i.e. the app is slow or uses too much ram). This is wrong. You should profile before this happens; you should profile to see if the time/memory is spent in the parts of the application that should spend it and you should profile whenever you care about making good code and not just "code that works". You should profile while you add features, to see their impact on the overall performance. Profiling at the end, when you have a 100K LOC codebase deployed, because a user ran out of memory is too late: too late to allow to easily spot the problem and too late to think an alternative approach/algorithm/design, instead of just patching the problem.
July 28, 2016
On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:
> ...

I like the  typo in the title. Let's make a game:

"write the `bypassign` function, its ddoc, and its unittests"

:)

July 28, 2016
On Thursday, 28 July 2016 at 17:54:20 UTC, jdfgjdf wrote:
> On Sunday, 24 July 2016 at 22:13:02 UTC, bitwise wrote:
>> ...
>
> I like the  typo in the title. Let's make a game:
>
> "write the `bypassign` function, its ddoc, and its unittests"
>
> :)

Entry one:

/**
 * Bypassign is a struct wrapper that bypasses the original type's `opAssign()`,
 * thus any assignation to the wrapped type is a noop.
 */
struct Bypassign(T)
if (is(T == struct))
{
    private T _bypassigned;
    alias _bypassigned this;
    void opAssign(T)(auto ref T t)
    {/*bypassignation*/}
}
///
unittest
{
    static struct Foo
    {
        int i;
        alias i this;
    }
    Bypassign!Foo bpaFoo;
    bpaFoo = 1;
    assert(bpaFoo == 0);
}


July 28, 2016
On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:
> While working on a past project(C++), I found this little gem:
>
> void draw() {
>     Font* f = new Font("arial.ttf", 16);
>     drawText(f, "hello world");
> }

It sounds like -vgc and --profile=gc are exactly what you want. @nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.
July 28, 2016
On Thursday, 28 July 2016 at 16:58:14 UTC, default0 wrote:
> On Thursday, 28 July 2016 at 16:45:05 UTC, bitwise wrote:
>> On Thursday, 28 July 2016 at 16:15:04 UTC, Guillaume Piolat wrote:
>>> On Thursday, 28 July 2016 at 15:24:10 UTC, bitwise wrote:
>>>>
>>>> It's not about running out of memory. It's a performance issue.
>>>>
>>>> Example: In the following class, it would be perfectly fine, and even expected to allocate in start() but not in update(). This is because start() gets called once on object initialization, but update() would get called every frame.
>>>>
>>>
>>> Vladimir implemented counting in -profile=gc, it gives you the number of allocations and the amount allocated for each allocation point.
>>
>> I'm not sure if this point is meant to be for or against what I'm suggesting, but still, I'm thinking in terms of *proactively* writing efficient code, not allowing an app get to the point where you need to run a profiler.
>>
>> The situation is similar to using @safe. You *could* just write code however you want, wait until it crashes, then try to find the problem using Valgrind or something, but that's bad for obvious reasons.
>>
>>     Bit
>
> Just my 2 cents on naming: what you want sounds a lot more like @warngc than @assumenogc or whatever was floating around before. What such an attribute should do and if its worth implementing is hard to figure out, though. Presumably you'd have your update() method marked @warngc but then how is the compiler supposed to know that an allocation like this:
>
> class A {
>     void update() @warngc {
>         if(rareCondition()) {
>             // something that allocates
>         }
>     }
> }
>
> is perfectly fine, but something like this
>
> class B {
>     void update() @warngc {
>         if(almostAlwaysTrue()) {
>             // something that allocates
>         }
>     }
> }
>
> is not?
> That issue aside, what exactly do you envision the compiler to tell you (examples of error messages and code patterns it should detect, examples of code patterns that it should NOT detect and are fine) incase it automagically finds problematic code?
>
> I'm having trouble putting a thumb on what you want following this thread, because what you are describing feels a bit vague to me.

I think you're complicating the issue quite a bit here.

It's very simple:

@nogc { /* in this scope, compiler disallows GC allocations. */ }

@nogc {
    @assumenogc { /* here, GC allocations are allowed */  }
}

@assumenogc would simply reverse the effects of the @nogc flag on a given scope.

So @nogc could be applied to performance critical scopes, as it is now. The exception would be, that if I as a programmer knew that I was only making a small one-time allocation, and that the GC was still enabled, I could do so by surrounding the allocation with @assumenogc.

    Bit

July 28, 2016
On Thursday, 28 July 2016 at 18:53:35 UTC, Meta wrote:
> On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:
>> While working on a past project(C++), I found this little gem:
>>
>> void draw() {
>>     Font* f = new Font("arial.ttf", 16);
>>     drawText(f, "hello world");
>> }
>
> It sounds like -vgc and --profile=gc are exactly what you want. @nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.

I understand that @assumenogc may not be exactly the right approach, but the underlying idea is sound, which is to have the compiler to disallow all GC allocations in some annotated scope, just like @nogc, but to allow the programmer to override the @nogc restriction in certain cases.

There may be alternative approaches, and the @warngc idea was just one random suggestion.

The point is, a mixture of @nogc and @assumenogc would achieve exactly what I'm looking for. The only problem is that it may cause issues for people that are using @nogc under a different set of assumptions.

    Bit

July 28, 2016
On Thursday, 28 July 2016 at 20:32:18 UTC, bitwise wrote:
> On Thursday, 28 July 2016 at 18:53:35 UTC, Meta wrote:
>> On Thursday, 28 July 2016 at 00:23:57 UTC, bitwise wrote:
>>> While working on a past project(C++), I found this little gem:
>>>
>>> void draw() {
>>>     Font* f = new Font("arial.ttf", 16);
>>>     drawText(f, "hello world");
>>> }
>>
>> It sounds like -vgc and --profile=gc are exactly what you want. @nogc is meant to *guarantee* that the GC will not be called within a function or any other functions called by that function. Taking that guarantee away makes it effectively useless.
>
> I understand that @assumenogc may not be exactly the right approach, but the underlying idea is sound, which is to have the compiler to disallow all GC allocations in some annotated scope, just like @nogc, but to allow the programmer to override the @nogc restriction in certain cases.
>
> There may be alternative approaches, and the @warngc idea was just one random suggestion.
>
> The point is, a mixture of @nogc and @assumenogc would achieve exactly what I'm looking for. The only problem is that it may cause issues for people that are using @nogc under a different set of assumptions.

Also, @assumenogc or whatever does not play well with public APIs: if a library function is marked @nogc, its user can no longer know if it is really @nogc or if it does allocate via @assumenogc. This is not a good thing, as the user may want *absolutely* no GC allocation in his program, and may even have disabled the GC at program startup. Also, the code of that maybe-not-@nogc library may not be available to check for this thing. Maybe the user doesn't want to trust the library writer, and so wants the compiler to guarantee no allocations at all.
July 28, 2016
On 07/28/2016 10:46 PM, Lodovico Giaretta wrote:
> Also, the code of that maybe-not-@nogc library may not be available to
> check for this thing. Maybe the user doesn't want to trust the library
> writer, and so wants the compiler to guarantee no allocations at all.

If you can't check the code, you have to trust the library writer. One can hack around @nogc as it is. It's not like dmd checks the object file for GC allocations.
July 28, 2016
On Thursday, 28 July 2016 at 21:07:22 UTC, ag0aep6g wrote:
> On 07/28/2016 10:46 PM, Lodovico Giaretta wrote:
>> Also, the code of that maybe-not-@nogc library may not be available to
>> check for this thing. Maybe the user doesn't want to trust the library
>> writer, and so wants the compiler to guarantee no allocations at all.
>
> If you can't check the code, you have to trust the library writer. One can hack around @nogc as it is. It's not like dmd checks the object file for GC allocations.

Yeah... So on one hand, currently, you could potentially have some random hack misbehaving inside @nogc code with no way to detect it, whereas a simple search for @assumenogc would immediately tell you if the @nogc convention was being broken for any reason. On the other hand, adding @assumenogc may increase the amount of instances where this is happening, cause this search to be mandatory for every package you decide to download.

Maybe if there were 3 variations, this could work:

// use current convention. 100% guarantee, no allocations.
@nogc

// same as current, but restriction can be broken by @nogc(off)
@nogc(weak)

// allows allocations. Can only override @nogc(weak), but not @nogc.
@nogc(off)


Example:

class NPC {
	Cake cake;
	void start() {
		cake = new Cake();  // OK
	}
	void update() @nogc(weak) {
		cake = new Cake();     // error: cannot allocate here
		@nogc(off) {
			cake = new Cake();  // ok: alloc allowed in @nogc(off)
		}
	}
	void draw() @nogc {
		@nogc(off) {    // error: @nogc(off) not legal inside @nogc
			cake = new Cake();
		}
		bar(); // error: nogc(weak) not callable here
	}
	void bar() @nogc(weak) { }
}

1 2 3 4
Next ›   Last »