September 01, 2012
On 01-Sep-12 16:27, Peter Alexander wrote:
> On Saturday, 1 September 2012 at 11:37:39 UTC, Piotr Szturmaj wrote:
>> It's similar behavior to nothrow and pure. Instead of manually
>> avoiding GC allocations, compiler does this checks for you. Imagine D
>> doesn't have nothrow. You'd have to check every called function to see
>> if it doesn't throw. In big programs throwing function may be left
>> unnoticed and this is why we have static nothrow checks in D.
>
> I understand the benefit. However, there are at least two significant
> costs:
>
> 1. If I want my entire program to be GC free, I have to annotate every
> single function with 'nogc'. This is not something I want to do.
>

I'd say
@nogc:
at the top and deal is sealed.

> 2. It's a new language feature and has all the associated costs: initial
> implementation, bug fixing, marking up of functions in Phobos,
> documentation, etc.
>

> Yes, with my approach, a rare allocation may go unnoticed, and you end
> up with an undesirable GC collection sometime in the future. It's not
> great, but it's not the end of the world, and I'm willing to risk that
> to avoid the costs I mentioned above.


-- 
Olshansky Dmitry
September 01, 2012
On Saturday, 1 September 2012 at 12:39:41 UTC, Dmitry Olshansky wrote:
> I'd say
> @nogc:
> at the top and deal is sealed.

BTW don't forget a @yesgc would be good to counter it. We need
a way to turn off each attribute to use this pattern best.
September 01, 2012
Le 01/09/2012 14:29, Dmitry Olshansky a écrit :
> On 01-Sep-12 15:47, Piotr Szturmaj wrote:
>> bearophile wrote:
>>
>>> The Koka language has a function annotation similar to @noheap, I have
>>> discussed a little about Koka here:
>>> http://forum.dlang.org/thread/ocxmiolhlcysehbjtcop@forum.dlang.org
>>> but Koka has type inference for effects, so often you don't need to add
>>> that annotation to functions.
>>
>> Well, __traits(hasGCallocations, func) will also do the trick.
>
> Make it __traits(hasAttribute, "nogc", func) and that might be something.
> Actually, I'd love to see some proposal that
> a) clarifies how @attributes are supposed to be used
> b) adds generic infrastructure to to use them via __traits or whatever
>

+1
September 01, 2012
C:

int mul(int x, int y);


Future D:

pure @safe nothrow nogc commutative associative distributive @forceinline mayoverflow int mul(int x, int y);

September 01, 2012
C:

int mul(int x, int y);


Future D:

pure @safe nothrow nogc commutative associative distributive @forceinline mayoverflow int mul(int x, int y);

September 01, 2012
On 01-Sep-12 19:58, Peter Alexander wrote:
> C:
>
> int mul(int x, int y);
>
>
> Future D:
>
> pure @safe nothrow nogc commutative associative distributive
> @forceinline mayoverflow int mul(int x, int y);
>

No it's GNU C++ of today just replace 'pure' with __attribute__((pure))
and you are done :)
And don't even get me started at MS extensions...

Either way this is a kind of thing that only some users need but std library have to use all of them just so that those 'some users' can use it.

In fact if pure @safe nothrow could be combined in a user defined tag:

alias pure @safe nothrow nogc nice_func;

nice_func int mul(int x, int y);

and even C has it via macros, damn...

-- 
Olshansky Dmitry
September 01, 2012
On 01-Sep-12 17:01, Adam D. Ruppe wrote:
> On Saturday, 1 September 2012 at 12:39:41 UTC, Dmitry Olshansky wrote:
>> I'd say
>> @nogc:
>> at the top and deal is sealed.
>
> BTW don't forget a @yesgc would be good to counter it. We need
> a way to turn off each attribute to use this pattern best.

What I see with this @nogc proposal is that that problem it tries to solve (and tool used to do so) is far more interesting and general.

Namely the problem is to specify that some functions can call only specific subset of functions and able to use only specific subset of language features. It's more far reaching then just gc, one may want to get @noblocking  or @async attribute to statically check e.g. that GUI thread can't ever block.
(it would however require to identify API calls that don't block, not possible on every OS, might entail some wrappers etc. but is very desirable)

To peek at what's more there that you can get this way see C++ AMP on why restricting a block of code or function is useful
e.g. here by Herb Sutter (including nice demo!):
http://www.youtube.com/watch?v=HK9rJFpX32Y

BTW @safe is in the same bucket, it does allow only to call @safe & @trusted (read as "subset of ") functions and use a subset of language features.

Actually exactly the same goes for pure (noglobal whatever) you just state this piece of code can't use this language feature (global variables, static variables, you name it), same for nothrow.

And not long ago David Nadlinger showed that function level trusted doesn't help much with templates that are @trusted for their own code, but need normal safety guarantee from foreign code brought by parameters. Thus restriction has to be able to work on a block scope too.

So what I want with this? I want to bring together C++ AMP restrict and @safe/@trusted/@system/pure/nothrow machinery in one clean and user-extensible future-proof feature.

The idea in a nutshell:

- specify a way attach tags to function declarations (to "paint" functions)

- allow specifying is-a relation between tags (supertags and subtags).

- add restrict specification that allows user to enforce on a block of code the following:
	a) disallow use of certain language features
	b) allow(or disallow) calling function with specific tags

