static void Main() {
void TestLocal() => TestLocal("arg");
TestLocal("arg");
}
static void TestLocal(string argument) {
}
In this example, local function has the same name as another method, which I want to overload. But this method is invisible from inside of this function, and even from inside of Main(). The same is for lambdas:
static void Main() {
Action TestLambda = () => TestLambda("arg");
}
static void TestLambda(string argument) {
}
I understand, why lambda hides outer method - because it is a local variable, and local variables always work this way. But I don't see any reason for local functions hide and not overload outer methods - it could be very useful for reducing amout of arguments in local scope, doing some kind of carrying.
Why local functions hide methods?
EDIT:
I can imagine an example where it gets complicated
void Bar(short arg) {
Console.WriteLine("short");
}
void Bar(byte arg) {
Console.WriteLine("byte");
}
void Test() {
void Bar(int arg) {
Console.WriteLine("int");
}
Bar(0);
}
It was already complicated enough with argument type resolution. If they added overloading to local methods, it would be one more stupid task for job interviews and one more huge task for compiler makers. And there are also virtual and new methods...
Why local functions hide methods?
Basically it's introducing the method name into the declaration space inside the method. Within that declaration space, the name only refers to the local method... just as it does for a local variable. I think that's reasonably consistent with the way that names introduced into methods have always worked.
I'd personally advise against trying to do this anyway, as it'll cause confusion, but if you really need to refer to the class method, just make it explicit:
ClassName.TestLocal("arg");
What I do think could be fixed is that local methods can't be overloaded between themselves. You can't write:
void Foo()
{
void Method(int x) {}
void Method(string y) {}
}
This is for a related reason - a method's declaration space can't include the same name twice, whereas a class's declaration space can do so, in terms of method overloading. Maybe the rules will be loosened around this...
Related
I'm currently learning about computer memory and asking questions to myself to understand it better.
I learned about how a new space is allocated in the stack whenever a function is called.
But why we can't reach local variables even though they are still on the stack? What is it that prevents me from accessing them while they are still on the stack?
Consider the following code (Please look at the comments):
class Program
{
public static void Main()
{
int number = 5;
Method();
} //<------ number variable will be stored in the stack until the program reaches here.
public static void Method()
{
// number=5 variable is still on the stack so why can't I reach it here?
number = 10; // throws an error because it's not defined in this scope but it's still on the stack.
int anotherNumber = 2;
}
}
In C and languages derived from it, functions are separately compiled so they cannot "see" the local variables of each other. This is a design decision.
In Pascal and languages derived from it, this is made possible by allowing nested function declarations. A function declared inside another sees the local variables of the latter as global ones.
But beware that via mutual and recursive calls, the same variable can exist at several places in the stack.
If that code could compile (i.e. if you comment out number = 10;), the variable number would likely not even be on the stack in a Release build because it's unused and the optimizer would realize that.
C# uses scoping for variables, and the scope of the variable number is the Main() method. If you define it inside the class instead, it'd be a class member and would be accessible also from the method Method(). As a general rule of thumb, though, always try to limit the scope of variables.
class Program
{
static int number = 5; // class member
public static void Main()
{
Method();
}
public static void Method()
{
number = 10; // no error anymore
int anotherNumber = 2;
}
}
variable is still on the stack so why can't I reach it here?
This argument hold as much water as "all variables are in memory so why can't I access from everywhere all variables, including variables from other programs, after all they are all on the same memory right?"
There are so many problems with what you propose. From encapsulation, to name pollution, to optimization, to security.
A local variable is just that: a local variable. It's for me, it's an implementation detail. The outside world should not know about it because since it's mine and I use it for my internal purposes I can change it or remove it at my will. With your proposal what? Now I can't change my own local variable because some function somewhere down the calling chain uses it. And why does it uses it? If I want to pass some information to the function I call then that should be done via parameters.
void foo() { int mine; bar(); }
void bar() { void baz(); }
void baz() { mine = 24; } // like wtf??
Besides how would you handle this situation:
void foo_1()
{
int mine; // I can name it mine because it's a local variable
bar();
}
void foo_2()
{
int mine; // I can also name it mine because it's a local variable
bar();
}
void foo_3()
{
bar();
}
void bar()
{
mine = 24; // ??????
}
In concussion to pass information from one function to another we use parameters, we don't pollute a fictional "global local namespace" because we are not savages.
I'm trying to understand delegates. when I run the following code:
public delegate void DelegateType1();
public static void callDelegate1(DelegateType1 callback) {
callback();
}
void start() {
callDelegate1(runMe);
}
void runMe() {
Debug.Log("Why?");
}
It outputs 'Why?'.
My question is: If CallDelegate1 takes an argument of type DelegateType1, why does it also accept a function name as argument? Also, is this a bad practice? Every tutorial I've seen online stores the function name in a variable of type DelegateType1.
Paraphrasing:
void f(long l) { }
void g() { f(1); }
My question is: if f takes an argument of type long, why does it also accept an int as argument?
Because there is an implicit conversion from int to long.
My question is: If CallDelegate1 takes an argument of type DelegateType1, why does it also accept a function name as argument?
Because there is an implicit conversion from a method group to a delegate type.
Also, is this a bad practice? Every tutorial I've seen online stores the function name in a variable of type DelegateType1.
The most explicit form is
void start() {
DelegateType1 runMeDelegate = new DelegateType1(runMe);
callDelegate1(runMeDelegate);
}
You can make it less explicit by writing it as a conversion:
void start() {
DelegateType1 runMeDelegate = (DelegateType1) runMe;
callDelegate1(runMeDelegate);
}
You can make it even less explicit by making the conversion implicit:
void start() {
DelegateType1 runMeDelegate = runMe;
callDelegate1(runMeDelegate);
}
And finally, you can get rid of the variable entirely:
void start() {
callDelegate1(runMe);
}
They are all perfectly fine and all do the same thing. The first form is something that code generators typically use, because explicit construction of a delegate type is something that's most widely supported in different languages. The last form is something that programmers tend to write when it's obvious to someone with sufficient C# experience what's going on there.
Tutorials are not focused on programmers with sufficient C# experience, so to make it clearer what's going on, they may choose to use one of the more verbose forms. There is nothing wrong with sticking with that form if it helps you understand, but there is equally nothing wrong with using the shorter form.
namespace test
{
class Program
{
static void Main(string[] args)
{
Derived obj = new Derived();
int i = 10;
obj.Foo(i);
Console.ReadLine();
}
}
class Base
{
public virtual void Foo(int i)
{
Console.WriteLine("Base:Foo()");
}
}
class Derived:Base
{
public override void Foo(int i)
{
Console.WriteLine("Foo(int)");
}
public void Foo(object i)
{
Console.WriteLine("Foo(object)");
}
}
}
output of the program according to me should be Foo(int) but output is coming as Foo(object) please help me in understanding the diffrence in output
Good question, I can reproduce your results. If one takes a look at the C# specifications one will find the following snippets:
7.5.3 Overload resolution
For example, the set of candidates for a method invocation does not
include methods marked override (§7.4), and methods in a base class
are not candidates if any method in a derived class is applicable
(§7.6.5.1).
7.4 Member Lookup
Otherwise, the set consists of all accessible (§3.5) members named N
in T, including inherited members and the accessible members named N
in object. If T is a constructed type, the set of members is obtained
by substituting type arguments as described in §10.3.2. Members that
include an override modifier are excluded from the set.
7.6.5.1 Method invocations
The set of candidate methods is reduced to contain only methods from
the most derived types: For each method C.F in the set, where C is the
type in which the method F is declared, all methods declared in a base
type of C are removed from the set. Furthermore, if C is a class type
other than object, all methods declared in an interface type are
removed from the set.
Sounds a bit complicated? Even the C# designers seem to think so and put in the 'helpful' note:
7.6.5.1 Method invocations
The intuitive effect of the resolution rules described above is as
follows: To locate the particular method invoked by a method
invocation, start with the type indicated by the method invocation and
proceed up the inheritance chain until at least one applicable,
accessible, non-override method declaration is found. Then perform
type inference and overload resolution on the set of applicable,
accessible, non-override methods declared in that type and invoke the
method thus selected. If no method was found, try instead to process
the invocation as an extension method invocation.
If we take a look at your derived class, we see two possible methods for C# to use:
A) public override void Foo(int i)
B) public void Foo(object i)
Let's use that last checklist!
Applicability - Both A and B are applicable -(both are void, both are named 'Foo' and both can accept an integer value).
Accessibility - Both A and B are accessible (public)
Not Overridden - Only B is not overridden.
But wait you might say! A is more specific than B!
Correct, but that consideration is only made after we've disregarded option A. As Eric Lippert (one of the designers) puts it Closer is always better than farther away. (Thanks Anthony Pegram)
Addendum
There is always the 'new' keyword:
class Derived : Base
{
public new void Foo(int i)
{
Console.WriteLine("Foo(int)");
}
public void Foo(object i)
{
Console.WriteLine("Foo(object)");
}
}
Though the specifics of that best left for another question!
The simple datatype int descends from object. You are overriding the function and also overloading the parameter list. Since the function name is the same with a different signature the compiler allows this. For simple objects, I image one copy of the parameter signature in the most basic form is stored in the method table.
I have the following simple code
abstract class A
{
public abstract void Test(Int32 value);
}
class B : A
{
public override void Test(Int32 value)
{
Console.WriteLine("Int32");
}
public void Test(Double value)
{
Test((Int32)1);
}
}
When I ran this code the line Test((Int32)1) causes stack overflow due to infinite recursion. The only possible way to correctly call proper method (with integer parameter) I found is
(this as A).Test(1);
But this is not appropriate for me, because both methods Test are public and I am willing the users to be able to call both method?
Method overload resolution in C# does not always behave as you might expect, but your code is behaving according to the specification (I wrote a blog post about this a while ago).
In short, the compiler start off by finding methods that
Has the same name (in your case Test)
are declared in the type (in your case B) or one of its base types
are not declared with the override modifier
Note that last point. This is actually logical, since virtual methods are resolved in run-time, not compile time.
Finally, if the type (in this case B) has a method that is a candidate (which means that the parameters in your call can be implicitly converted to the parameter type of the candidate method), that method will be used. Your overridden method is not even part of the decision process.
If you want to call your overridden method, you will need to cast the object to its base type first.
Unfortunately in order to call the A::Test(int) through a B reference some sort of cast is needed. So long as the C# compiler sees the reference through B it will pick the B::Test(double) version.
A slightly less ugly version is the following
((A)this).Test(1);
Another thought though is have a private method with a different name that both feed into.
class B : A {
public override void Test(int i) {
TestCore(i);
}
public void Test(double d) {
TestCore(1);
}
private void TestCore(int i) {
// Combined logic here
}
}
A delegate is a function pointer. So it points to a function which meets the criteria (parameters and return type).
This begs the question (for me, anyway), what function will the delegate point to if there is more than one method with exactly the same return type and parameter types? Is the function which appears first in the class?
Thanks
The exact method is specified when you create the Delegate.
public delegate void MyDelegate();
private void Delegate_Handler() { }
void Init() {
MyDelegate x = new MyDelegate(this.Delegate_Handler);
}
As Henk says, the method is specified when you create the delegate. Now, it's possible for more than one method to meet the requirements, for two reasons:
Delegates are variant, e.g. you can use a method with an Object parameter to create an Action<string>
You can overload methods by making them generic, e.g.
static void Foo() {}
static void Foo<T>(){}
static void Foo<T1, T2>(){}
The rules get quite complicated, but they're laid down in section 6.6 of the C# 3.0 spec. Note that inheritance makes things tricky too.
So it points to a function which meets the criteria (parameters and return type).
Nope.
To add some background to Henk's Answer:
Just like int x is an variable which can contain integers, A delegate is a variable which can contain functions.
It points to whatever function you tell it to point to.
EG:
// declare the type of the function that we want to point to
public delegate void CallbackHandler(string); //
...
// declare the actual function
public void ActualCallbackFunction(string s){ ... }
...
// create the 'pointer' and assign it
CallbackHandler functionPointer = ActualCallbackFunction;
// the functionPointer variable is now pointing to ActualCallbackFunction