www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - class extensions

reply Michael Deardeuff <grignaak gmail.com> writes:
I am very excited about the future of D. Walter's and Andrei's talk at the
conference was awesome.

However, there are still a few quirks to get out:
This is regarding slide 9 of the presentation.

I noticed that most people at the conference liked the idea of extending
library classes, but were not to pleased with the interchangability of 
---
foo(a, args)
---
and
---
a.foo(args)
---
like the arrays have.

I have a suggestion: class extensions kindof like C#'s partial classes
----
class A {...}
...
extension class A {
   void foo(args) {...}
}
...
a.foo(args);
----
(maybe the syntax could be "class extension A" or "extension A"...)

In this way class extensions are clearly marked and the syntax is consistent.

It would be easy to add interfaces to the library class:

extension A : Visitable {
   void accept(Visitor v) {...}
}

Just an idea for you guys, Walter, Andrei, and the community.

--Michael Deardeuff
Aug 29 2007
next sibling parent Robert Fraser <fraserofthenight gmail.com> writes:
Michael Deardeuff Wrote:

 I am very excited about the future of D. Walter's and Andrei's talk at the
conference was awesome.
 
 However, there are still a few quirks to get out:
 This is regarding slide 9 of the presentation.
 
 I noticed that most people at the conference liked the idea of extending
library classes, but were not to pleased with the interchangability of 
 ---
 foo(a, args)
 ---
 and
 ---
 a.foo(args)
 ---
 like the arrays have.
Really? I got the feeling it was very well-received. I like the idea quite a bit, not necessarily just for class extensions (I think it might encourage a lower degree of encapsulation, although if the fields are package-private this might be mitigated by adding class extensions in other modules in the same package), but for primitive types.
 
 I have a suggestion: class extensions kindof like C#'s partial classes
 ----
 class A {...}
 ...
 extension class A {
    void foo(args) {...}
 }
 ...
 a.foo(args);
 ----
 (maybe the syntax could be "class extension A" or "extension A"...)
 
 In this way class extensions are clearly marked and the syntax is consistent.
 
 It would be easy to add interfaces to the library class:
 
 extension A : Visitable {
    void accept(Visitor v) {...}
 }
 
 Just an idea for you guys, Walter, Andrei, and the community.
 
 --Michael Deardeuff
 
I proposed this a while ago, and I agree this would be a good idea. However, the more I think about it, the more I realize that in a native-compiled language we're talking vtable problems - how do we know when the vtable is finished? If partials are cross-module, it would require recompilation of every involved module, and just be generally problematic. The suggestion that cam eup in the other thread was to use templates: --- interface IFoo { int bar(); } template IFoo_Impl() { int bar() { return 3; } } interface IBaz { string quux(); } template IBaz_Impl() { string quux() { return "abc"; } } class Baz : IFoo, IBaz { mixin IFoo_Impl!(); mixin IBaz_Impl(); } ---
Aug 29 2007
prev sibling next sibling parent reply Michael Deardeuff <some where.com> writes:
Robert Fraser Wrote:

 Michael Deardeuff Wrote:
 
 I am very excited about the future of D. Walter's and Andrei's talk at the
conference was awesome.
 
 However, there are still a few quirks to get out:
 This is regarding slide 9 of the presentation.
 
 I noticed that most people at the conference liked the idea of extending
library classes, but were not to pleased with the interchangability of 
 ---
 foo(a, args)
 ---
 and
 ---
 a.foo(args)
 ---
 like the arrays have.
Really? I got the feeling it was very well-received. I like the idea quite a bit, not necessarily just for class extensions (I think it might encourage a lower degree of encapsulation, although if the fields are package-private this might be mitigated by adding class extensions in other modules in the same package), but for primitive types.
 
 I have a suggestion: class extensions kindof like C#'s partial classes
 ----
 class A {...}
 ...
 extension class A {
    void foo(args) {...}
 }
 ...
 a.foo(args);
 ----
 (maybe the syntax could be "class extension A" or "extension A"...)
 
 In this way class extensions are clearly marked and the syntax is consistent.
 
 It would be easy to add interfaces to the library class:
 
 extension A : Visitable {
    void accept(Visitor v) {...}
 }
 
 Just an idea for you guys, Walter, Andrei, and the community.
 
 --Michael Deardeuff
 