- fit with existing world and provide clean migration path, specify defaults

I claim that it's enough to implement pure/safe/trusted/nothrow/nogc and proposed nogc.


The following is the draft of proposal.

1. Introduce a restrict keyword. Restrict applies to a block of code or a function:

auto foo(...) restrict(<restriction spec>)
{
	
}

auto bar(...)
{
	restrict(<restriction spec>){
	}
}

And the usual

restrict(<restrict spec>):

to affect all subsequent declarations in the module.

Multiple restrict blocks on the same declaration are treated as single restrict with restrict specifications concatenated.

The effect of such a clause is that declarations and statements inside of a block have to pass restriction check in order to compile.
The kind of check is described in restrict specification.

2. Functions declared with restrict(<restrict spec>) can only be bound by function pointer of more permissive type w.r.t. spec:

(assume A,B,C,D,E are elements of spec)
void funcABCD() restrict(A,B,C,D);
void funcACD() restrict(A,C,D);


function void() restrict(A,B,D) fp;
fp = &funcABCD; ///okay, fp is more permissive
fp = &funcACD; //fail, B is allowed inside of funcACD but not by fp

3. Function tags. Tag is a special literal associated with function declaration and type of function pointer. Any FP or function declarations can have an arbitrary amount of tags attached:

@tag(mytag, safe, nothrow)
void foobar();

function void () @tag(default, nothrow)
Every function without tags has one implicit 'default' tag (name clashes with 'default' keyword may require another name). To only add tags include 'default' among others and to override it just don't list default.

User defined tags are specified as follows:

@tag tag_name; //new tag called tag_name

@tag tag_name : supertag; //tag_name is a subtag of super tag

The following tags are declared in object.d:

//pure is subtag of default, address of pure function can be assigned to default FP
@tag pure : default;
@tag system : default; //and system is subtag of default
@tag nothrow: default;
@tag trusted: system;
@tag safe: trusted;

Any assignments of FP allows only compatible pointer types.
Namely for the left hand side of assignment exp (LHS) and the right hand side (RHS):
all of RHS tags must have super tag or direct match in LHS's set of tags.

4. Restrict specifications

Introduce a list of language features that can be enabled/disabled with descriptive names, the list may be extended in the future.
Common suspects are:
	- heap stack frames and implicit GC actions
	- ability to declare/access kinds of variables (immutable, shared, static ...)
	- pointers to functions
	- pointers to ...
	- virtual functions
	- labels & goto
	- RTTI
	- inline assembler
	- pointer arithmetic
	- unions & reinterpret casts
	- C and D style varargs
	- other casts (integer/float coercing, const, dynamic)
	- exceptions
	...

each of those should have an IDs akin to __traits like 'virtual_calls', 'gc' etc. Also all of the built-in names are reserved in a tags namespace.

Restrict specification is a comma separated list of:
1) tag - allow to call only functions that have tag 'tag' or have supertag of 'tag'

2) language_feature_id - disable feature with name language_feature_id

5. Backward compatibility.
@safe, @trusted, @system, nothrow and pure work as aliases respectively:
@safe - @tag(safe) restrict(safe)
@trusted - @tag(trusted) restrict(trusted)
@system - @tag(system) restrict(system)
pure - @tag(pure) restrict(globals, static, pure)
nothrow - @tag(nothrow) restrict(nothrow)

Sometime later these could be deprecated or left as simple shortcuts.

6. Probably we need a way to alias a list of restictions to ease the use of frequent combinations. (No idea, but any sane syntax around alias will do)

