www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Optional tags and attributes

reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
Hopefully, now I'm posting to the right place (instead of 
.announce like last time >_<).

Is there a way to make function tags and attributes optional? For 
example, C++ has noexcept tag that takes an optional bool that 
actually enables or desables the whole specifier. I find its uses 
in C++ somewhat painful due to clumsy template syntax, but the 
value is there.

I found a discussion from 2010 about doing something similar in 
D, but it doesn't seem to have went far, and I don't know if 
anything has been done in this direction.



In essence, here's what I mean:

import std.traits;

template isNoThrow(alias func) {
   enum bool isNoThrow = (functionAttributes!func & nothrow_) != 0;
}

void thisIsSoPolymorphic(T)(T t) nothrow(isNoThrow!(T.unsure)) {
   // ...
   t.unsure();
   // ...
}

Without this behavior, I basically have to either drop nothrow 
entirely (bummer), or make two functions enclosed in static if 
checks, which obviously blows up if I want to make more tags 
optional.
Jan 17 2014
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
Templates automatically infer their attributes based on the 
input, so you don't have to specify them there.

If you do a foo!(nothrow_function)(), foo is also nothrow 
(unless, of course, it throws!)
Jan 17 2014
parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 00:23:14 UTC, Adam D. Ruppe wrote:
 Templates automatically infer their attributes based on the 
 input, so you don't have to specify them there.

 If you do a foo!(nothrow_function)(), foo is also nothrow 
 (unless, of course, it throws!)
This doesn't apply here. I'm not using function as a template paramter. That's the whole case here. Suppose I'm writing a template class that's parametrized by some type, and in my method I want to call methods of that type. I cannot make any of my functions nothrow until I am sure the methods I call will not throw, and the compiler will tell me. And how can I be sure they don't throw if it's an arbitrary type? I can check it, sure, with that isNoThrow() template. But how then to use that information in my own function declaration?
Jan 17 2014
parent reply "Rikki Cattermole" <alphaglosined gmail.com> writes:
On Saturday, 18 January 2014 at 00:32:53 UTC, Stanislav Blinov 
wrote:
 On Saturday, 18 January 2014 at 00:23:14 UTC, Adam D. Ruppe 
 wrote:
 Templates automatically infer their attributes based on the 
 input, so you don't have to specify them there.

 If you do a foo!(nothrow_function)(), foo is also nothrow 
 (unless, of course, it throws!)
This doesn't apply here. I'm not using function as a template paramter. That's the whole case here. Suppose I'm writing a template class that's parametrized by some type, and in my method I want to call methods of that type. I cannot make any of my functions nothrow until I am sure the methods I call will not throw, and the compiler will tell me. And how can I be sure they don't throw if it's an arbitrary type? I can check it, sure, with that isNoThrow() template. But how then to use that information in my own function declaration?
Perhaps using template if statements and pure functions. A little like how I implemented some of Dvorm's[0] utility functions. That way it can execute at compile time. You can pass the type to it and check any method you would call if its nothrow or not via traits. That way you can have two declarations but with one being opposite of the if. [0] https://github.com/rikkimax/Dvorm/blob/master/src/orm/util.d#L31
Jan 17 2014
parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 00:42:35 UTC, Rikki Cattermole 
wrote:
 Perhaps using template if statements and pure functions. A 
 little like how I implemented some of Dvorm's[0] utility 
 functions. That way it can execute at compile time. You can 
 pass the type to it and check any method you would call if its 
 nothrow or not via traits.
Obviously I didn't explain myself clearly. I know how to determine if a function is nothrow or pure or safe or anything else thanks to D's awesomeness :) But what I want is a way to *use* that knowledge when declaring my own functions. Or rather, tell the compiler "Wait, I really want this to be nothrow, but I don't know if that function will throw. Here's a check for you, please make me nothrow if it passes". After all, tags are not just for enforcing correctness at compile time, they can be used (once verified) for optimization too. So it'd be nice to find a way to provide all the nice info to the compiler whenever possible. It's not just about nothrow, but also pure, safe/ system/ trusted, hell, even public/protected/private for that matter. :)
 That way you can have two declarations but with one being 
 opposite of the if.
