August 30, 2007
Lars Ivar Igesund wrote:
> [...]
> It will also be directly detrimental to maintainability when used for user
> defined types, as you no longer will be able to decide where a function is
> implemented by only looking at the call site (given inheritance and
> polymorphism this can in cases be difficult enough, but at least you have a
> type hierarchy to look to).

Well, usually a simple change to the import list will reveal where each functions are defined. I wouldn't see that as an argument against this feature.

Apart from that, in an ideal world, the code is well documented enough to not have to determine the location of a function/method implementation yourself, anyways. Of course, this is the *ideal*, but maybe this encourages some to document better.
August 30, 2007
Alexander Panek wrote:

> Lars Ivar Igesund wrote:
>> [...]
>> It will also be directly detrimental to maintainability when used for
>> user defined types, as you no longer will be able to decide where a
>> function is implemented by only looking at the call site (given
>> inheritance and polymorphism this can in cases be difficult enough, but
>> at least you have a type hierarchy to look to).
> 
> Well, usually a simple change to the import list will reveal where each functions are defined. I wouldn't see that as an argument against this feature.

I probably miss your point here, but it certainly shouldn't be necessary to change your code to find out what it does?

> 
> Apart from that, in an ideal world, the code is well documented enough to not have to determine the location of a function/method implementation yourself, anyways. Of course, this is the *ideal*, but maybe this encourages some to document better.

One should of course always document, but as many of the other suggestions in the Future of D presentation leans towards self documenting code (pure and nothrow functions for instance), I see this change as quite the opposite in that regard.

-- 
Lars Ivar Igesund
blog at http://larsivi.net
DSource, #d.tango & #D: larsivi
Dancing the Tango
August 30, 2007
Alexander Panek wrote:
> Lars Ivar Igesund wrote:
>> [...]
>> It will also be directly detrimental to maintainability when used for user
>> defined types, as you no longer will be able to decide where a function is
>> implemented by only looking at the call site (given inheritance and
>> polymorphism this can in cases be difficult enough, but at least you have a
>> type hierarchy to look to).
> 
> Well, usually a simple change to the import list will reveal where each functions are defined. I wouldn't see that as an argument against this feature.
> 
> Apart from that, in an ideal world, the code is well documented enough to not have to determine the location of a function/method implementation yourself, anyways. Of course, this is the *ideal*, but maybe this encourages some to document better.

On the other hand, the ambiguity problem:

class A {
    int foo (int);
}

int foo (A, int);

..leads or at least may lead to maintenance problems, anyways.

(Yes, I might have missed the point in the other post :P)
August 30, 2007
kris wrote:
...
> 
> And it potentially introduces additional namespace issues, hijacking issues, and compilation errors for large and/or long-term software development projects. The commercial-development space is where D ought to target, if it's to rise well above being just another enthusiasts playground :p

I agree, although I am that enthusiast. The main reason I liked this feature is 1) see Jarret's post and 2) I find it is easier to write small classes and extend them with free functions, good class design is hard. But if there are such issues then it is probably not worth it.

> A conservative approach would remove the existing idiom with arrays, rather than propagate it, and address concerns instead by perhaps looking at alternate approaches for supporting 'properties' (C# for example). Are you thinking this makes a good solution for 'properties' in general? As has been discussed recently?

No, not for properties. I never think of the current way properties are handled really as 'properties' in the sense of data members. They are just an alternative syntax for functions with 0 or 1 arguments in my book, with perhaps a hint to their role in a design.
Now this is my opinion, maybe misinformed, but I don't think class properties are important. They are just dressed up getters/setters, which is not so good an idiom to use frequently.

> Just because some folks apparently like it, and are vocal about it, doesn't necessarily make it "generally appreciated"? That's a problem with newsgroups and forums though ... it's perhaps easy to get a skewed perspective?

Sure, although I have never seen one single post that objects to array properties, nor have I encountered bugs / problems related to it.

> As for extending to other types, that's cool! I just feel this particular idiom potentially builds smoldering fires larger than the one(s) it is attempting to extinguish (or perhaps it's not even trying to resolve anything?). If that is the case it is hardly an adequate resolution, and will simply return to bite D in the buttocks.

My impression was that it is mainly for syntactic sugar, and maybe there was a notion of how it could be used in generic programming? Can't think of an issue that it solves.

> As such, I suspect alternatives should be given great consideration (or /greater/ consideration) and the relative trade-offs should be weighed appropriately. Yourself, and others, may feel that's not necessary or has been adequately performed already? I don't feel that way, and it's not the impression I got from the conference :-D