I proposed this a while ago, and I agree this would be a good idea. However, the more I think about it, the more I realize that in a native-compiled language we're talking vtable problems - how do we know when the vtable is finished? If partials are cross-module, it would require recompilation of every involved module, and just be generally problematic.
Excellent point. Blast. I think it still _is_ a good idea if you scrap the inheritance/vtable problem and only allow extension classes to use the syntax "a.foo(...);" I guess what I'm getting at is, I don't like the prospect of working with code that in one line is "foo(a, ...);" and the next "a.foo(...);" With the extension class bit it makes it clear that only methods meant as a class extension can (and must) use the "a.foo();" syntax, which I prefer. And, of course, I'm in here for myself. j/k. But not really. --Michael Deardeuff
Aug 29 2007
parent reply kris <foo bar.com> writes:
Michael Deardeuff wrote:
 Robert Fraser Wrote:
[snip]
 I proposed this a while ago, and I agree this would be a good idea. However,
the more I think about it, the more I realize that in a native-compiled
language we're talking vtable problems - how do we know when the vtable is
finished? If partials are cross-module, it would require recompilation of every
involved module, and just be generally problematic.
Excellent point. Blast. I think it still _is_ a good idea if you scrap the inheritance/vtable problem and only allow extension classes to use the syntax "a.foo(...);" I guess what I'm getting at is, I don't like the prospect of working with code that in one line is "foo(a, ...);" and the next "a.foo(...);" With the extension class bit it makes it clear that only methods meant as a class extension can (and must) use the "a.foo();" syntax, which I prefer. And, of course, I'm in here for myself. j/k. But not really. --Michael Deardeuff
Yeah, the proposed extensions raised all kinds of red flags for me at the conference. Bluntly, it felt like the notion of "structured programming" was being tossed out in favor of "slapdash programming" ... a brand new paradigm to go along with the other(s) being adopted :)
Aug 29 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
kris wrote:
 Michael Deardeuff wrote:
 Robert Fraser Wrote:
[snip]
 I proposed this a while ago, and I agree this would be a good idea. 
 However, the more I think about it, the more I realize that in a 
 native-compiled language we're talking vtable problems - how do we 
 know when the vtable is finished? If partials are cross-module, it 
 would require recompilation of every involved module, and just be 
 generally problematic.
Excellent point. Blast. I think it still _is_ a good idea if you scrap the inheritance/vtable problem and only allow extension classes to use the syntax "a.foo(...);" I guess what I'm getting at is, I don't like the prospect of working with code that in one line is "foo(a, ...);" and the next "a.foo(...);" With the extension class bit it makes it clear that only methods meant as a class extension can (and must) use the "a.foo();" syntax, which I prefer. And, of course, I'm in here for myself. j/k. But not really. --Michael Deardeuff
Yeah, the proposed extensions raised all kinds of red flags for me at the conference. Bluntly, it felt like the notion of "structured programming" was being tossed out in favor of "slapdash programming" ... a brand new paradigm to go along with the other(s) being adopted :)
It's pretty much the same deal as with property syntax. A lot of folks think the use of property syntax with a function should need to be enabled explicilty to avoid nonsense like writefln = 5; 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" Which seems pretty weird to me. --bb
Aug 29 2007
next sibling parent Downs <default_357-line yahoo.de> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

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"
 
 Which seems pretty weird to me.
 
 --bb
I actually welcome this as a straightforward way to enable coders to write out what they mean. Of course, it can be abused for stuff like writefln="whee", but in many cases, abusability is related to the power/expressiveness of a feature - if you can use it to express more, it follows that you can also use it to express more garbage; however, that doesn't mean you have to. --downs -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFG1dBQpEPJRr05fBERAvSWAJ9oE3i7jIcSRnuiXVfFCz+SgFCARACfQTse ax7kN3DRe9CdOeC+ac+ihbE= =abAO -----END PGP SIGNATURE-----
Aug 29 2007
prev sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
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
Aug 30 2007
parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
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
Aug 30 2007
parent reply Alexander Panek <alexander.panek brainsware.org> writes:
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 } //
Aug 30 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Alexander Panek wrote:
 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.
I'm sure we'll never, ever, see something quite like: $db.commit transaction unless transaction.flag_set? :Simulate But other than that... ;)
 (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 } //
Oh yes, I know. :) (See Cashew.) But unlike D/1.x, ColdC supports this for all types (in its own weird way). Right now it only works for arrays, and was originally just a fluke side-effect that got popular. It looks like D/2.x is going to open up that Pandora's Box though. Here's hoping it goes a lot better than the referenced myth. -- Chris Nicholson-Sauls
Aug 30 2007
prev sibling parent reply Lutger <lutger.blijdestijn gmail.com> writes:
kris wrote:
 
 Yeah, the proposed extensions raised all kinds of red flags for me at 
 the conference.
 
 Bluntly, it felt like the notion of "structured programming" was being 
 tossed out in favor of "slapdash programming" ... a brand new paradigm 
 to go along with the other(s) being adopted :)