...Or four in case I'd also want pure/not pure, or nine if I'd also want safe/not safe...
Jan 17 2014
parent reply "Rikki Cattermole" <alphaglosined gmail.com> writes:
On Saturday, 18 January 2014 at 00:57:27 UTC, Stanislav Blinov 
wrote:
 Obviously I didn't explain myself clearly. I know how to 
 determine if a function is nothrow or pure or  safe or anything 
 else thanks to D's awesomeness :) But what I want is a way to 
 *use* that knowledge when declaring my own functions. Or 
 rather, tell the compiler "Wait, I really want this to be 
 nothrow, but I don't know if that function will throw. Here's a 
 check for you, please make me nothrow if it passes". After all, 
 tags are not just for enforcing correctness at compile time, 
 they can be used (once verified) for optimization too. So it'd 
 be nice to find a way to provide all the nice info to the 
 compiler whenever possible. It's not just about nothrow, but 
 also pure,  safe/ system/ trusted, hell, even 
 public/protected/private for that matter. :)

 That way you can have two declarations but with one being 
 opposite of the if.
...Or four in case I'd also want pure/not pure, or nine if I'd also want safe/not safe...
Okay, I'll explain what I was inferring. If the methods your calling are lets say nothrow which can be checked by a pure function lets say. Using the template if statement we can check that it does throw. For example: void myfunc(T)(T arg) nothrow if (checkIfNothrow!T) {} void myfunc(T)(T arg) if (checkIfNoModifiers!T) {} void myfunc(T)(T arg) pure if (checkIfPure!T) {} Basically you have to define all combinations. That is what I was meaning. Preferably you'll use q{} your code that is actually used. And use a template mixin to generate all these statements, so you don't have to!
Jan 17 2014
next sibling parent "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 01:52:56 UTC, Rikki Cattermole 
wrote:

 Okay, I'll explain what I was inferring. If the methods your 
 calling are lets say nothrow which can be checked by a pure 
 function lets say. Using the template if statement we can check 
 that it does throw.
I'm going to continue to think that I am overly not explicit and thus there continues to be a misunderstanding. However, I'd like to correct that misunderstanding by saying that *I KNOW HOW TO DO THIS WITH TEMPLATES AND STATIC IF* :D (By the way, I did sort of mention it in the first post). In other words, I wasn't asking *how* to do it in principle, I'm interested if there's any possibility to do it elegantly.
 For example:
 void myfunc(T)(T arg) nothrow if (checkIfNothrow!T) {}
 void myfunc(T)(T arg) if (checkIfNoModifiers!T) {}
 void myfunc(T)(T arg) pure if (checkIfPure!T) {}

 Basically you have to define all combinations. That is what I 
 was meaning.
 Preferably you'll use q{} your code that is actually used. And 
 use a template mixin to generate all these statements, so you 
 don't have to!
That is precisely the thing I'd like to avoid entirely. Following your example (which is not entirely correct since in this case I won't be checking T, I'll be checking T.foo or T.bar or whatever combination of those :o), I'd have to have three distinct function definitions, even though in the end only one of them will ever be compiled into my class. Yes, this can be simplified by mixing-in the actual function body into all of those definitions. But we have to be able to do better :) I'm not trying to say that C++'s syntax wins, no. The syntax can be anything, other than blowing up my class with all those declarations and ifs :). If we're talking templates, it would sure be nice to be just a tad more generic. Consider: void myfunc(T)(T arg) pure(isPure!(T.foo)) nothrow(isNoThrow!(T.bar)) { ... } I know that myfunc *can* be pure (I wrote it) and it *won't* throw anywhere, and that would be true for all the function body, *except* I also know that T.foo *may* be impure or T.bar *may* throw (because I didn't write them, T is an arbitrary type possibly from user code). Because of those "may"s I either have to drop the tags entirely, or to have four different declarations with various combinations of constraints. Having the ability to specify the condition for a tag would elegantly solve this issue. It's one definition, no static ifs or additional template constraints. Again, the syntax here could be anything, like something proposed in that discussion I mentioned earlier: void myfunc(T)(T arg) optional(isPure!(T.foo), pure) optional(isNoThrow!(T.bar), nothrow) { ... } or anything else. Granted, presence of overloads and templates may make those ifPure/ifNoThrow/ifWhatever checks not that trivial to implement or invoke, but still possible nevertheless.
Jan 17 2014
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Jan 18, 2014 at 01:52:55AM +0000, Rikki Cattermole wrote:
 On Saturday, 18 January 2014 at 00:57:27 UTC, Stanislav Blinov
 wrote:
Obviously I didn't explain myself clearly. I know how to determine
if a function is nothrow or pure or  safe or anything else thanks
to D's awesomeness :) But what I want is a way to *use* that
knowledge when declaring my own functions. Or rather, tell the
compiler "Wait, I really want this to be nothrow, but I don't know
if that function will throw. Here's a check for you, please make
me nothrow if it passes". After all, tags are not just for
enforcing correctness at compile time, they can be used (once
verified) for optimization too. So it'd be nice to find a way to
provide all the nice info to the compiler whenever possible. It's
not just about nothrow, but also pure,  safe/ system/ trusted,
hell, even public/protected/private for that matter. :)