No I don't pretend to have thought through the issues, I don't think I can. That's why I asked you!
August 30, 2007
Alexander Panek wrote:
> Bill Baxter wrote:
>> [...]
>> But Walter seems to think it's ok the way it is.  Given that, I can definitely see how he'd think making a.foo uniformly interchangable with foo(a) makes sense.  I guess with property syntax and this combined we'll have
>>    "a.value" == "value(a)" == "value = a"
> 
> Oooh it looks like this would be possible to write:
> 
> 3.times = (int a) { Stdout(a.toUtf8).newline; }
> 
> ...fun! :D

I reiterate what I've said about three times now: I watch as D slowly turns into Ruby.  :)

(Although I actually like pseudo-members.  ColdC has this as well, but by modifying a type-lib object; $String.foo() callable as "abc".foo() for example.)

-- Chris Nicholson-Sauls
August 30, 2007
Chris Nicholson-Sauls wrote:
> I reiterate what I've said about three times now: I watch as D slowly turns into Ruby.  :)
Hehe. They indeed have similarities - maybe not in language theory or overall concept, but in innovation. Having (part of) Ruby's expressiveness in D would be a very neat thing, as long as it doesn't affect other concepts and goals of D.

> (Although I actually like pseudo-members.  ColdC has this as well, but by modifying a type-lib object; $String.foo() callable as "abc".foo() for example.)

That's actually possible already in D (D1, even):

//
import tango.io.Stdout;

void print (char[] s) {
    Stdout(s);
}

void main () {
    "Hello world!".print(); // omitting () is not possible, though
}
//
August 30, 2007
kris wrote:
> Lutger wrote:
>> kris wrote:

> And it potentially introduces additional namespace issues, hijacking issues, and compilation errors for large and/or long-term software development projects. The commercial-development space is where D ought to target, if it's to rise well above being just another enthusiasts playground :p

Namespace issues are why I don't currently find much use for the array trick.  If you put your array trick functions in a module, they're mostly going to have short names like "find" and "index".  So if you import that module normally it will clobber a valuable chunk of your namespace with little words like that.  But doing a static or renamed import causes the things not to work.  "arrayfn.find" can't be used as a property.  Ok so you can static import and then alias just the ones you want to use in the current module, possibly down at function scope to limit the namespace clashing.  But that's kind of a pain.

The error messages are also not very intuitive currently.  You type foo.bar(x,y) and get the error message "bar does not match types (int, int, int)"    Wait -- I'm not even calling bar with three args!?  Oh yeh that member syntax thing.  And if there really *is* a member with that name in the current context then it will shadow the external one even though it *looks* like foo.bar should be unambiguously scoped by foo.

These are from recent experience trying to emulate C++ iterators on top of D arrays.  For instance I wanted to be able to say  darray.begin() to get an iterator to an array.  Forget it.  Most classes in which I want to use that trick already have their own 'begin()' member which shadows the external begin(T)(T[]) function.

