Issue Details (XML | Word | Printable)

Key: BOO-564
Type: Wish Wish
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Sorin Ionescu
Votes: 0
Watchers: 1
Operations

If you were logged in you would be able to see more operations.
Boo

Better extension methods syntax.

Created: 29/Oct/05 05:24 PM   Updated: 20/May/08 09:09 AM
Component/s: Compiler
Affects Version/s: None
Fix Version/s: 0.8.3

Time Tracking:
Not Specified

File Attachments: 1. File ExtensionOfAttribute.boo (2 kB)

Image Attachments:

1. Extension Method Example.jpg
(200 kB)


 Description  « Hide
The current syntax is not good enough.
Traditionally, self refers to a member of a class from inside that class. In extension methods, self refers to a class from outside that class.
Also, currently, extension methods don't stand out well. I have a solution for making them stand out.
I don't have a solution for "self" yet.
static def Each(self as IEnumerable, func as callable):
. for item in self:
. func(item)

We do:

[ExtensionOf(IEnumerable)] def Each(func as callable):
. for item in self:
. func(item)

This is similar to tye typeof(Type). One can clearly see that it's an extension method from very far.



 All   Comments   Work Log   Change History      Sort Order: Ascending order - Click to sort in descending order
Arron Washington added a comment - 29/Oct/05 05:27 PM
def Each(func as callable) extends IEnumerable ?

Sorin Ionescu added a comment - 29/Oct/05 06:00 PM
Implementation of my proposed syntax.

Sorin Ionescu added a comment - 29/Oct/05 07:22 PM
The "value" keyword is much better than "self" because it is already implied on properties. "Self" is confusing because you normally don't use it in static methods.

Sorin Ionescu added a comment - 29/Oct/05 07:23 PM
Updated to use "value" instead of "self".

Doug H added a comment - 29/Oct/05 08:03 PM
What keyword would you use if support is added for extension properties?
I like either keep using "self" or one of ckknight's proposals:
[ExtensionMethod]
def Say(s as string):
print "you said", s.ToUpper()

That makes it easier to convert regular methods to extension methods, too.


Sorin Ionescu added a comment - 29/Oct/05 08:37 PM
You would still use "value" in properties. There is no conflict.

Chuck Esterbrook added a comment - 09/Dec/05 02:49 PM
extend IDictionary:

def Get(key, default) as object:
return self[key] if ContainsKey(key) else default

def GetOrSet(key, default) as object:
if ContainsKey(key):
return self[key]
else:
return self[key]=default

def Update(d as IDictionary):
for key in d.Keys:
self[key] = d[key]

Selling points in no particular order:

  • it's explicit
  • it's easy to have several extension members
  • it makes it natural to have extension properties
  • you don't have to declare self
  • you don't have to keep naming what's extended (just like class
    members don't have to keep naming their class)
  • it reuses the same brainspace that knows how to write classes

Cameron Kenneth Knight added a comment - 09/Dec/05 02:53 PM
if you have a syntax like "extend IDictionary:" it doesn't translate well between the upcoming C# 3.0. For example, System.Query.Sequence handles most of the LINQ stuff and includes both extension and non-extension methods.

Arron Washington added a comment - 09/Dec/05 02:57 PM
How does that apply? Boo is not C#, and the syntax used to declare extension methods in C# doesn't have to look anything like how C# does it.

Cameron Kenneth Knight added a comment - 09/Dec/05 03:27 PM
well, how would I make a class that contains both extension methods and non-extension methods, then?

I prefer the [ExtensionOf(type)] syntax.


Arron Washington added a comment - 09/Dec/05 03:33 PM
You wouldn't. Why would you try to mix instance / static methods and extension methods? How useful is that?

Cameron Kenneth Knight added a comment - 09/Dec/05 04:55 PM
it's done in LINQ.

in the System.Query.Sequence class:

Extension Methods:
Select
SelectMany
Where
Take
Skip
TakeWhile
SkipWhile
Concat
OrderBy
ThenBy
OrderByDescending
ThenByDescending
Reverse
GroupBy
Distinct
Union
Intersect
Except
ToSequence
ToArray
ToList
ToDictionary
EqualAll
First
FirstOrDefault
ElementAt
Any
All
Count
Sum
Min
Max
Average

Non-Extension Methods:
Range
Repeat

Though they are primarily extension methods, the non-extension methods do belong in the same place.


Chuck Esterbrook added a comment - 12/Dec/05 12:10 AM
It's not clear to me why they belong in the same class, why not just the same namespace? But in any case, this is no reason to not use the "extend Foo:" syntax. Consider that we can already do this:

class A:
___ class B:
______ pass

and that "extend Foo:" is meant to parallel "class Foo:". So if we desire extenions inside classes then allow them there too:

class Sequence:
___ extend IEnumerable:
______ def Select(...)
_________ pass
______ def SelectMany(...)
_________ pass

But don't make me retype IEnumerable 30 times!


Chuck Esterbrook added a comment - 12/Dec/05 12:12 AM
I also want to point out that since the "extend Foo:" makes the declarations natural, it not only paves the way for extension properties, but also extension to

Chuck Esterbrook added a comment - 12/Dec/05 12:24 AM
I also want to point out that since the "extend Foo:" syntax makes the declarations natural, it not only paves the way for extension properties, but also extension fields. And not only in terms of declarations, but also keeping the extension fields private to the extension:

extend Foo:
___ _bar as int
___ Bar as int:
______ get:
_________ return _bar
______ set:
_________ assert value>0
_________ _bar = value

The getting and setting of the field _bar would actually be something like the access of a compiler generated Dictionary<[weak] object, Dictionary<string, object>> which maps objects to extension field names to values.

This is just an idea. I'm not proposing that supporting fields be included with BOO-564. I just wanted to show where the "extend Foo:" syntax could take us.


Rodrigo B. de Oliveira added a comment - 10/Jun/06 10:56 AM
I'm dropping the 'self' syntax in favor of the proposals above and to also support extension properties.

The low level way of defining any extension will simply be applying the existing Extension attribute.

Where before we did:

def DoubleTrouble(self as string):
return self*2

we will now do:

[Extension]
static def DoubleTrouble(s as string):
return s*2

'self' will no longer be allowed as a method parameter by the parser. Remember that this is the low level way.

The high level way will be implemented as a new type of macro. A type declaration macro (MacroTypeDeclaration ast node) and it will be pretty much the extend syntax in the comment above (although field extension support depends on how good the macro will be).

The macro will translate:

extend string:
def DoubleTrouble():
return self*2
IsNullOrEmpty:
get:
return self is null or len(self) == 0

To something like the lower level:

[Extension]
static def DoubleTrouble(extendee as string):
return extendee*2

[Extension]
static IsNullOrEmpty[extendee as string]:
get:
return extendee is null or len(extendee) == 0

which the programmer could have typed in (him|her)self.

I think this will give us:

  • a more modular extension implementation;
  • a new and powerful type macro facility;
  • a syntax which is not hardcoded in the parser and thus can be safely changed/contributed by users through macros;