-- 
Olshansky Dmitry
September 01, 2012
On Saturday, 1 September 2012 at 16:20:14 UTC, Dmitry Olshansky
wrote:
> On 01-Sep-12 17:01, Adam D. Ruppe wrote:
>> On Saturday, 1 September 2012 at 12:39:41 UTC, Dmitry Olshansky wrote:
>>> I'd say
>>> @nogc:
>>> at the top and deal is sealed.
>>
>> BTW don't forget a @yesgc would be good to counter it. We need
>> a way to turn off each attribute to use this pattern best.
>
> What I see with this @nogc proposal is that that problem it tries to solve (and tool used to do so) is far more interesting and general.
>
> Namely the problem is to specify that some functions can call only specific subset of functions and able to use only specific subset of language features. It's more far reaching then just gc, one may want to get @noblocking  or @async attribute to statically check e.g. that GUI thread can't ever block.
> (it would however require to identify API calls that don't block, not possible on every OS, might entail some wrappers etc. but is very desirable)
>
> To peek at what's more there that you can get this way see C++ AMP on why restricting a block of code or function is useful
> e.g. here by Herb Sutter (including nice demo!):
> http://www.youtube.com/watch?v=HK9rJFpX32Y
>
> BTW @safe is in the same bucket, it does allow only to call @safe & @trusted (read as "subset of ") functions and use a subset of language features.
>
> Actually exactly the same goes for pure (noglobal whatever) you just state this piece of code can't use this language feature (global variables, static variables, you name it), same for nothrow.
>
> And not long ago David Nadlinger showed that function level trusted doesn't help much with templates that are @trusted for their own code, but need normal safety guarantee from foreign code brought by parameters. Thus restriction has to be able to work on a block scope too.
>
> So what I want with this? I want to bring together C++ AMP restrict and @safe/@trusted/@system/pure/nothrow machinery in one clean and user-extensible future-proof feature.
>
> The idea in a nutshell:
>
<snip details>

I skipped the details but I do agree with the general sentiment.
This long post begs the question - Why a general annotation
mechanism isn't enough to justify adding so much complexity to
the language?

Me thinks that simply tagging malloc/alloca/GC.allocate/etc..
with a _user defined_ annotation should be sufficient without the
need to introduce all of the above syntax to the language. In
fact, I have a vague memory of reading about green/red marking of
code via templates in plain old c++. No extra syntax required.

Here's the link:
http://www.artima.com/cppsource/codefeaturesP.html
September 01, 2012
On 02-Sep-12 01:13, foobar wrote:
[snip]
>
> I skipped the details but I do agree with the general sentiment.
> This long post begs the question - Why a general annotation
> mechanism isn't enough to justify adding so much complexity to
> the language?

It's quite short compared to all of the features it replaces and it had to allow for backwards compatibility. And it had to leave place for other @annotations as I felt restricting blocks of code is not the only use case for annotations.

Also sadly it reiterates a lot of trivia around how tagged functions and pointers interact with each another.

About general annotation mechanism. Nobody yet put together a proper proposal (if any at all), all I see is people that keep saying: "it's simple - just add the general annotation mechanism!".


> Me thinks that simply tagging malloc/alloca/GC.allocate/etc..
> with a _user defined_ annotation should be sufficient without the
> need to introduce all of the above syntax to the language.

Simple tags have no much use on their own - need syntax to use them.
The compiler can deduce their meaning so you also need a way tell the compiler: this function can only use "yellow" and "green" functions. Then some tags need to be compatible (or convertible with others), then there is a need to bundle tags together and so on.

I agree that simply tagging functions with red/green is attractive and simple concept but to implement things like say @safe you need more then that. You need to tweak what compiler puts in there for you (and forbid/allow as it suits your needs).

 In
> fact, I have a vague memory of reading about green/red marking of
> code via templates in plain old c++. No extra syntax required.
>
But xxtra works obviously :)
The method entails carrying around tag arguments apparently. It could be labeled as creative but a very backward way to do something simple. More specifically it shows that this has to be a language feature so that developers can focus on using it instead of being busy implementing it by hand.

> Here's the link:
> http://www.artima.com/cppsource/codefeaturesP.html


-- 
Olshansky Dmitry
September 02, 2012
On 2012-09-01 11:54:10 +0000, Piotr Szturmaj <bncrbme@jadamspam.pl> said:

> Michel Fortin wrote:
>>> If some of the function's arguments take references (directly or
>>> indirectly), then all of them are automatically added to the list of
>>> GC roots (addRoot()).
>> 
>> You still have a problem: you might have added an object passed as an
>> argument to the GC roots, preventing the GC from collecting it, but if
>> any thread is allowed to mutate a pointer inside this object pointing to
>> some other data, using this other data in your thread is not safe,
>> unless you have added a root for this other pointer too. You'd have to
>> recursively add roots for this to work.
>> 
>> There's also the same issue with global variables, the ones which are
>> pointers to other pointers.
> 
> Yes, there is no obvious solution, but I think it could be done. For example non-immutable references may be disallowed at all.

That would be sufficient to enforce the guaranties, but it's a severe limitation that'll cause people to question the usefulness of the whole thing.

> The other solution is to copy the whole referenced object using malloc, and add it to the GC roots.

Having to copy everything is also severe limitation I think. And even then it's not that simple to correctly copy a data structure if you want that to be done automatically. If you want it to be done manually, then how can you tell that the resulting pointer, and everything it points to, is not allocated from the GC heap?

-- 
Michel Fortin
michel.fortin@michelf.ca
http://michelf.ca/