|
sherifffruitfly wrote: In c#, interfaces suffice.
No they don't, because you have to implement the interface yourself in every derived class, instead of just inheriting the functionality of the base class.
- S
50 cups of coffee and you know it's on!
|
|
|
|
|
You can use composition to substitute for inheritance in 99% of cases and composition is preferred over inheritance. Why create a potentially more problematic solution using multiple inheritance when you could be using composition?
|
|
|
|
|
scoobydoo27 wrote: Why create a potentially more problematic solution using multiple inheritance when you could be using composition?
Here's why:[^]
People quite correctly say that you don't need multiple inheritance, because anything you can do with multiple inheritance you can also do with single inheritance. You just use the delegation trick I mentioned. Furthermore, you don't need any inheritance at all, because anything you do with single inheritance you can also do without inheritance by forwarding through a class. Actually, you don't need any classes either, because you can do it all with pointers and data structures. But why would you want to do that? When is it convenient to use the language facilities? When would you prefer a workaround? I've seen cases where multiple inheritance is useful, and I've even seen cases where quite complicated multiple inheritance is useful. Generally, I prefer to use the facilities offered by the language to doing workarounds.
|
|
|
|
|
Excellent post.
Some people have illogical fear of multiple inheritence, they once read something bad will happen if you use it, they can't remember exactly what, but just give it a wide berth to be safe.
Really, there is one case where multiple inheritence causes problems (i.e. when you have a diamond shaped hierarchy). The solution is just to avoid using it in that specific case. Disabling the feature completely is throwing the baby out with the bathwater.
|
|
|
|
|
Its the perfect answer on "needs in multiple inheritance" question for all newbies PIEBALDconsult talked about
|
|
|
|
|
I said they sufficed. I did not say they were exactly the same thing.
|
|
|
|
|
Part of the reason is that .NET is multi-language and most OO languages don't provide MI. Not enabling it made MS's job easier. It wouldn't have been an impossible task to have it in, say, C# by itself though. The Eiffel guys have been able to support MI on .NET and still maintain language interoperability.
Having said that I think most would consider generics to be a more essential feature than MI.
Kevin
|
|
|
|
|
MI is useful, especially when you need to write code that would combine code from multiple sources.
Eiffel supports multiple inheritance using interface inheritance + composition because the .net runtime does not support MI. The only reason that MS or Sun did not include MI in their languages is that it is extremely difficult to implement a class loader that would support multiple base classes. All the other arguments against MI are artificial
|
|
|
|
|
... I would love default parameter value in a programming language.
P.S. Sorry C++
|
|
|
|
|
FYI: C++ has default parameter support, and they have to be at the end of the param list, just like optional parameters in VB.
I.e.
void Poo(int parm1 = 1, int parm2 = 42)
{
}
Usage:
Poo(); // parm1 will be 1, parm2 will be 42
Poo(29); // parm1 will be 29, parm2 will be 42
Poo(29, 33); // parm1 will be 29, parm2 will be 33
Maybe you were thinking C#, which I think doesn't have default parms?
- S
50 cups of coffee and you know it's on!
|
|
|
|
|
You can't have default parameters but you can achieve the same things in C#.
void Foo(int x, int y) {....}
void Foo(int x) { Foo(x, 5); }
void Foo() { Foo(9, ); }
|
|
|
|
|
Steve Echols wrote: C++ has default parameter support
Yes, I know that. My "Sorry C++" is meant to avoid offending those C++ guys who hate to be associated in any way with VB.
|
|
|
|
|
Why would anyone want that?
Let's say you have a function called IsUserLoggedOn which returns True or False. With the new feature, it will return { True, False, NotSure, WhateverAnswerYouWant } as the output, very helpful.
|
|
|
|
|
I think what they mean is support for something like C#'s out parameter. I always though it was better to return a single typed object with queryable properties. That way, if you need more return information, you modify the object, rather than the method signature. It, by definition, makes your code more object-oriented.
---------------------
Marshall Rosenstein
.NET Consultant
|
|
|
|
|
Right, just return an object that contains the values.
|
|
|
|
|
Marshall Rosenstein wrote: I always though it was better to return a single typed object with queryable properties. That way, if you need more return information, you modify the object, rather than the method signature. It, by definition, makes your code more object-oriented.
Now, if only it was possible to use C# 3.0's anonymouse types for function return values... imagine this:
var foo(string arg1, int arg2, float[] arg3)
{
return new {tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0]};
}
|
|
|
|
|
The problem is that if you were to externally link to a library containing such a function, there's no easy way to determine the properties available from "var" at compile time - Intellisense would certainly fail. Strangely, this compiles fine:
public object foo( string arg1, int arg2, float[] arg3 )
{
return new { tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0] };
}
But again, what is the object? What do you cast it to? Reflection might work in this case, but that seems kind of clunky to me.
Actually, something like this might actually work:
public var MyDynamicClass foo( string arg1, int arg2, float[] arg3 )
{
return new var{ tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0] };
}
In this case, MyDynamicClass becomes what I might call a "dynamic type", but it can still be inferred by the compiler and its meta-data made available externally as if it were a formally defined class. But there are all sorts of problems this would induce in terms of maintenance and version compatibility.
Or how about something like this:
public var foo( string arg1, int arg2, float[] arg3 )
{
return new var("MyDynamicClassName"){ tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0] };
}
---------------------
Marshall Rosenstein
.NET Consultant
modified on Wednesday, December 19, 2007 9:38:04 AM
|
|
|
|
|
Thinking too generically?
Return values of type object are common enough.* I don't see any problem with that approach. It's also a mechanism for circumventing the inability to create a single method w/a variable arg list. (Overloads really don't come close to replacing this joy of C ).
At first, I was thinking about strategies to pass in the type of the class that was to be returned, and since this was passed in by the caller its type was known by the caller. The typeid could be used, an object of that type created, and cast to a generic object type for return.
All this to avoid simply returning a struct containing the appropriate info (?).**
Then I got to thinking about the whole thing. In what circumstance could I get any real added-value functionality by returning an arbitrary type? Here's what I was thinking: the full generalization is to submit arbitrary data and return an arbitrary type. How do we process the former without making so large and complex a logic tree that it's unworkable? The crux of this is that it implies a totally generic data-processor (i.e., it too is a sort of arbitrary).
All things wonderful could be accomplished by either returning (a) structure, or (b) an object container (like ArrayList), or (c) an generic object.
The methods utlimately need some sort of body to do anything and so if we make it too abstract we end up with either too much or nothing at all
* Example: SqlClient::SqlCommand::ExecuteScaler()
** Time/watch analogy in a different area of the main thread
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein
|
|
|
|
|
When you call ExecuteScaler(), the result can be cast to a known value type. The problem with returning an object in the var case (C# 3.0) is that you are returning an anonymous type. So what type do you cast the object to get at its data / properties after calling the function? To cast it to something useful, the definition of the type has to be publically available to the caller somewhere. Otherwise, you're left with using reflection on the object.
I think the point of an anonymous type is to allow the return of arbitrary data without vastly increasing the number of types predefined in the namespace. The common usage of a struct requires the data to conform to a structure, rather than having a structure conform to the data (as is the case with anonymous types).
In LINQ, even if the input data is not arbitrary, the data that gets returned from a query can be abitrary due to the many possible transformations.
---------------------
Marshall Rosenstein
.NET Consultant
|
|
|
|
|
The point that struck home to me is that, in general, I create an function to do a specific job, which requires specific data, and allows specific processing.
As a mental exercise, what you're saying is fine. I just (accidentally) gave it some practical thought. An arbitrary return type would imply arbitrary arguments (ok - pass in an Obj) and arbitrary processing - the anything function - that's got me beat.
On the other hand, if any of the these are fixed, than so to would be the possible return types. The type could declared without bothering to allocate its dat (for example), be passed in as the first value of the arbitrary data list. Since the processing possibilities in a real system are limited, it could be type-id'ed, processed accordingly into that type, and then cast as an generic object for the return. TYpe-id it again on the other side, or cast it directly upon return.
In real life, I've usually worked this out as either structures or ArrayLists as return types.
This stuff may work differently for me (in C++) than it does in C#.
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein
|
|
|
|
|
I think I understand what you are saying. But at a pragmatic level, I'm suspicious that the language feature of anonymous types was added just to support Intellisense for lazy programmers like myself.
---------------------
Marshall Rosenstein
.NET Consultant
|
|
|
|
|
Balboos wrote: variable arg list
params object[] doesn't work for you?
|
|
|
|
|
Marshall Rosenstein wrote: The problem is that if you were to externally link to a library containing such a function, there's no easy way to determine the properties available from "var" at compile time - Intellisense would certainly fail.
I'd say you're wrong about that. Why? var isn't a Variant-like type from VB6 days. The Type of var is determined at compile-time. When you write
new { tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0] }; <big>
</big>
a new type is generated (named something like "Anonymous1" or equivalent). So, technically, it is not hard to implemented the feature I proposed; except maybe it would be slow/painful to add support for it in the IntelliSense tool, though doesnt seem too hard - since they can do it for variables, why not for functions. IMO they did not see it as a needed feature. Perhaps VS2010
Marshall Rosenstein wrote: Strangely, this compiles fine:
public object foo( string arg1, int arg2, float[] arg3 )
{
return new { tmp=arg1+"test", md=arg2 % 42, len=arg3.Length, first=arg3[0] };
}
Of course. as said before, the new {...} statement makes the compiler generate a new class, and the "new" makes an instance of it. And then returning it, well, it boxes it into the object, and that's it.
Hmm, I just might post this on Connect. Maybe they'll add this. Any idea on where the Connect website is? :p
|
|
|
|
|
Hi,
I haven't heard of the Connect website -- is it something I should explore?
I don't think they'll ever add var as a return function value, and here's why.
The Type of var is known at compile time since it is the compiler that auto-generates the Type. However, the accessibility of the Type is always internal sealed . Also, if you look at the IL for foo() , there is no boxing that occurs, since anonymous types are not value types.
Since public var foo() is public , it would require that the return Type of foo() to be public as well. This is especially important when the method you are calling is in an external library. Otherwise you introduce the following problems:
- The
var or object can't be cast to its original type by the caller. - You can only access the data in the
var using reflection. - Since the return Type of
foo() isn't named in the meta-data (this can be verified using reflection), the Intellisense parser would have to both parse and interpret the IL of the third party library function to determine the actual return Type. In some cases, it is not possible to determine the return Type at compile time. For example, if the function logic contained a switch statement where what is returned is conditioned in some way by the runtime values of the input parameters:
public var foo()( int myRuntimeVal )
{
switch( myRuntimeVal ){
case 1: return new{ Value=1 };
default: return new{ Name="Hello", Value="World" };
}
} - Once the IL analysis successfully determined the Type, it would have to use reflection to determine the available properties of the Type.
Changing the auto-generated type from internal to public is in essence the same as proposing that anonymous types no longer be anonymous. Even so, on another post, I proposed a couple ways this might be done. "Named auto-generated types" is of course possible. This is adding language support to create a public contract based on ad-hoc definitions of data-structures. In practice, these definitions are subject to change due to the context in which such definitions are intended to be used - data queries. This becomes a real maintenance problem in terms of "published" interfaces, especially for third-party users.
One easy solution would be to only allow the var keyword to be used for private or internal functions.
---------------------
Marshall Rosenstein
.NET Consultant
modified on Thursday, December 20, 2007 12:23:31 PM
|
|
|
|
|
Marshall Rosenstein wrote: I haven't heard of the Connect website -- is it something I should explore?
MS' feedback site. http://connect.microsoft.com/[^]
Marshall Rosenstein wrote: I don't think they'll ever add var as a return function value, and here's why.
The Type of var is known at compile time since it is the compiler that auto-generates the Type. However, the accessibility of the Type is always internal sealed. Also, if you look at the IL for foo(), there is no boxing that occurs, since anonymous types are not value types.
Since public var foo() is public, it would require that the return Type of foo() to be public as well. This is especially important when the method you are calling is in an external library. Otherwise you introduce the following problems:
Hmm, very valid point. However, why not make anonymous types public sealed ? I don't see any major problems with this.
Marshall Rosenstein wrote: Since the return Type of foo() isn't named in the meta-data (this can be verified using reflection), the Intellisense parser would have to both parse and interpret the IL of the third party library function to determine the actual return Type. In some cases, it is not possible to determine the return Type at compile time. For example, if the function logic contained a switch statement where what is returned is conditioned in some way by the runtime values of the input parameters:
//Return Type cannot be determined at compile time
public var foo()( int myRuntimeVal )
{
switch( myRuntimeVal ){
case 1: return new{ Value=1 }; //Anonymous Type 1
default: return new{ Name="Hello", Value="World" }; //Anonymous Type 2
}
}
That, IMHO, shouldn't be allowed at all. After all, its like saying
public CType1 foo(int myRuntimeVal)
{
switch(myRuntimeVal){
case 1: return new CType1(1);
default: return new CType2("Hello", "World");
}
} assuming CType1 and CType2 exist as actual classes, are accessible, and have the needed constructors, of course.
I do have to agree with the "Named auto-generated types" idea, however.
|
|
|
|
|