Jump to page: 1 2
Thread overview
Proposal: Extension Methods
May 12, 2008
Nick Sabalausky
May 12, 2008
janderson
May 12, 2008
Nick Sabalausky
May 13, 2008
janderson
May 13, 2008
janderson
May 12, 2008
terranium
May 12, 2008
Fawzi Mohamed
May 12, 2008
Nick Sabalausky
May 12, 2008
Pragma
May 18, 2008
Nick Sabalausky
May 18, 2008
Chris Wright
May 18, 2008
Nick Sabalausky
May 19, 2008
Chris Wright
May 19, 2008
Chris Wright
May 18, 2008
Dee Girl
May 18, 2008
Nick Sabalausky
Jun 10, 2008
Bruno Medeiros
May 12, 2008
I thought I had seen discussion on something like this back when the "Functions as Array Properties" feature was introduced, but I just did a search and didn't see much of anything. So sorry if this has been discussed to death before.

I propose adding to D a feature that C# calls extension methods. These are similar to D's "Functions as Array Properties", but provide more control and flexibility.

For any function that's not a member of a class (and maybe also static member functions of classes), if you add the modifier "extend" or "this" to first argument of the function declaration like this:

// Normal Function
void Foo(MyClass arg) {/*...*/}

// Extension Method (I'm proposing either of these, but not both):
void Foo(this MyClass arg) {/*...*/} // C#-style
void Foo(extend MyClass arg) {/*...*/} // Might be more readable

(Although, there wouldn't actually be overloading based soley on whether or not it's declared as an extension method. (Or would there? Probably not.))

Then that allows you to call Foo like this:

auto obj = new MyClass();

// Always allowed
Foo(obj);

// Allowed if and only if Foo has been declared
// using the above extension method syntax.
// But regardless, Foo never has access to private members
// of MyClass, since it still isn't a true member.
obj.Foo();

This should also be allowed for primitives:

void Foo(extend int arg);
int myInt = 7;
myInt.Foo();
5.Foo(); // Might interfere with parsing of floating-point literals, though.

This has two advantages over the current "Functions as Array Properties" feature:

1. It supports more than just arrays (obviously).
2. The special syntax is only available if the function's author intends it
as a non-member "extension" to the given type.

Possible modifications to this proposal:

- If advantage #2 is deemed to be an unwarranted concern, I'd be happy to at least have the current "Functions as Array Properties" feature extended to all types, not just arrays.

- Maybe declaring a function as an extension method would *require* it to be called using extension method syntax. Although under this arrangement, if you wanted a function to be callable via either syntax (but would this ability really be desirable?), that would require a function overload or a messy kludge like using "maybe_extend" instead of "extend".


May 12, 2008
Nick Sabalausky wrote:
> I thought I had seen discussion on something like this back when the "Functions as Array Properties" feature was introduced, but I just did a search and didn't see much of anything. So sorry if this has been discussed to death before.
> 
> I propose adding to D a feature that C# calls extension methods. These are similar to D's "Functions as Array Properties", but provide more control and flexibility.
> 
> For any function that's not a member of a class (and maybe also static member functions of classes), if you add the modifier "extend" or "this" to first argument of the function declaration like this:
> 
> // Normal Function
> void Foo(MyClass arg) {/*...*/}
> 
> // Extension Method (I'm proposing either of these, but not both):
> void Foo(this MyClass arg) {/*...*/} // C#-style
> void Foo(extend MyClass arg) {/*...*/} // Might be more readable
> 
> (Although, there wouldn't actually be overloading based soley on whether or not it's declared as an extension method. (Or would there? Probably not.))
> 
> Then that allows you to call Foo like this:
> 
> auto obj = new MyClass();
> 
> // Always allowed
> Foo(obj);
> 
> // Allowed if and only if Foo has been declared
> // using the above extension method syntax.
> // But regardless, Foo never has access to private members
> // of MyClass, since it still isn't a true member.
> obj.Foo();
> 
> This should also be allowed for primitives:
> 
> void Foo(extend int arg);
> int myInt = 7;
> myInt.Foo();
> 5.Foo(); // Might interfere with parsing of floating-point literals, though.
> 
> This has two advantages over the current "Functions as Array Properties" feature:
> 
> 1. It supports more than just arrays (obviously).
> 2. The special syntax is only available if the function's author intends it as a non-member "extension" to the given type.
> 
> Possible modifications to this proposal:
> 
> - If advantage #2 is deemed to be an unwarranted concern, I'd be happy to at least have the current "Functions as Array Properties" feature extended to all types, not just arrays.
> 
> - Maybe declaring a function as an extension method would *require* it to be called using extension method syntax. Although under this arrangement, if you wanted a function to be callable via either syntax (but would this ability really be desirable?), that would require a function overload or a messy kludge like using "maybe_extend" instead of "extend".
> 
> 

Walter talked about the proposal for interchangeable method/functions. It was talked about at the D conference.  I'm not sure how much resistance he got to the idea.

I'm a big fan on interchangeable function/methods without the additional syntax as it would push the flexibility to the user rather then the lib designer.  I have mentioned it several times.

-Joel
May 12, 2008
It seems like C# is so young, that D was mostly done when it appeared.
May 12, 2008
On 2008-05-12 06:03:01 +0200, "Nick Sabalausky" <a@a.a> said:

> I thought I had seen discussion on something like this back when the
> "Functions as Array Properties" feature was introduced, but I just did a
> search and didn't see much of anything. So sorry if this has been discussed
> to death before.
> 
> I propose adding to D a feature that C# calls extension methods. These are
> similar to D's "Functions as Array Properties", but provide more control and
> flexibility.
> 
> For any function that's not a member of a class (and maybe also static
> member functions of classes), if you add the modifier "extend" or "this" to
> first argument of the function declaration like this:
> 
> // Normal Function
> void Foo(MyClass arg) {/*...*/}
> 
> // Extension Method (I'm proposing either of these, but not both):
> void Foo(this MyClass arg) {/*...*/} // C#-style
> void Foo(extend MyClass arg) {/*...*/} // Might be more readable
> 
> (Although, there wouldn't actually be overloading based soley on whether or
> not it's declared as an extension method. (Or would there? Probably not.))
> 
> Then that allows you to call Foo like this:
> 
> auto obj = new MyClass();
> 
> // Always allowed
> Foo(obj);
> 
> // Allowed if and only if Foo has been declared
> // using the above extension method syntax.
> // But regardless, Foo never has access to private members
> // of MyClass, since it still isn't a true member.
> obj.Foo();
> 
> This should also be allowed for primitives:
> 
> void Foo(extend int arg);
> int myInt = 7;
> myInt.Foo();
> 5.Foo(); // Might interfere with parsing of floating-point literals, though.
> 
> This has two advantages over the current "Functions as Array Properties"
> feature:
> 
> 1. It supports more than just arrays (obviously).
> 2. The special syntax is only available if the function's author intends it
> as a non-member "extension" to the given type.
> 
> Possible modifications to this proposal:
> 
> - If advantage #2 is deemed to be an unwarranted concern, I'd be happy to at
> least have the current "Functions as Array Properties" feature extended to
> all types, not just arrays.
> 
> - Maybe declaring a function as an extension method would *require* it to be
> called using extension method syntax. Although under this arrangement, if
> you wanted a function to be callable via either syntax (but would this
> ability really be desirable?), that would require a function overload or a
> messy kludge like using "maybe_extend" instead of "extend".

I find this kind of extensions nice, they allow to work around library misdesign (or to handle special cases) in a much better way.
Dynamic language often can do it.
A static language language that had the idea of a posteriori extension very well developed:
	http://www.aldor.org/docs/HTML/chap10.html
(the language itself is basically dead but for other reasons)
The question is how difficult is their implementation, and how useful they really are, as these  can lead also to bad design if overused, but well used they are really nice.

Fawzi

May 12, 2008
"Fawzi Mohamed" <fmohamed@mac.com> wrote in message news:g09ivq$6bk$1@digitalmars.com...
> I find this kind of extensions nice, they allow to work around library
> misdesign (or to handle special cases) in a much better way.
> Dynamic language often can do it.
> A static language language that had the idea of a posteriori extension
> very well developed:
> http://www.aldor.org/docs/HTML/chap10.html
> (the language itself is basically dead but for other reasons)
> The question is how difficult is their implementation, and how useful they
> really are, as these  can lead also to bad design if overused, but well
> used they are really nice.
>

I didn't read that page very closely, but it sounds like the extensions in Aldor are true members of the class they're extending and able to access private members? If so, that's the first time I've seen that in a static language (Which is kind of interesting). It also sounds kind of like partial classes, but with the original class not needing to be declared as partial.

Maybe it's just an unsubstantiated gut feeling, but that stikes me as either breaking encapsulation, or possibly causing trouble for dynamic linking (ie, one assembly's version of the class has the methods, and another assembly's version doesn't - but then, couldn't that affect C#'s partial classes too? I wonder how they solved it?), or otherwise reducing some of the benefits of strong static typing.


May 12, 2008
"janderson" <askme@me.com> wrote in message news:g08j47$8cs$1@digitalmars.com...
>
> Walter talked about the proposal for interchangeable method/functions. It was talked about at the D conference.  I'm not sure how much resistance he got to the idea.
>
> I'm a big fan on interchangeable function/methods without the additional syntax as it would push the flexibility to the user rather then the lib designer.  I have mentioned it several times.
>

Maybe someone can point out that I'm worrying over nothing, but here's my main concern about that:

Unless I misunderstand the "interchangeable methods/functions" concept, that means that the following code would result in conflict issues with "Foo":

// Note: sample code untested
module moduleA
{
  class A
  {
    public void Foo() {}
  }
  void Bar() {}
}

module moduleB
{
  import moduleA;

  void Foo(ref A a) {}
  void Bar() {}
  void main(char[][] args) {}
}

In this example, there is a conflict with Bar(). But this is OK, since, in main() we can disambiguate like (I might be forgetting the details here, but it's something like this):

moduleA.Bar();  // moduleA's Bar()
.Bar();  // moduleB's Bar()

// On a totally separate note, what does this do?
// Does this assume one Bar() or the other,
// or is it disallowed due to ambiguity?
Bar();

So with Bar() we're ok. But how would you disambiguate Foo() when using member function syntax?

auto a = new A();

// moduleA:
a.moduleA.Foo(); // Makes it seem like "moduleA" belongs to "a"
moduleA.a.Foo(); // Makes it seem like "a" belongs to "moduleA"
a.A.Foo(); // Makes it seem like "A" is a member of "a"
A.a.Foo(); // Makes it seem like "a" is a static member of "A"
a.(moduleA.Foo)(); // Kinda ugly, but maybe?
a.(A.Foo)(); // Kinda ugly, but maybe?

// moduleB:
a..Foo();  // As Earnest P. Worrell would say, "Eeeewwww..."
.a.Foo();  // Makes it seem like the scope resolution
           // operator is referring to "a" instead of "Foo"
a.(.Foo)();  // Kinda ugly, but maybe?

Seems to me you could solve that three ways, none of which seem ideal:

1. Disallow member function syntax when a conflict like this exists. So all of a sudden, I can't call A's own member function with member function syntax. Yuck.

2. Force member function syntax to mean moduleA's Foo() and non-member syntax to mean moduleB's Foo(). But this could result in accidentally calling the wrong Foo(), especially when people are accustomed to being able to use "obj.Func();" and "Func(obj);" interchangeably.

3. Generate a "function redefined" compile-time error. But this is inconsistent with Bar().


May 12, 2008
Nick Sabalausky Wrote:

> Maybe it's just an unsubstantiated gut feeling, but that stikes me as either breaking encapsulation, or possibly causing trouble for dynamic linking (ie, one assembly's version of the class has the methods, and another assembly's version doesn't - but then, couldn't that affect C#'s partial classes too? I wonder how they solved it?), or otherwise reducing some of the benefits of strong static typing.
> 

IMO, yes it does break encapsulation, but it shouldn't disrupt dynamic linking.

The former is really more of a "best practice" kind of thing.  My feeling on that is that a language always generates a wart when it tries to hold too tightly to such things since there's always a case where it doesn't apply.  Perhaps "extension methods" are one of those cases?

As to the latter, dynamic linking, I've played around a lot in this area.  Dynamically linking against anything but an interface is a bad idea for a few reasons; obviously interfaces wouldn't apply with "extension methods".  But if you are coding against a given implementation of a class or struct, then there is no problem since the linked library should have or require the same class or struct.

For dynamic linking and working with classes/structs, the real problem is: do the host program and the dynamic library have access to the same *version* of the class/struct in question?  If not, then there's a mismatch between the binary size and/or vtable layout of the items in question. And that's clearly not a problem that is limited to our hypthotetical "extension methods", so again, there shouldn't be any new technical problems introduced, were they implemented.