That way you can have two declarations but with one being
opposite of the if.
...Or four in case I'd also want pure/not pure, or nine if I'd also want safe/not safe...
Okay, I'll explain what I was inferring. If the methods your calling are lets say nothrow which can be checked by a pure function lets say. Using the template if statement we can check that it does throw. For example: void myfunc(T)(T arg) nothrow if (checkIfNothrow!T) {} void myfunc(T)(T arg) if (checkIfNoModifiers!T) {} void myfunc(T)(T arg) pure if (checkIfPure!T) {} Basically you have to define all combinations. That is what I was meaning. Preferably you'll use q{} your code that is actually used. And use a template mixin to generate all these statements, so you don't have to!
What's wrong with just letting the compiler infer the maximal function attributes? void fun(T)(T arg) if (is(typeof(arg.method()))) { arg.method(); } int globvar; struct Impure { void method() safe nothrow { globvar++; } } struct Thrower { void method() pure safe { throw new Exception("abc"); } } struct Unsafe { void method() pure nothrow { int[2] arr; int* ptr = arr.ptr; ptr++; *ptr = 123; } } pragma(msg, typeof(fun!Impure)); pragma(msg, typeof(fun!Thrower)); pragma(msg, typeof(fun!Unsafe)); Compiler output: nothrow safe void(Impure arg) pure safe void(Thrower arg) pure nothrow system void(Unsafe arg) Notice how the best attributes have been inferred for fun(), depending on what type was passed in, even though we never annotated fun() with any attributes. That is, fun()'s attributes change depending on how T.method() was implemented. So if T.method happens to be pure, safe, and nothrow, then so will fun(). If fun() calls multiple methods, then its final attributes will be the intersection of the attributes of all the method calls plus its own code (so if you threw in fun(), then it would become nothrow regardless of whether T.method is nothrow or not, but if fun() itself never throws, then it will be marked nothrow depending on whether T.method throws). Sadly, this only works for template functions currently -- so I still had to annotate the various method()'s by hand, but if you were to turn them into template functions too, their attributes will also be inferred automatically. T -- Almost all proofs have bugs, but almost all theorems are true. -- Paul Pedersen
Jan 17 2014
parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 02:38:28 UTC, H. S. Teoh wrote:

 What's wrong with just letting the compiler infer the maximal 
 function
 attributes?
...
 Sadly, this only works for template functions currently -- so I 
 still
 had to annotate the various method()'s by hand, but if you were 
 to turn
 them into template functions too, their attributes will also be 
 inferred
 automatically.