What are the objections to this? Are there technical pitfalls? I liked to idea very much. It gives a flexible way of object-oriented / object-based programming similar to how I often see it implemented in C. Plus one can achieve a very nice syntactic sugar for call chaining, which is a great benefit I think. I thought this syntax for arrays is generally appreciated, so why not extend it for other types?
Aug 29 2007
parent reply kris <foo bar.com> writes:
Lutger wrote:
 kris wrote:
 Yeah, the proposed extensions raised all kinds of red flags for me at 
 the conference.

 Bluntly, it felt like the notion of "structured programming" was being 
 tossed out in favor of "slapdash programming" ... a brand new paradigm 
 to go along with the other(s) being adopted :)
What are the objections to this? Are there technical pitfalls?
Technical? Since when did that become important? ;) I belong to the "just because you can doesn't mean you should" camp, and feel that perhaps a more holistic view should be taken here? Just don't see this specific idiom as being particularly beneficial, without adding detrimental side-effect that I'll briefly touch on in a moment (it never really had significant value with arrays either, other than perhaps as a means to confuse non-experts O_+)
 I liked to idea very much. It gives a flexible way of object-oriented / 
 object-based programming similar to how I often see it implemented in C. 
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 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?
 Plus one can achieve a very nice syntactic sugar for call chaining, 
D provides that already, no? Tango supports call-chaining extensively.
 which is a great benefit I think. I thought this syntax for arrays is 
 generally appreciated, so why not extend it for other types?
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? 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. 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 (parts of this are written somewhat tongue-in-cheek, as there's only so much one can achieve via this medium. Please just take it as my opinion, and nothing more)
Aug 29 2007
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"kris" <foo bar.com> wrote in message news:fb5742$nek$1 digitalmars.com...
 Plus one can achieve a very nice syntactic sugar for call chaining,
D provides that already, no? Tango supports call-chaining extensively.
I think by call-chaining he was referring to cases such as join(reverse(split(toUpper(str)))) vs. str.toUpper.split.reverse.join(). The latter is arguably much more readable than the former.
Aug 29 2007
parent kris <foo bar.com> writes:
Jarrett Billingsley wrote:
 "kris" <foo bar.com> wrote in message news:fb5742$nek$1 digitalmars.com...
 Plus one can achieve a very nice syntactic sugar for call chaining,
D provides that already, no? Tango supports call-chaining extensively.
I think by call-chaining he was referring to cases such as join(reverse(split(toUpper(str)))) vs. str.toUpper.split.reverse.join(). The latter is arguably much more readable than the former.
Had completely missed that, Jarret. Thanks, and fair point
Aug 29 2007
prev sibling next sibling parent reply Lars Ivar Igesund <larsivar igesund.net> writes:
kris wrote:

 Lutger wrote:
 kris wrote:
 Yeah, the proposed extensions raised all kinds of red flags for me at
 the conference.

 Bluntly, it felt like the notion of "structured programming" was being
 tossed out in favor of "slapdash programming" ... a brand new paradigm
 to go along with the other(s) being adopted :)
I liked to idea very much. It gives a flexible way of object-oriented / object-based programming similar to how I often see it implemented in C.
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
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). -- Lars Ivar Igesund blog at http://larsivi.net DSource, #d.tango & #D: larsivi Dancing the Tango
Aug 30 2007
parent reply Alexander Panek <alexander.panek brainsware.org> writes:
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.
Aug 30 2007
next sibling parent Lars Ivar Igesund <larsivar igesund.net> writes:
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
Aug 30 2007
prev sibling parent reply Alexander Panek <alexander.panek brainsware.org> writes:
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)
Aug 30 2007
parent janderson <askme me.com> writes:
Alexander Panek wrote:
 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)
Perhaps, but even without interchangeability warning signs go up for me if you have a method and a function that have the same signature.
Aug 31 2007
prev sibling next sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
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!
Aug 30 2007
prev sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
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
Aug 30 2007
next sibling parent reply Brad Roberts <braddr puremagic.com> writes:
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
Aug 30 2007
parent Bill Baxter <dnewsgroup billbaxter.com> writes:
Brad Roberts wrote:
 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.
Yeh, that should help some. But that doesn't seem to do anything about foo.bar() inside a class being treated as this.bar(foo). I think that just shouldn't happen ever. Maybe that's just a bug, though. In fact I think I'll go file it as one right now. --bb
Aug 30 2007
prev sibling next sibling parent kris <foo bar.com> writes:
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
Aug 30 2007
prev sibling parent reply Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
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
Aug 30 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Chris Nicholson-Sauls wrote:
 Bill Baxter wrote:
 kris wrote:
 Lutger wrote:
 kris wrote:
 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.
