www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Too many attributes?

reply "Janice Caron" <caron800 googlemail.com> writes:
On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
  D2 will allow the following:
  pure invariant invariant(int) func(invariant(int)) nothrow;
  Am I the only one that thinks the above is too much?
You're not the only one. Just for the record though, invariant(int) will implicitly cast to and from int, so the above could be simiplified to pure invariant int func(int) nothrow; However, the following cannot be simplified pure invariant invariant(C) func(invariant(C) c) nothrow; where C is a class. And it gets worse. Consider the following code: pure int func(invariant(C) a, invariant(C) b) { if (c == b) ... Whoops! That won't compile, because - guess what!? - opEquals isn't pure!!!! And it doesn't stop there - opEquals cannot be made pure just by changing its declaration, because a pure function must have invariant arguments, and opEquals has to work with or without invariant data. The upshot is that, eventually, Object.opEquals may have to be implemented twice: class Object { // the normal version const bool opEquals(const Object o) {...} // the pure version pure invariant bool opEquals(invariant Object o) {...} } and, therefore, so will anything that overloads it. And then there are delegates. I have mentioned in a previous thread (called something like "big hole in const system") that big problems exist because attributes can be applied to functions /but not to delegates/. That is, we cannot declare pure invariant invariant(C) delegate(invariant(C) c) nothrow dg; If we take the address of func, where func is declared as pure invariant invariant(C) func(invariant(C) c) nothrow; then &func will have type invariant(C) delegate(invariant(C)) That is, all the attributes will have been lost. That makes it possible to break any contract implied by the attributes without the compiler noticing, /just by taking the address of a function/. And then we come to templates. Oh my! These new attributes are going to cause a big problem for templates. Consider: ReturnType!(f) foo(alias f)(ParameterTypeTuple!(f) n) { return f(n); } or should that be... ReturnType!(f) foo(alias f)(ParameterTypeTuple!(f) n) nothrow { return f(n); } ? Hmm. Looks like the real answer is template foo(alias f) { if(is(f == nothrow)) { ReturnType!(f) foo(ParameterTypeTuple!(f) n) nothrow { return f(n); } } else { ReturnType!(f) foo(ParameterTypeTuple!(f) n) { return f(n); } } } (and even that's assuming that we will be able to test for "if(is(f == nothrow))", which also is not certain). In fact, really, the template should also test for "pure" as well, so it can attach the "pure" attribute if it can. And just in case anyone thinks that was a contrived example, real world uses would include root-solving by Newton's method, root-solving by the secant method, numerical integration, etc. - all of which will be pure iff f is pure, nothrow iff f is nothrow, etc. While I understand the reasons for "pure", etc. (- and don't misunderstand me, they are sound reasons!), there are implications for syntax which will come back and bite us if we're not careful. At the very least, I would suggest (1) attributes for delegates (2) attribute tuples for templates (e.g. AttributeTuple!(f) ReturnType!(f) foo(alias f)(ParameterTypeTuple!(f) n) { return f(n); } )
Apr 25 2008
next sibling parent Yigal Chripun <yigal100 gmail.com> writes:
Janice Caron wrote:
 While I understand the reasons for "pure", etc. (- and don't
 misunderstand me, they are sound reasons!), there are implications for
 syntax which will come back and bite us if we're not careful. At the
 very least, I would suggest
 
 (1) attributes for delegates
 (2) attribute tuples for templates
 
 (e.g.
 
     AttributeTuple!(f) ReturnType!(f) foo(alias f)(ParameterTypeTuple!(f) n)
     {
         return f(n);
     }
 
 )
My example was a contrived one, but you provided good examples that illustrates the syntactic issues that arise from all those additions to D's syntax. One note regarding your template example: I don't see how that AttributeTuple!(f) helps. this should be solved via introspection at runtime or via traits at compile type. either way, it should be possible to get f's attributes in a tuple/array. something like: f.attributesof which would return a tuple of attributes. since I'm advocating for introduction of user defined attributes to D, I'd suggest that the compiler should treat "const"/"pure" and such as built-in attributes that are provided by the language, so that if you define: [myAttr1, myAttr2] pure int func(invariant C c); then func.attributesof would contain the tuple: (pure, myAttr1, myAttr2). just like a type tuple can contain both built-in types and user defined ones. --Yigal
Apr 25 2008
prev sibling next sibling parent reply Christian Kamm <kamm.incasoftware shift-at-left-and-remove-this.de> writes:
 And then there are delegates. I have mentioned in a previous thread
 (called something like "big hole in const system") that big problems
 exist because attributes can be applied to functions /but not to
 delegates/. That is, we cannot declare
 
         pure invariant invariant(C) delegate(invariant(C) c) nothrow dg;
For what it's worth, the D spec 2.013 allows delegates to have the pure and nothrow attributes. (Declarations: BasicType2 and Expressions: FunctionLiteral) Christian
Apr 25 2008
parent "Janice Caron" <caron800 googlemail.com> writes:
On 25/04/2008, Christian Kamm
<kamm.incasoftware shift-at-left-and-remove-this.de> > > For what it's
worth, the D spec 2.013 allows delegates to have the pure and
 nothrow attributes. (Declarations: BasicType2 and Expressions:
 FunctionLiteral)
Ooh nice! Thanks for pointing that out. But they need to be able to take const and invariant attributes too. (And come to think of it, if you allowed delegates to be declared static then we could lose the "function" keyword altogether, as "delegate static" could take over that role. Maybe that's pushing things too far though).
Apr 25 2008
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Janice Caron wrote:
 On 25/04/2008, Yigal Chripun <yigal100 gmail.com> wrote:
  D2 will allow the following:
  pure invariant invariant(int) func(invariant(int)) nothrow;
  Am I the only one that thinks the above is too much?
You're not the only one.
I second that.
 
     pure int func(invariant(C) a, invariant(C) b)
     {
         if (c == b) ...
 
 Whoops! That won't compile, because - guess what!? - opEquals isn't pure!!!!
 
 And it doesn't stop there - opEquals cannot be made pure just by
 changing its declaration, because a pure function must have invariant
 arguments, and opEquals has to work with or without invariant data.
 The upshot is that, eventually, Object.opEquals may have to be
 implemented twice:
 
     class Object
     {
         // the normal version
         const bool opEquals(const Object o) {...}
 
         // the pure version
         pure invariant bool opEquals(invariant Object o) {...}
     }
 
 and, therefore, so will anything that overloads it.
 
Another example why "scoped const", despite "only" being a syntactical convenience, might be so important. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2008
parent reply "Janice Caron" <caron800 googlemail.com> writes:
On 29/04/2008, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
 Another example why "scoped const", despite "only" being a syntactical
 convenience, might be so important.
That wouldn't help in this case. The reason you need the second declaration is so that one declaration can be pure, the other not. Steven's proposal solves a different problem.
Apr 29 2008
parent Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Janice Caron wrote:
 On 29/04/2008, Bruno Medeiros <brunodomedeiros+spam com.gmail> wrote:
 Another example why "scoped const", despite "only" being a syntactical
 convenience, might be so important.
That wouldn't help in this case. The reason you need the second declaration is so that one declaration can be pure, the other not. Steven's proposal solves a different problem.
Not if you combine "scoped const" with the partially pure function rules (see new thread). Example: //(using 'anyconst' as the scoped const keyword) class Object { pure anyconst bool opEquals(anyconst(Object) obj) {...} The 3 versions of opEquals would be created. 2 of them would partially pure, the other (the invariant one) would be fully pure. The mutable version would be redudant though. This would work, but since there is redundancy, I'm thinking there could be a better way to do it. -- Bruno Medeiros - Software Developer, MSc. in CS/E graduate http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Apr 29 2008