Oh, I see now where it went the wrong way. From my own example, of course :) Surely I was meaning: class Careful(T) { //... void thisIsSoPolymorphic() nothrow(isNoThrow!(T.foo)) { ... } //... } Something to that extent. So that yes, the function itself is not a template.
Jan 17 2014
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 17 Jan 2014 21:50:07 -0500, Stanislav Blinov  
<stanislav.blinov gmail.com> wrote:

 On Saturday, 18 January 2014 at 02:38:28 UTC, H. S. Teoh wrote:

 What's wrong with just letting the compiler infer the maximal function
 attributes?
...
 Sadly, this only works for template functions currently -- so I still
 had to annotate the various method()'s by hand, but if you were to turn
 them into template functions too, their attributes will also be inferred
 automatically.
Oh, I see now where it went the wrong way. From my own example, of course :) Surely I was meaning: class Careful(T) { //... void thisIsSoPolymorphic() nothrow(isNoThrow!(T.foo)) { ... } //... } Something to that extent. So that yes, the function itself is not a template.
I was about to respond with a similar point, but it seems you are understanding now how the nothrow inference works :) I can't think of a correct way to do this without repeating code, since it has to be polymorphic (and therefore not a template), nothrow inference only works on templates. The idea to be able to attach attributes/annotations based on compile-time introspection would be a worthy addition to the language IMO, but I really don't like the syntax you have outlined (I see you don't like it either). Especially if you have to do all the attributes this way. I think a "use the attributes of X" would be a general enough tool. Something like: void thisIsSoPolymorphic() attrOf(T.foo) -Steve
Jan 17 2014
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Fri, Jan 17, 2014 at 10:02:44PM -0500, Steven Schveighoffer wrote:
 On Fri, 17 Jan 2014 21:50:07 -0500, Stanislav Blinov
 <stanislav.blinov gmail.com> wrote:
 
On Saturday, 18 January 2014 at 02:38:28 UTC, H. S. Teoh wrote:

What's wrong with just letting the compiler infer the maximal function
attributes?
...
Sadly, this only works for template functions currently -- so I still
had to annotate the various method()'s by hand, but if you were to turn
them into template functions too, their attributes will also be inferred
automatically.
Oh, I see now where it went the wrong way. From my own example, of course :) Surely I was meaning: class Careful(T) { //... void thisIsSoPolymorphic() nothrow(isNoThrow!(T.foo)) { ... } //... } Something to that extent. So that yes, the function itself is not a template.
I was about to respond with a similar point, but it seems you are understanding now how the nothrow inference works :) I can't think of a correct way to do this without repeating code, since it has to be polymorphic (and therefore not a template), nothrow inference only works on templates.
See https://d.puremagic.com/issues/show_bug.cgi?id=10329 and the associated pull, which has just been merged. I haven't tested it myself yet, but it would appear that methods inside template classes should now have their methods' attributes inferred too? If so, then you can just take out the nothrow clause and it should work? (But since I haven't tested this yet I could be wrong.)
 The idea to be able to attach attributes/annotations based on
 compile-time introspection would be a worthy addition to the
 language IMO, but I really don't like the syntax you have outlined
 (I see you don't like it either). Especially if you have to do all
 the attributes this way.
 
 I think a "use the attributes of X" would be a general enough tool.
 
 Something like:
 
  void thisIsSoPolymorphic() attrOf(T.foo)
[...] Hmm. Would functionAttributes and SetFunctionAttributes in std.traits help somehow? Not sure how you might actually use them to declare methods with desired attributes, though. But maybe there's a way. T -- Always remember that you are unique. Just like everybody else. -- despair.com
Jan 17 2014
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 17 Jan 2014 22:21:15 -0500, H. S. Teoh <hsteoh quickfur.ath.cx>  
wrote:

 On Fri, Jan 17, 2014 at 10:02:44PM -0500, Steven Schveighoffer wrote:
 On Fri, 17 Jan 2014 21:50:07 -0500, Stanislav Blinov
 <stanislav.blinov gmail.com> wrote:

On Saturday, 18 January 2014 at 02:38:28 UTC, H. S. Teoh wrote:

What's wrong with just letting the compiler infer the maximal function
attributes?
...
Sadly, this only works for template functions currently -- so I still
had to annotate the various method()'s by hand, but if you were to  
turn
them into template functions too, their attributes will also be  
inferred
automatically.
Oh, I see now where it went the wrong way. From my own example, of course :) Surely I was meaning: class Careful(T) { //... void thisIsSoPolymorphic() nothrow(isNoThrow!(T.foo)) { ... } //... } Something to that extent. So that yes, the function itself is not a template.
I was about to respond with a similar point, but it seems you are understanding now how the nothrow inference works :) I can't think of a correct way to do this without repeating code, since it has to be polymorphic (and therefore not a template), nothrow inference only works on templates.
See https://d.puremagic.com/issues/show_bug.cgi?id=10329 and the associated pull, which has just been merged. I haven't tested it myself yet, but it would appear that methods inside template classes should now have their methods' attributes inferred too?
Hm... how does that work on a virtual function? You may not know the body. It does seem like a good solution for most cases.
 The idea to be able to attach attributes/annotations based on
 compile-time introspection would be a worthy addition to the
 language IMO, but I really don't like the syntax you have outlined
 (I see you don't like it either). Especially if you have to do all
 the attributes this way.

 I think a "use the attributes of X" would be a general enough tool.

 Something like:

  void thisIsSoPolymorphic() attrOf(T.foo)
[...] Hmm. Would functionAttributes and SetFunctionAttributes in std.traits help somehow? Not sure how you might actually use them to declare methods with desired attributes, though. But maybe there's a way.
Not sure, it looks like SetFunctionAttributes only can be used to construct types, not declare functions. -Steve
Jan 17 2014
prev sibling parent "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 03:22:43 UTC, H. S. Teoh wrote:
 On Fri, Jan 17, 2014 at 10:02:44PM -0500, Steven Schveighoffer 
 wrote:
 See https://d.puremagic.com/issues/show_bug.cgi?id=10329
 If so, then you can just take out the nothrow clause and it 
 should work?
 (But since I haven't tested this yet I could be wrong.)
Hmm... It certainly *looks* that way, but I don't have a local pull of the compiler, so can't test either. But if it's true, that's great!
 Hmm. Would functionAttributes and SetFunctionAttributes in 
 std.traits
 help somehow? Not sure how you might actually use them to 
 declare
 methods with desired attributes, though. But maybe there's a 
 way.
functionAttributes can be used for inference (see isNoThrow in my first post). But alas, currently attributes can't be mixed-in or otherwise conditionally specified (without resorting to static if), at least I don't know one, what prompted me to start this topic in the first place.
Jan 17 2014
prev sibling next sibling parent reply "Stanislav Blinov" <stanislav.blinov gmail.com> writes:
On Saturday, 18 January 2014 at 03:02:45 UTC, Steven 
Schveighoffer wrote:

 I was about to respond with a similar point, but it seems you 
 are understanding now how the nothrow inference works :)
O:)
 I can't think of a correct way to do this without repeating 
 code, since it has to be polymorphic (and therefore not a 
 template), nothrow inference only works on templates.

 The idea to be able to attach attributes/annotations based on 
 compile-time introspection would be a worthy addition to the 
 language IMO, but I really don't like the syntax you have 
 outlined (I see you don't like it either).
No, I actually quite like that C++ syntax, although AFAIK it's only "special" in that one particular occasion. I was mentioning that syntax doesn't matter because I wanted to make sure I'm not pushing any C++ features here, just making a point about a nice usability feature :)
 Especially if you have to do all the attributes this way.
 I think a "use the attributes of X" would be a general enough 
 tool.

 Something like:

  void thisIsSoPolymorphic() attrOf(T.foo)
And here is where I would disagree. Fine-grained control over each attribute is more important. For example, the function may be always nothrow (say I handle all the exceptions in the world or assert(0) on what's left; D helpfully doesn't consider assert(0) as throwing :) ), but it may be conditionally pure or safe.
Jan 17 2014
parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Fri, 17 Jan 2014 22:25:11 -0500, Stanislav Blinov  
<stanislav.blinov gmail.com> wrote:

 On Saturday, 18 January 2014 at 03:02:45 UTC, Steven Schveighoffer wrote:
 I think a "use the attributes of X" would be a general enough tool.

 Something like:

  void thisIsSoPolymorphic() attrOf(T.foo)