Maybe even just use a semi-colon instead of comma in the arg list? size_t indexOf(T)(T[] array; T elem) { ... } ulong area (IShape shp;) { ... } void unique (ref T[] array; T) () { ... } --bb
Aug 30 2007
parent reply Nathan Reed <nathaniel.reed gmail.com> writes:
Bill Baxter wrote:
 Chris Nicholson-Sauls wrote:
 Bill Baxter wrote:
 kris wrote:
 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.
Maybe even just use a semi-colon instead of comma in the arg list? size_t indexOf(T)(T[] array; T elem) { ... } ulong area (IShape shp;) { ... } void unique (ref T[] array; T) () { ... } --bb
I like that syntax; something similiar is used in mathematics on occasion. Simple and elegant. Thanks, Nathan Reed
Aug 30 2007
parent Chris Nicholson-Sauls <ibisbasenji gmail.com> writes:
Nathan Reed wrote:
 Bill Baxter wrote:
 Chris Nicholson-Sauls wrote:
 Bill Baxter wrote:
 kris wrote:
 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.
Maybe even just use a semi-colon instead of comma in the arg list? size_t indexOf(T)(T[] array; T elem) { ... } ulong area (IShape shp;) { ... } void unique (ref T[] array; T) () { ... } --bb
I like that syntax; something similiar is used in mathematics on occasion. Simple and elegant. Thanks, Nathan Reed
Agreed. I believe the use of semicolons within params was once suggested for another purpose, ages ago, and (obviously) went nowhere. Maybe this suggestion will be a bit more lucky. -- Chris Nicholson-Sauls
Aug 30 2007
prev sibling parent reply janderson <askme me.com> writes:
Michael Deardeuff wrote:
 I am very excited about the future of D. Walter's and Andrei's talk at the
conference was awesome.
 
 However, there are still a few quirks to get out:
 This is regarding slide 9 of the presentation.
 
 I noticed that most people at the conference liked the idea of extending
library classes, but were not to pleased with the interchangability of 
 ---
 foo(a, args)
 ---
 and
 ---
 a.foo(args)
 ---
 like the arrays have.
 
 I have a suggestion: class extensions kindof like C#'s partial classes
 ----
 class A {...}
 ...
 extension class A {
    void foo(args) {...}
 }
 ...
 a.foo(args);
 ----
 (maybe the syntax could be "class extension A" or "extension A"...)
 
 In this way class extensions are clearly marked and the syntax is consistent.
 
 It would be easy to add interfaces to the library class:
 
 extension A : Visitable {
    void accept(Visitor v) {...}
 }
 
 Just an idea for you guys, Walter, Andrei, and the community.
 
 --Michael Deardeuff
 
I'm on the camp that like the interchangeable method/function syntax because it will encourage people to write better code, rather then sticking everything into the class body. It also allows you to change methods into functions and visa versa without breaking the users code. -Joel
Aug 31 2007
parent janderson <askme me.com> writes:
janderson wrote:
 Michael Deardeuff wrote:
 I am very excited about the future of D. Walter's and Andrei's talk at 
 the conference was awesome.

 However, there are still a few quirks to get out:
 This is regarding slide 9 of the presentation.

 I noticed that most people at the conference liked the idea of 
 extending library classes, but were not to pleased with the 
 interchangability of ---
 foo(a, args)
 ---
 and
 ---
 a.foo(args)
 ---
 like the arrays have.

 I have a suggestion: class extensions kindof like C#'s partial classes
 ----
 class A {...}
 ...
 extension class A {
    void foo(args) {...}
 }
 ...
 a.foo(args);
 ----
 (maybe the syntax could be "class extension A" or "extension A"...)

 In this way class extensions are clearly marked and the syntax is 
 consistent.

 It would be easy to add interfaces to the library class:

 extension A : Visitable {
    void accept(Visitor v) {...}
 }

 Just an idea for you guys, Walter, Andrei, and the community.

 --Michael Deardeuff
I'm on the camp that like the interchangeable method/function syntax because it will encourage people to write better code, rather then sticking everything into the class body. It also allows you to change methods into functions and visa versa without breaking the users code. -Joel
Here's a thought. Will this work with C code such that we could for instance expose a class C++ in C like form and then use it in D like a regular class, and visa versa? Note of course would only applies to classes without V-Tables.
Aug 31 2007