So my feeling is that for this to be more useful:
1) Extension members should be marked as such and *only* be allowed to be called with member syntax.  Those not marked as such will not be allowed to be called with member syntax.  (if you need both then it's easy enough to write a trivial forwarding function.)

2) Inside a class/struct scope, lookup of foo.bar should ignore methods of the local class.  (this would be a natural side effect of #1 though.  it already means extension members would do lookup differently than normal function lookup)

--bb
August 30, 2007
On Fri, 31 Aug 2007, Bill Baxter wrote:

> Namespace issues are why I don't currently find much use for the array trick. If you put your array trick functions in a module, they're mostly going to have short names like "find" and "index".  So if you import that module normally it will clobber a valuable chunk of your namespace with little words like that.  But doing a static or renamed import causes the things not to work.  "arrayfn.find" can't be used as a property.  Ok so you can static import and then alias just the ones you want to use in the current module, possibly down at function scope to limit the namespace clashing.  But that's kind of a pain.
> 
> The error messages are also not very intuitive currently.  You type foo.bar(x,y) and get the error message "bar does not match types (int, int, int)"    Wait -- I'm not even calling bar with three args!?  Oh yeh that member syntax thing.  And if there really *is* a member with that name in the current context then it will shadow the external one even though it *looks* like foo.bar should be unambiguously scoped by foo.
> 
> These are from recent experience trying to emulate C++ iterators on top of D
> arrays.  For instance I wanted to be able to say  darray.begin() to get an
> iterator to an array.  Forget it.  Most classes in which I want to use that
> trick already have their own 'begin()' member which shadows the external
> begin(T)(T[]) function.
> 
> So my feeling is that for this to be more useful:
> 1) Extension members should be marked as such and *only* be allowed to be
> called with member syntax.  Those not marked as such will not be allowed to be
> called with member syntax.  (if you need both then it's easy enough to write a
> trivial forwarding function.)
> 
> 2) Inside a class/struct scope, lookup of foo.bar should ignore methods of the local class.  (this would be a natural side effect of #1 though.  it already means extension members would do lookup differently than normal function lookup)
> 
> --bb

Don't overlook the changes upcoming in 2.0 to the overload resolution logic.  They'll greatly reduce (if not eliminate) the problem.  Many of the changes in 2.0 in isolation might introduce problems, but together make for a more powerful whole.

Later,
Brad
August 30, 2007
Bill Baxter wrote:
> kris wrote:
>> Lutger wrote:
>>> kris wrote:
> 
>> And it potentially introduces additional namespace issues, hijacking issues, and compilation errors for large and/or long-term software development projects. The commercial-development space is where D ought to target, if it's to rise well above being just another enthusiasts playground :p
> 
> Namespace issues are why I don't currently find much use for the array trick.  If you put your array trick functions in a module, they're mostly going to have short names like "find" and "index".  So if you import that module normally it will clobber a valuable chunk of your namespace with little words like that.  But doing a static or renamed import causes the things not to work.  "arrayfn.find" can't be used as a property.  Ok so you can static import and then alias just the ones you want to use in the current module, possibly down at function scope to limit the namespace clashing.  But that's kind of a pain.
> 
> The error messages are also not very intuitive currently.  You type foo.bar(x,y) and get the error message "bar does not match types (int, int, int)"    Wait -- I'm not even calling bar with three args!?  Oh yeh that member syntax thing.  And if there really *is* a member with that name in the current context then it will shadow the external one even though it *looks* like foo.bar should be unambiguously scoped by foo.
> 
> These are from recent experience trying to emulate C++ iterators on top of D arrays.  For instance I wanted to be able to say  darray.begin() to get an iterator to an array.  Forget it.  Most classes in which I want to use that trick already have their own 'begin()' member which shadows the external begin(T)(T[]) function.
> 
> So my feeling is that for this to be more useful:
> 1) Extension members should be marked as such and *only* be allowed to be called with member syntax.  Those not marked as such will not be allowed to be called with member syntax.  (if you need both then it's easy enough to write a trivial forwarding function.)
> 
> 2) Inside a class/struct scope, lookup of foo.bar should ignore methods of the local class.  (this would be a natural side effect of #1 though.  it already means extension members would do lookup differently than normal function lookup)
> 
> --bb


Amen
August 30, 2007
Bill Baxter wrote:
> kris wrote:
>> Lutger wrote:
>>> kris wrote:
> 
>> And it potentially introduces additional namespace issues, hijacking issues, and compilation errors for large and/or long-term software development projects. The commercial-development space is where D ought to target, if it's to rise well above being just another enthusiasts playground :p
> 
> Namespace issues are why I don't currently find much use for the array trick.  If you put your array trick functions in a module, they're mostly going to have short names like "find" and "index".  So if you import that module normally it will clobber a valuable chunk of your namespace with little words like that.  But doing a static or renamed import causes the things not to work.  "arrayfn.find" can't be used as a property.  Ok so you can static import and then alias just the ones you want to use in the current module, possibly down at function scope to limit the namespace clashing.  But that's kind of a pain.

Or just use selective import to do the same thing:

import cashew .utils .Array : contains, push, pop ;

> The error messages are also not very intuitive currently.  You type foo.bar(x,y) and get the error message "bar does not match types (int, int, int)"    Wait -- I'm not even calling bar with three args!?  Oh yeh that member syntax thing.  And if there really *is* a member with that name in the current context then it will shadow the external one even though it *looks* like foo.bar should be unambiguously scoped by foo.

I agree; but I consider it a lookup bug, not an inherent aspect of pseudo-members.

> These are from recent experience trying to emulate C++ iterators on top of D arrays.  For instance I wanted to be able to say  darray.begin() to get an iterator to an array.  Forget it.  Most classes in which I want to use that trick already have their own 'begin()' member which shadows the external begin(T)(T[]) function.

static import FooBar foo.bar : begin ;
alias FooBar.begin fb_begin ;

//...
darray.fb_begin()



Yeah, okay, that is a bit borked.

> So my feeling is that for this to be more useful:
> 1) Extension members should be marked as such and *only* be allowed to be called with member syntax.  Those not marked as such will not be allowed to be called with member syntax.  (if you need both then it's easy enough to write a trivial forwarding function.)

Its not a bad idea.  The "trivial forwarding function" should be inlineable anyhow.  Maybe a "context" parameter?  Something like:
size_t indexOf : T[] array (T) (T elem) { ... }

Where the (':' param) after the function name creates the context-param.  Other examples:

ulong area : IShape shp () { ... }

void unique : inout T[] array (T) () { ... }


Its just a random on-the-spot idea.

> 2) Inside a class/struct scope, lookup of foo.bar should ignore methods of the local class.  (this would be a natural side effect of #1 though.  it already means extension members would do lookup differently than normal function lookup)

Aye.

-- Chris Nicholson-Sauls