November 09, 2012
On Friday, 9 November 2012 at 05:25:12 UTC, Jonathan M Davis wrote:
> Given that a range requires a very specific set of functions, I find it highly unlikely that anything which isn't a range will
> qualify as one.


I've had it happen to me several times. Let me show you some code

from my dom.d:

mixin template JavascriptStyleDispatch() {
        string opDispatch(string name)(string v = null) if(name != "popFront") { // popFront will make this look like a range. Do not want.


class Element {
        // name != "popFront" is so duck typing doesn't think it's a range
        @property string opDispatch(string name)(string v = null) if(name != "popFront") {
}

struct CssRule {

        string opDispatch(string nameGiven)(string value = null) if(nameGiven != "popFront") {
}



From prototype.d:

class PrototypeObject {
        // the constraint is needed otherwise the Variant constructor fails
        @property ref PrototypeObject opDispatch(string name)() if(name != "length") {
}

(I'm not sure if this last one is a range problem, because it was Variant that was confused, but the dom ones definitely were).


Of course, they all have something in common: an open opDispatch. But that's a valid D feature so surely I'm not the only one using it.


Every one of those constraints come from it actually being a problem at one point or another.

November 09, 2012
On Friday, November 09, 2012 14:14:01 Adam D. Ruppe wrote:
> Of course, they all have something in common: an open opDispatch. But that's a valid D feature so surely I'm not the only one using it.

Okay. I can see it happening there, and alias this could cause similar problems, but if you're actually naming the functions yourself, I find it very hard to believe that it's every a problem. opDispatch and alias this do pose their own sorts of problems though (alias this in particular can do funny things to make template constraints pass but still make it so that the template doesn't work).

- Jonathan M Davis
November 10, 2012
Le 08/11/2012 01:11, Timon Gehr a écrit :
> On 11/08/2012 12:18 AM, Walter Bright wrote:
>> Started a new thread on this.
>>
>> On 11/7/2012 3:05 AM, Leandro Lucarella wrote:
>> > OK, that's another thing. And maybe a reason for listening to people
>> having
>> > more experience with UDAs than you.
>> >
>> > For me the analogy with Exceptions is pretty good. The issues an
>> conveniences
>> > of throwing anything or annotating a symbol with anything instead of
>> just
>> > type are pretty much the same. I only see functions making sense to
>> be accepted
>> > as annotations too (that's what Python do with annotations,
>> @annotation symbol
>> > is the same as symbol = annotation(symbol), but is quite a different
>> language).
>>
>> There's another aspect to this.
>>
>> D's UDAs are a purely compile time system, attaching arbitrary metadata
>> to specific symbols. The other UDA systems I'm aware of appear to be
>> runtime systems.
>>
>> This implies the use cases will be different - how, I don't really know.
>> But I don't know of any other compile time UDA system. Experience with
>> runtime systems may not be as applicable.
>>
>> Another interesting data point is CTFE. C++11 has CTFE, but it was
>> deliberately crippled and burdened with "constexpr". From what I read,
>> this was out of fear that it would turn out to be an overused and
>> overabused feature. Of course, this turned out to be a large error.
>>
>> One last thing. Sure, string attributes can (and surely would be) used
>> for different purposes in different libraries. The presumption is that
>> this would cause a conflict. But would it? There are two aspects to a
>> UDA - the attribute itself, and the symbol it is attached to. In order
>> to get the UDA for a symbol, one has to look up the symbol. There isn't
>> a global repository of symbols in D. You'd have to say "I want to look
>> in module X for symbols." Why would you look in module X for an
>> attribute that you have no reason to believe applies to symbols from X?
>> How would an attribute for module X's symbols leak out of X on their own?
>>
>> It's not quite analogous to exceptions, because arbitrary exceptions
>> thrown from module X can flow through your code even though you have no
>> idea module X even exists.
>
> This is a valid point, and I think it does not really make sense to only
> exclude built-in types. Any type not intended for use as an attribute
> and that is exported to sufficiently many places can have the same
> behaviour.
> I'd vote no restrictions at all, or for requiring @attribute annotations
> on the user-defined type and ban user-defined types from being
> annotations that do not have that.

I'd vote for requiring @attribute annotations on the user-defined type and ban user-defined types from being annotations that do not have that.

That is really important to allow libs not to step on each other's toes.
November 10, 2012
Le 08/11/2012 11:56, simendsjo a écrit :
> On Thursday, 8 November 2012 at 09:05:31 UTC, Jacob Carlborg wrote:
>> I think we should only allow user defined types marked with
>> @attribute, i.e.
>>
>> @attribute struct foo {}
>> @attribute class foo {}
>> @attribute interface foo {}
>> @attribute enum foo {}
>>
>> And so on.
>
> Or
> struct @foo {}
> interface @foo {}
> enum @foo {0
> etc
>

I love it ! Shorter and achieve the same result, very readable, that is THE solution.
November 10, 2012
Le 08/11/2012 19:55, simendsjo a écrit :
> On Thursday, 8 November 2012 at 17:20:39 UTC, Jacob Carlborg wrote:
>> On 2012-11-08 17:53, simendsjo wrote:
>>
>>> I guess it depends. I find it easier to see that it's an attribute,
>>> especially when you annotate it. But it's harder to grep for.
>>>
>>> Is foo an attribute or not?
>>> @serializable
>>> @xmlRoot
>>> @attribute
>>> @displayName("foo")
>>> struct foo {}
>>>
>>> Is foo an attribute or not?
>>> @serializable
>>> @xmlRoot
>>> @displayName("foo")
>>> struct @foo {}
>>>
>>
>> I don't know really. In that bottom example, the struct declartion
>> almost disappears among all the attributes.
>
> Yeah.. But at least you'll always know where to look.
>
> @[serializable, xmlRoot, attribute, displayName("foo")]
> struct foo {}
>
> @[serializable, xmlRoot, displayName("foo")]
> struct @foo {}
>
> but attribute could be required as the last type, and on a line of it's
> own, giving:
>
> @[serializable, xmlRoot, displayName("foo")]
> @attribute
> struct foo {}
>

More special case isn't a good idea. We already have way too much of them.
November 10, 2012
Le 09/11/2012 07:53, Nick Sabalausky a écrit :
> On Thu, 08 Nov 2012 21:24:49 -0800
> Jonathan M Davis<jmdavisProg@gmx.com>  wrote:
>
>> On Thursday, November 08, 2012 21:10:55 Walter Bright wrote:
>>> Many algorithms (at least the ones in Phobos do) already do a check
>>> to ensure the inputs are the correct kind of range. I don't think
>>> you'll get very far trying to use a range that isn't a range.
>>>
>>> Of course, you can always still have bugs in your range
>>> implementation.
>>
>> Given that a range requires a very specific set of functions, I find
>> it highly unlikely that anything which isn't a range will qualify as
>> one. It's far more likely that you screw up and a range isn't the
>> right kind of range because one of the functions wasn't quite right.
>>
>> There is some danger in a type being incorrectly used with a function
>> when that function requires and tests for only one function, or maybe
>> when it requires two functions. But I would expect that as more is
>> required by a template constraint, it very quickly becomes the case
>> that there's no way that any type would ever pass it with similarly
>> named functions that didn't do the same thing as what they were
>> expected to do. It's just too unlikely that the exact same set of
>> function names would be used for different things, especially as that
>> list grows. And given that ranges are a core part of D's standard
>> library, I don't think that there's much excuse for having a type
>> that has the range functions but isn't supposed to be a range. So, I
>> really don't see this as a problem.
>>
>
> Looking at one set of interfaces in isolation, sure the chances might
> be low. (Just like the chances of name collisions when hygeine is
> lacking, and yet we thankfully have a real module system, instead of C's
> clumsy "Well, it should usually work ok!" garbage.) But it's a terrible
> precedent. Scale things up, use ducks as common practice, and all of a
> sudden you're right back into the same old land of "no-hygeine". Bad,
> sloppy, lazy precedent. AND the presumed benefit of the duckness is
> minimal at best. Just not a good design, it makes all the wrong
> tradeoffs.
>

UDA is a really good way to express that intent.
November 10, 2012
On 11/09/12 07:41, Nick Sabalausky wrote:
> Of course, it'd be even nicer still to have all this wrapped up in
> some language sugar (D3? ;) ) and just do something like:
> 
> struct interface InputRange {
>     // ... *declare* .empty, .front, .popFront here
> }
> 
> struct interface ForwardRange : InputRange {
>     // ... *declare* .save here
> }
> 
> struct MyForwardRange : ForwardRange {
>     // ... define .empty, .front, .popFront, .save here
>     // Actually validated by the compiler
> }
> 
> Which would then amount to what we're doing by hand up above. So kinda like Go, except not error-prone and ducky and all shitty.

This would actually be backwards compatible and also relatively forward compatible - does not need to wait for a D3.

However, while it's a step in the right direction, doing it like that would be to limiting. Compare with:

   interface template InputRange(T) {
      enum InputRange = __traits(compiles, {T r; /* check the i/f here */});
   }

   struct MyInputRange : InputRange {
      enum empty = false;
      enum front = 42;
      void popFront() {}
   }

Ie requiring a certain interface to be present is fine, requiring a certain
set of function signatures is too restrictive (and could still be done inside
the interface-template when necessary).
I used "interface-templates" because this feature should not clash with
/normal/ struct inheritance, once that one emerges.

All the boilerplate in the InputRange template above could be made implicit and it could then look like this:

   interface template InputRange(T) {
       T r;
       bool e = r.empty;
       r.popFront();
       auto f = r.front;
   }
   else
       throw("Not an input range"); // "static throw", "assert", whatever.

These i/f templates would also be useful in places where the current
'isInputRange' hack is used; would significantly improve both readability
and error reporting (that's the reason for the else clause).

artur
1 2 3 4 5
Next ›   Last »