Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add @default attribute #236

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Add @default attribute #236

wants to merge 1 commit into from

Conversation

dkorpel
Copy link
Contributor

@dkorpel dkorpel commented Dec 6, 2022

No description provided.

@ichordev
Copy link
Contributor

ichordev commented Dec 7, 2022

After reading through it a couple of times, I think I got the idea. "@default removes all non-default properties and attributes."
It's a cool idea, but I'm not sure it'll be very easy to read in practice? Another concern of mine is also that it might be a mess if the default attributes change. Of course, that's fairly unlikely, but if everyone was used to explicitly annotating functions then it'd be less of a big deal.
I'm also unsure if it's the most elegant solution. In this case it's nice:

pure:
void myPureFn(){}
void myImpureFn() @default{}

But in this case, not so much:

@nogc nothrow pure @safe:
void myPureFn(){}
void myImpureFn() @default @nogc nothrow @safe{}

That said, it does eliminate the headache of having to remember what exact properties attributes are collectively applicable for the current function:

@nogc @trusted:
void myFn1(){}
nothrow pure:
void myFn2(){}
void myFn3() @nothrow(default) @safe(default){} //what is happening!?!?

Overall, it's probably one of the better approaches to this issue I've seen proposed.


In this case, the `toString` method should not force the provided Output Range to have an implementation of `sink.put` with all function attributes, but
neither should `toString` be denied those attributes when it can infer them.
The only option here is to place all template methods above the `@nogc nothrow pure @safe:` line, or go back to 'attribute soup' by repeating all function attributes for individual members.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When writing the only, there should come 1 option, not two. Also, a third option exists: @attribute { … }.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When writing the only, there should come 1 option, not two. Also, a third option exists: @attribute { … }.

Having to end an attribute{ /*...*/ } block and start it again just for 1 declaration is a hassle. Meanwhile, inverting an attribute (@gc/throw) or using @default helps the reader understand that the block they're in has a @nogc/nothrow or non-default attribute applied to it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When writing the only, there should come 1 option, not two. Also, a third option exists: @attribute { … }.

You're right, I'll rewrite it

The only option here is to place all template methods above the `@nogc nothrow pure @safe:` line, or go back to 'attribute soup' by repeating all function attributes for individual members.

What is really desired is something to specify that attributes on `toString` should go back to the default state,
which this DIP proposes in the form of the `@default` attribute.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially for the case of templates, alternatively, we could change the language so that attributes are inferred unless they are applied directly to the template. Colon and brace attributes need not matter. With the proposal, @default is a niche thing I have to remember.


// ...

void f(T)(T x) @nogc(default) @nothrow(default) pure(default) @safe(default)
Copy link
Contributor

@Bolpat Bolpat Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a template, it is not clear what @safe(default) even means. On a regular function, @safe(default) is the same as @system, but on a template, it seems to be mean infer. Better: Just use “infer” instead of “default” everywhere or make “default” mean “infer attributes” everywhere.
Inferring could be done with @safe(auto) or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not part of the proposal, it's listed as an alternative and criticized for its verbosity. Whether you call it default or infer or auto, it doesn't change the point.

The syntax `@default` is chosen because `default` is already a reserved keyword, but it may not be the clearest name.
A different name, such as `@reset`, could be considered, despite it potentially being used as a User Defined Attribute already.

The `@` could be omitted when using the `default` keyword, but it is suggested to keep it to make it clear it's related to attributes, and not types or the `default` statement.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a declaration context, nothing is nowhere near a statement, including default statement in D. A lot of function attributes have no @ in front of them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get what you're saying. ("nothing is nowhere near a statement"?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A lot of function attributes have no @ in front of them.

That's the converse of what I'm saying. Things starting with @ imply attributes, that doesn't mean it holds the other way around as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default keyword is only used for the default: case in a switch statement; the spec calls this a DefaultStatement. Function attributes are quite far removed from switch statements, there is no possible conflation. (I hope this clarified the confusing sentence.)
Having a keyword after @ would be quite novel, actually. The @ attributes were introduced as a workaround because the desired keyword (safe, trusted, system, nogc, property, disable, and live) was a legal identifier and not already a keyword, and making it one would have resulted in breakage, and because Walter opposes contextual keywords. With the @, it resulted in (almost) no breakage. For default, this reasoning does not apply. When return became a function attribute, it was not @return. I just don’t see why default warrants an exception. The position where default would appear implies “attribute” according to D syntax.

@Bolpat
Copy link
Contributor

Bolpat commented Dec 14, 2022

Thinking it through, this can be an extension of @safe(boolExpr): @safe means @safe(true) and @safe(auto) means “infer if @safe or not”. In contrast C++’s noexcept(expr) expression (that returns true when expr is noexcept), in D, isSafe can be a simple overload set and be used like @safe(isSafe({ stmts; })):

bool isSafe(void delegate()) @safe { return false; }
bool isSafe(void delegate() @safe) @safe { return true; }

@default (or just default) could (should?, by its name) be an abbreviation for all the named and unnamed function attributes that are the language default for the construct, i.e. @default represents @safe(default) (= @system), const(default) (= mutable), pure(default) (= impure), public(default) (= private for imports, public for everything else) etc., and @auto could be an abbreviation for a similar sequence with auto as its argument, i.e. infer all except visibility attributes, which cannot possibly be inferred. What it includes is up for debate because e.g. const could in principle be inferred.

@Bolpat
Copy link
Contributor

Bolpat commented Dec 14, 2022

Another problem this DIP might have is that attribute: is increasingly frowned upon for attributes that are not either visibility attributes or – maybe – really and absolutely by the nature of the aggregate or module of that property.
Visibility attributes have sane defaults in D and are rarely needed, also they’re never inferred and can be undone easily.
People (myself included) will say: If you happen to find yourself in needing @default, just don’t use attribute: or attribute { … }. It makes it even harder to figure out what attributes apply to a declaration.

@ichordev
Copy link
Contributor

ichordev commented Dec 14, 2022

If you happen to find yourself in needing @default, just don’t use attribute: or attribute { … }. It makes it even harder to figure out what attributes apply to a declaration.

If you can record a video of yourself writing 100 empty functions in a attribute{ /*...*/ } block, and then the same but manually writing the annotations for each function by hand (which should be @nogc nothrow @safe pure pragma(inline,true) deprecated("Scheduled for removal in version 3.0, please use nameHere instead."), of course) but in the same amount of time as the first video with you typing at the same speed... then maybe I'll be convinced. ;)

Jokes aside, no I'm not wasting my time with that. Even Phobos uses attribute: all over the place. @nogc nothrow: is really useful when you want all your code to be BetterC compatible, but @nogc on CTFE'd lambdas disallows string concatenation! A travesty! Hence, @gc or @default or whatever would be very useful for the ONE piece of CTFE-only code I write in the middle of code that has to have a bunch of specific attributes.

@dkorpel
Copy link
Contributor Author

dkorpel commented Dec 15, 2022

Another problem this DIP might have is that attribute: is increasingly frowned upon for attributes that are not either visibility attributes or – maybe – really and absolutely by the nature of the aggregate or module of that property.

How do you know it's "increasingly frowned upon"?

If you happen to find yourself in needing @default, just don’t use attribute: or attribute { … }.

My code has 171 occurences of the line @nogc nothrow pure @safe: and 32 of nothrow pure @safe:. I don't want to repeat those attributes even more than that, it clutters all the function signatures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants