View mode: basic / threaded / horizontal-split · Log in · Help
May 12, 2008
Proposal: Extension Methods
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
Re: Proposal: Extension Methods
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
Re: Proposal: Extension Methods
It seems like C# is so young, that D was mostly done when it appeared.
May 12, 2008
Re: Proposal: Extension Methods
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
Re: Proposal: Extension Methods
"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
Re: Proposal: Extension Methods
"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
Re: Proposal: Extension Methods
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
Re: Proposal: Extension Methods
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
Re: Proposal: Extension Methods
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
Re: Proposal: Extension Methods
"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
Top | Discussion index | About this forum | D home