Extending existing classes
One other point that came up in the static import thread was extending existing classes. It's not uncommon to want to add specific methods to existing classes - or at least have the appearance of doing this. For example, I might want to add a new method to the string class, so I can call it with:
string s = ...;
string r = s.Permute(10, 15);
rather than
string r = Utils.Permute(s, 10, 15);
We've discussed this a few times in the past, and we think this is an important scenario to consider. There are a number of reasons why you wouldn't want to actually modify the class, of which security is just one consideration. But one could think of a way of writing something like (very hypothetical syntax):
class Utils
{
[AddTo(typeof(string))]
public static string Permute(string s, int a, int b) {...}
}
and have the compiler then allow you to use it as if it were part of the string class. This is very useful, but perhaps not terribly understandable, and would certainly be open to abuse.
Another option would be to allow the following definition (also hypothetical)
class MyString<T>: T where T:string
{
public string Permute(int a, int b) {...}
}
Now, if you use a MyString, you can add methods onto the existing method. This would also be useful to add a specific implementation of something onto an existing class, somewhat in the way that Mixins work.
We have no plans in this area, but will likely discuss the scenario more in the future.
Comments
- Anonymous
July 01, 2004
My opinion is if you are going to do something like this to C#, you use prototypes like you have in Javascript, JScript.NET, etc.
(I'm sure you know what I mean, in case someone reading this doesn't)
function MyClass_MyFunction() {
}
function MyClass() {
}
MyClass.prototype.MyFunction = MyClass_MyFunction;
new MyClass().MyFunction() - Anonymous
July 01, 2004
Sounds a bit like Delphi's class helpers. - Anonymous
July 01, 2004
The comment has been removed - Anonymous
July 01, 2004
I think we should be more open to static helper methods like that. I find that they make interfaces much more useful.
For example, almost all of the new methods on List<T> that take delegates as arguments and perform common list operations can be defined in terms of the IList<T> interface, except that there is nowhere to put them because:
a) if they go in the interface, every implementer of that interface has to provide an implementation, even though almost all or all of those implementations will or should be the same because the behavior is defined in terms of the existing interface members
b) C# doesn't allow static members on interfaces (although to my understanding the CLR does)
c) if they are defined on a helper class, discoverability becomes a problem
In this spefic case, I suggest that we make static versions of all those methods on List<T> or some other class in the System.Collections.Generic namespace that take an IList<T> as an argument, but a more general solution is highly desirable since there are a number of related problems. - Anonymous
July 01, 2004
I really like the idea of being able to add methods to existing classes. A friend of mine had an argument with Stroustrup about it in the C++ world - he always (and unsuccessfully) wanted it added.
as far as syntax goes, how's this for an idea?
extender class StringHelper : String
{
public bool Contains( string subString )
{return Instr( subString)> -1;}
public static string FairlyUnique( int length)
{
return Guid.NewGuid().ToString().Substring( 1, length );
}
}
Allowing many extenders to exist for a particular class, and giving extenders only public access to the class they are extending.
This would brilliantly gel with other requests - like it would get rid of the need to add static functions to interfaces for instance - because you could then do this:
public interface IPreferencesStorage
{
...
}
extender class IPreferencesStorageFactory : IPreferencesStorage
{
public IPreferencesStorage CreateFromConfiguration( SystemConfiguration config )
{
return (config.UseRegistryForPreferences)
? new RegistryPreferenceStorage()
: new FilePreferenceStorage();
}
}
And then you just have to get to have code like
IPreferencesStorage storage = IPreferencesStorage.CreateFromConfiguration( currentSystemConfiguration ); - Anonymous
July 01, 2004
Hi,
I think this is just a code game..
Here is my option:
public codegame class StringHelper : string//even the string class is sealed
{
//no fields
//will compile into static public string CodeGameLeft(string codegametarget,int len)
public string Left(int len)
{
return Substring(0,len);
}
public string SafeLeft(int len)
{
if(Length>=len)
return this;
return Substring(0,len);
}
}
and call it just like:
string s="hello world!";
StringHelper sh=s;//implicit..
string l1=s.Left(3);
string l2=((StringHelper)s).Left(4);
and it just means :
string s="hello world!";
string l1=StringHelper.CodeGameLeft(s,3);
string l2=StringHelper.CodeGameLeft(s,4);
of cause it's would be nice if this syntax is ok:
string l3=s<StringHelper>.Left(5); - Anonymous
July 01, 2004
I'd say that although it sounds nice to be able to add methods to existing classes, it would probably be a bad idea (putting on my maintenance and code readability hat). That said it would be nice to have a different kind of "inheritance" that allows a "public-only" view of the base class. That means that it is entirely clear which class the additional methods belong to. Cases where this would be useful would be ado.net, where db vendors create sealed class implementations of Connection and DataReader classes.
When trying to extend these classes you need to make a clunky wrapper class that implements the interfaces, when you just want to add 1 or 2 methods to them. - Anonymous
July 01, 2004
The comment has been removed - Anonymous
July 02, 2004
Doug McClean's comments on the new List<T> methods is correct. Most of those methods would best be attached to IList<T>, and many of them should in fact be attached to IEnumerable<T> (i.e. the ones that dont rely on an indexer).
I dont think that adding methods to classes is the right way to go.
Interfaces with default methods might be the way to go, but.. it seems to break the basic model of what an interface is.
Static helper methods (and operators) in an interface is more like what we are looking for.
Maybe whats needed is true multimethods. - Anonymous
July 04, 2004
This feature is a long time coming but I would prefer the following syntax:
public class StringExtensions : static string
{
public String Left(int count)
{
return this.Substring(0, count);
}
}
The "static" can be used to signify the class is extending sidways. - Anonymous
July 05, 2004
Cool
C# becomes type safe Ruby - Anonymous
July 06, 2004
The comment has been removed - Anonymous
August 04, 2004
This concept is new enough, at least to me, to be open to consideration despite a couple of obvious liabilities.
From an object oriented design perspective the questions revolve arround the relationship of the operation to the type of thing upon which the operation is performed. In the original example, a permutation function that does not belong to any class can act upon a string without violating the nature of what it means to be a string. Adding the permutation function to the string will necesssarily raise the question, is Permutation consistent with the concept of a string type? Since we may permute numbers as well as strings, does that imply that a string is a number? I realize that this is pretty thin but this sort of confusion is the most common cause of "bad" code. A mis-diagnosed problem yields a solution that is "good enough" for the moment but quickly breaks when attempting to extend the solution to a similar problem.
First ask, what is the problem being solved? If you are capable of adding any behaviour to a class, without consideration for the nature of the class, you stand a good chance of introducing confusion, not clarity. E.g., you can add the behaviour of flying to a human being without changing the human into a bird, airplane or Icarus resulting in utter confusion. Such a development would not be progress. On the other hand, you can hobbies, abilities and preferences to a human and be coherent. And the abilitiy to add such properties and behaviours is certainly preferable to defining a new derived class of type cook, athlete or programmer.
The potential good that can come from such a feature is the complete abstraction of common features into discrete functors that may be applied to a wide variety of types that cannot be readily predicted prior to development. The potential evil is a level of spaghetti code that would make mangled C++ code look like an elegant algorithm worthy of Knuth. - Anonymous
June 07, 2009
PingBack from http://weakbladder.info/story.php?id=3126