And here is where I would disagree. Fine-grained control over each attribute is more important. For example, the function may be always nothrow (say I handle all the exceptions in the world or assert(0) on what's left; D helpfully doesn't consider assert(0) as throwing :) ), but it may be conditionally pure or safe.
void thisIsSoPolymorphic() attrOf(T.foo) nothrow I would assume, we could come up with ways to mask out attributes you want to set specifically. For example if you always want it NOT to be nothrow, you could do something like: void thisIsSoPolymorphic() attrOf(withoutNothrow!(T.foo)) -Steve
Jan 17 2014
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2014-01-18 04:02, Steven Schveighoffer wrote:

 I think a "use the attributes of X" would be a general enough tool.

 Something like:

   void thisIsSoPolymorphic() attrOf(T.foo)
Yet another case for AST macros: class Careful (T) { void thisIsSoPolymporphic () inferAttributes(T.foo) { } } macro inferAttributes (Context context, Ast!(Symbol) symbol, Declaration decl) { foreach (attr ; symbol.attributes) decl.attributes ~= attr; return decl; } -- /Jacob Carlborg
Jan 18 2014
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 01/18/2014 03:50 AM, Stanislav Blinov wrote:

 Oh, I see now where it went the wrong way. From my own example, of
 course :)

 Surely I was meaning:

 class Careful(T) {
 //...
    void thisIsSoPolymorphic() nothrow(isNoThrow!(T.foo)) { ... }
 //...
 }

 Something to that extent. So that yes, the function itself is not a
 template.
Well, but it will be annotated nothrow anyway if possible. Inference is not actually limited in the implied way. In case you _really_ want to be explicit about this (and you seem not to), the general problem precluding a nice library implementation is that built-in attributes cannot be aliased. You can always use a string mixin though: mixin(`void thisIsSoPolymorphic()`~(isNoThrow!(T.foo)?:"nothrow":"")~q{{ ... }}); This easily scales to all attributes you may find interesting: mixin(`void thisIsSoPolymorphic()`~stringOfAttributes!(T.foo)~q{{ ... }});
Jan 18 2014