- Pragma
May 13, 2008
Nick Sabalausky wrote:
> "janderson" <askme@me.com> wrote in message news:g08j47$8cs$1@digitalmars.com...
>> Walter talked about the proposal for interchangeable method/functions. It was talked about at the D conference.  I'm not sure how much resistance he got to the idea.
>>
>> I'm a big fan on interchangeable function/methods without the additional syntax as it would push the flexibility to the user rather then the lib designer.  I have mentioned it several times.
>>
> 
> Maybe someone can point out that I'm worrying over nothing, but here's my main concern about that:
> 
> Unless I misunderstand the "interchangeable methods/functions" concept, that means that the following code would result in conflict issues with "Foo":
> 
> // Note: sample code untested
> module moduleA
> {
>   class A
>   {
>     public void Foo() {}
>   }
>   void Bar() {}
> }
> 
> module moduleB
> {
>   import moduleA;
> 
>   void Foo(ref A a) {}
>   void Bar() {}
>   void main(char[][] args) {}
> }
> 
> In this example, there is a conflict with Bar(). But this is OK, since, in main() we can disambiguate like (I might be forgetting the details here, but it's something like this):
> 
> moduleA.Bar();  // moduleA's Bar()
> .Bar();  // moduleB's Bar()
> 
> // On a totally separate note, what does this do?
> // Does this assume one Bar() or the other,
> // or is it disallowed due to ambiguity?
> Bar();
> 
> So with Bar() we're ok. But how would you disambiguate Foo() when using member function syntax?
> 
> auto a = new A();
> 
> // moduleA:
> a.moduleA.Foo(); // Makes it seem like "moduleA" belongs to "a"
> moduleA.a.Foo(); // Makes it seem like "a" belongs to "moduleA"
> a.A.Foo(); // Makes it seem like "A" is a member of "a"
> A.a.Foo(); // Makes it seem like "a" is a static member of "A"
> a.(moduleA.Foo)(); // Kinda ugly, but maybe?
> a.(A.Foo)(); // Kinda ugly, but maybe?
> 
> // moduleB:
> a..Foo();  // As Earnest P. Worrell would say, "Eeeewwww..."
> .a.Foo();  // Makes it seem like the scope resolution
>            // operator is referring to "a" instead of "Foo"
> a.(.Foo)();  // Kinda ugly, but maybe?
> 
> Seems to me you could solve that three ways, none of which seem ideal:
> 
> 1. Disallow member function syntax when a conflict like this exists. So all of a sudden, I can't call A's own member function with member function syntax. Yuck.
> 
> 2. Force member function syntax to mean moduleA's Foo() and non-member syntax to mean moduleB's Foo(). But this could result in accidentally calling the wrong Foo(), especially when people are accustomed to being able to use "obj.Func();" and "Func(obj);" interchangeably.
> 
> 3. Generate a "function redefined" compile-time error. But this is inconsistent with Bar().
> 
> 


If the code has been multiply defined, the compiler should respond that it does not know what version to use and ask for a qualifier.

What that qualifier is I don't know.  Perhaps:

Foo((a));

and

(a).Foo();

-Joel
May 13, 2008
Nick Sabalausky wrote:
> "janderson" <askme@me.com> wrote in message news:g08j47$8cs$1@digitalmars.com...
>> Walter talked about the proposal for interchangeable method/functions. It was talked about at the D conference.  I'm not sure how much resistance he got to the idea.
>>
>> I'm a big fan on interchangeable function/methods without the additional syntax as it would push the flexibility to the user rather then the lib designer.  I have mentioned it several times.
>>
> 
> Maybe someone can point out that I'm worrying over nothing, but here's my main concern about that:
> 
> Unless I misunderstand the "interchangeable methods/functions" concept, that means that the following code would result in conflict issues with "Foo":
> 
> // Note: sample code untested
> module moduleA
> {
>   class A
>   {
>     public void Foo() {}
>   }
>   void Bar() {}
> }
> 
> module moduleB
> {
>   import moduleA;
> 
>   void Foo(ref A a) {}
>   void Bar() {}
>   void main(char[][] args) {}
> }
> 
> In this example, there is a conflict with Bar(). But this is OK, since, in main() we can disambiguate like (I might be forgetting the details here, but it's something like this):
> 
> moduleA.Bar();  // moduleA's Bar()
> .Bar();  // moduleB's Bar()
> 
> // On a totally separate note, what does this do?
> // Does this assume one Bar() or the other,
> // or is it disallowed due to ambiguity?
> Bar();
> 
> So with Bar() we're ok. But how would you disambiguate Foo() when using member function syntax?
> 
> auto a = new A();
> 
> // moduleA:
> a.moduleA.Foo(); // Makes it seem like "moduleA" belongs to "a"
> moduleA.a.Foo(); // Makes it seem like "a" belongs to "moduleA"
> a.A.Foo(); // Makes it seem like "A" is a member of "a"
> A.a.Foo(); // Makes it seem like "a" is a static member of "A"
> a.(moduleA.Foo)(); // Kinda ugly, but maybe?
> a.(A.Foo)(); // Kinda ugly, but maybe?
> 
> // moduleB:
> a..Foo();  // As Earnest P. Worrell would say, "Eeeewwww..."
> .a.Foo();  // Makes it seem like the scope resolution
>            // operator is referring to "a" instead of "Foo"
> a.(.Foo)();  // Kinda ugly, but maybe?
> 
> Seems to me you could solve that three ways, none of which seem ideal:
> 
> 1. Disallow member function syntax when a conflict like this exists. So all of a sudden, I can't call A's own member function with member function syntax. Yuck.
> 
> 2. Force member function syntax to mean moduleA's Foo() and non-member syntax to mean moduleB's Foo(). But this could result in accidentally calling the wrong Foo(), especially when people are accustomed to being able to use "obj.Func();" and "Func(obj);" interchangeably.
> 
> 3. Generate a "function redefined" compile-time error. But this is inconsistent with Bar().
> 
> 

Actually maybe using alias like we do now will do that job.

-Joel
May 18, 2008
"Nick Sabalausky" <a@a.a> wrote in message news:g08fha$2e5$1@digitalmars.com...
>I thought I had seen discussion on something like this back when the "Functions as Array Properties" feature was introduced, but I just did a search and didn't see much of anything. So sorry if this has been discussed to death before.
>
> I propose adding to D a feature that C# calls extension methods. These are similar to D's "Functions as Array Properties", but provide more control and flexibility.
>
> For any function that's not a member of a class (and maybe also static member functions of classes), if you add the modifier "extend" or "this" to first argument of the function declaration like this:
>
> // Normal Function
> void Foo(MyClass arg) {/*...*/}
>
> // Extension Method (I'm proposing either of these, but not both):
> void Foo(this MyClass arg) {/*...*/} // C#-style
> void Foo(extend MyClass arg) {/*...*/} // Might be more readable
>
> (Although, there wouldn't actually be overloading based soley on whether or not it's declared as an extension method. (Or would there? Probably not.))
>
> Then that allows you to call Foo like this:
>
> auto obj = new MyClass();
>
> // Always allowed
> Foo(obj);
>
> // Allowed if and only if Foo has been declared
> // using the above extension method syntax.
> // But regardless, Foo never has access to private members
> // of MyClass, since it still isn't a true member.
> obj.Foo();
>
> This should also be allowed for primitives:
>
> void Foo(extend int arg);
> int myInt = 7;
> myInt.Foo();
> 5.Foo(); // Might interfere with parsing of floating-point literals,
> though.
>
> This has two advantages over the current "Functions as Array Properties" feature:
>
> 1. It supports more than just arrays (obviously).
> 2. The special syntax is only available if the function's author intends
> it as a non-member "extension" to the given type.
>
> Possible modifications to this proposal:
>
> - If advantage #2 is deemed to be an unwarranted concern, I'd be happy to at least have the current "Functions as Array Properties" feature extended to all types, not just arrays.
>
> - Maybe declaring a function as an extension method would *require* it to be called using extension method syntax. Although under this arrangement, if you wanted a function to be callable via either syntax (but would this ability really be desirable?), that would require a function overload or a messy kludge like using "maybe_extend" instead of "extend".
>

I was just looking through the documentation on some of the Phobos stuff that's new in D2, and at pipe! and compose! in particular. This is kind of nice (from docs):

int[] a = pipe!(readText, split, map!(to!(int)))("file.txt");

Not to nag about extension methods (well, ok, yes: to nag ;) ), but with extension methods (regardless if they're explicit or implicit), that could be cleaned up to:

int[] a = "file.txt".readText().split().map!(to!(int)))();

Granted, this doesn't actually create a new composite function. But for cases like this one where a reusable composite function isn't needed, it increases readablity quite a bit.

It would also allow extra paramaters to be specified without having to turn them into template parameters:

int[] a = "file.csv".readText().split(",").map!(to!(int)))();

Maybe that might break functional-style code if that's what the coder is going for (not sure, my functional experience is limited), but in that case they can still fall back on pipe!.


« First   ‹ Prev
1 2